From 7cd468a3d7dee7d6c92f69a0bb7061ae208ec727 Mon Sep 17 00:00:00 2001 From: Damjan Marion Date: Mon, 19 Dec 2016 23:05:39 +0100 Subject: Reorganize source tree to use single autotools instance Change-Id: I7b51f88292e057c6443b12224486f2d0c9f8ae23 Signed-off-by: Damjan Marion --- Makefile | 4 +- build-data/packages/cavium-dpdk.mk | 55 - build-data/packages/g2.mk | 6 +- build-data/packages/gmod.mk | 6 +- build-data/packages/perftool.mk | 5 +- build-data/packages/plugins.mk | 25 +- build-data/packages/src.mk | 0 build-data/packages/svm.mk | 5 - build-data/packages/vlib-api-cavium-dpdk.mk | 6 - build-data/packages/vlib-api.mk | 4 - build-data/packages/vlib-cavium-dpdk.mk | 7 - build-data/packages/vlib.mk | 16 - build-data/packages/vnet-cavium-dpdk.mk | 29 - build-data/packages/vpp-api-test-cavium-dpdk.mk | 32 - build-data/packages/vpp-api-test.mk | 39 - build-data/packages/vpp-api.mk | 16 +- build-data/packages/vpp-cavium-dpdk.mk | 30 - build-data/packages/vpp.mk | 29 +- build-data/packages/vppinfra.mk | 5 - build-data/platforms.mk | 6 +- build-data/platforms/vpp.mk | 4 +- build-data/platforms/vpp_lite.mk | 3 +- build-data/suffix-rules.mk | 27 - build-root/bootstrap.sh | 2 +- build-root/packages/src.mk | 4 + build-root/packages/tools.mk | 3 + build-root/packages/vppapigen.mk | 5 - build-root/rpm/vpp.spec | 24 +- build-root/scripts/find-plugins-contents | 6 +- build-root/scripts/find-python-api-contents | 2 +- g2/Makefile.am | 34 - g2/clib.c | 154 - g2/configure.ac | 12 - g2/cpel.c | 470 - g2/cpel.h | 83 - g2/events.c | 475 - g2/g2.h | 195 - g2/g2version.c | 19 - g2/main.c | 196 - g2/menu1.c | 565 - g2/mkversion.c | 77 - g2/pointsel.c | 854 - g2/props.c | 279 - g2/props.h | 21 - g2/view1.c | 3077 ---- gmod/gmod/mod_vpp.c | 2 +- perftool/Makefile.am | 44 - perftool/c2cpel.c | 248 - perftool/configure.ac | 12 - perftool/cpel.h | 83 - perftool/cpel_util.c | 456 - perftool/cpel_util.h | 68 - perftool/cpelatency.c | 927 - perftool/cpeldump.c | 638 - perftool/cpelinreg.c | 892 - perftool/cpelstate.c | 822 - perftool/delsvec.c | 315 - perftool/linreg.c | 78 - perftool/new.cpel | Bin 1672 -> 0 bytes perftool/new.elog | Bin 4525 -> 0 bytes perftool/props.c | 280 - plugins/Makefile.am | 12 - plugins/configure.ac | 3 - plugins/flowperpkt-plugin/Makefile.am | 64 - plugins/flowperpkt-plugin/configure.ac | 9 - .../flowperpkt-plugin/flowperpkt/flowperpkt.api | 42 - plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c | 671 - plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h | 90 - .../flowperpkt/flowperpkt_all_api_h.h | 18 - .../flowperpkt/flowperpkt_msg_enum.h | 31 - .../flowperpkt-plugin/flowperpkt/flowperpkt_test.c | 234 - plugins/flowperpkt-plugin/flowperpkt/l2_node.c | 561 - plugins/flowperpkt-plugin/flowperpkt/node.c | 574 - plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md | 13 - plugins/ila-plugin/Makefile.am | 29 - plugins/ila-plugin/configure.ac | 9 - plugins/ila-plugin/ila/ila.c | 1070 -- plugins/ila-plugin/ila/ila.h | 116 - plugins/sixrd-plugin/Makefile.am | 38 - plugins/sixrd-plugin/configure.ac | 9 - plugins/sixrd-plugin/sixrd/ip4_sixrd.c | 127 - plugins/sixrd-plugin/sixrd/ip6_sixrd.c | 129 - plugins/sixrd-plugin/sixrd/sixrd.c | 369 - plugins/sixrd-plugin/sixrd/sixrd.h | 141 - plugins/sixrd-plugin/sixrd/sixrd_dpo.c | 132 - plugins/sixrd-plugin/sixrd/sixrd_dpo.h | 61 - src/Makefile.am | 101 + src/configure.ac | 195 + src/examples/vlib/dir.dox | 22 + src/examples/vlib/main_stub.c | 418 + src/examples/vlib/mc_test.c | 384 + src/examples/vlib/plex_test.c | 527 + src/g2.am | 32 + src/perftool.am | 41 + src/plugins/Makefile.am | 60 + src/plugins/flowperpkt.am | 38 + src/plugins/flowperpkt/flowperpkt.api | 42 + src/plugins/flowperpkt/flowperpkt.c | 671 + src/plugins/flowperpkt/flowperpkt.h | 90 + src/plugins/flowperpkt/flowperpkt_all_api_h.h | 18 + src/plugins/flowperpkt/flowperpkt_msg_enum.h | 31 + src/plugins/flowperpkt/flowperpkt_plugin_doc.md | 13 + src/plugins/flowperpkt/flowperpkt_test.c | 234 + src/plugins/flowperpkt/l2_node.c | 561 + src/plugins/flowperpkt/node.c | 574 + src/plugins/ila.am | 20 + src/plugins/ila/ila.c | 1070 ++ src/plugins/ila/ila.h | 116 + src/plugins/sixrd.am | 26 + src/plugins/sixrd/ip4_sixrd.c | 127 + src/plugins/sixrd/ip6_sixrd.c | 129 + src/plugins/sixrd/sixrd.c | 369 + src/plugins/sixrd/sixrd.h | 141 + src/plugins/sixrd/sixrd_dpo.c | 132 + src/plugins/sixrd/sixrd_dpo.h | 61 + src/scripts/vnet/arp4 | 21 + src/scripts/vnet/arp4-mpls | 24 + src/scripts/vnet/arp6 | 21 + src/scripts/vnet/bvi | 76 + src/scripts/vnet/dhcp/dhcpd.conf | 8 + src/scripts/vnet/dhcp/left-ping-target.sh | 4 + src/scripts/vnet/dhcp/leftpeer.conf | 17 + src/scripts/vnet/icmp | 16 + src/scripts/vnet/icmp6 | 16 + src/scripts/vnet/ige | 19 + src/scripts/vnet/ip6 | 15 + src/scripts/vnet/ip6-hbh | 84 + src/scripts/vnet/ixge | 15 + src/scripts/vnet/l2efpfilter | 83 + src/scripts/vnet/l2efpfilter_perf | 58 + src/scripts/vnet/l2fib | 46 + src/scripts/vnet/l2fib_perf | 29 + src/scripts/vnet/l2fib_xc | 31 + src/scripts/vnet/l2flood | 42 + src/scripts/vnet/l2tp | 134 + src/scripts/vnet/leftpeer/leftpeer-classify | 8 + src/scripts/vnet/leftpeer/leftpeer-classify6 | 5 + src/scripts/vnet/leftpeer/leftpeer-classifyl2 | 8 + src/scripts/vnet/leftpeer/leftpeer-dhcp | 23 + src/scripts/vnet/leftpeer/leftpeer-ioam.conf | 15 + src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf | 12 + src/scripts/vnet/leftpeer/leftpeer-lisp.conf | 18 + src/scripts/vnet/leftpeer/leftpeer-mpls.conf | 17 + src/scripts/vnet/leftpeer/leftpeer-sr.conf | 24 + src/scripts/vnet/leftpeer/leftpeer-vxlan.conf | 17 + src/scripts/vnet/leftpeer/leftpeer.script | 9 + src/scripts/vnet/lfib/ip4-to-mpls | 26 + src/scripts/vnet/lfib/mpls-pop-to-mpls | 28 + src/scripts/vnet/lfib/mpls-to-ip4 | 27 + src/scripts/vnet/lfib/mpls-to-mpls | 26 + src/scripts/vnet/mpls-o-ethernet/leftpeer.conf | 17 + src/scripts/vnet/mpls-o-ethernet/pg | 10 + src/scripts/vnet/mpls-o-ethernet/rightpeer.conf | 15 + src/scripts/vnet/mpls-o-ethernet/single.conf | 17 + src/scripts/vnet/mpls-o-gre/dhcpd.conf | 116 + src/scripts/vnet/mpls-o-gre/leftpeer.conf | 14 + src/scripts/vnet/mpls-o-gre/rightpeer.conf | 14 + src/scripts/vnet/mpls-tunnel | 87 + src/scripts/vnet/pcap | 18 + src/scripts/vnet/probe4 | 11 + src/scripts/vnet/probe6 | 7 + src/scripts/vnet/rewrite | 62 + src/scripts/vnet/rightpeer/rightpeer-ioam.conf | 14 + src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf | 9 + src/scripts/vnet/rightpeer/rightpeer-lisp.conf | 16 + src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf | 24 + src/scripts/vnet/rightpeer/rightpeer-mpls.conf | 17 + src/scripts/vnet/rightpeer/rightpeer-sr.conf | 28 + src/scripts/vnet/rightpeer/rightpeer-vxlan.conf | 16 + src/scripts/vnet/rightpeer/rightpeer.script | 9 + src/scripts/vnet/rpf | 18 + src/scripts/vnet/rtt-test | 31 + src/scripts/vnet/snat | 34 + src/scripts/vnet/snat_static | 44 + src/scripts/vnet/snat_static_with_port | 44 + src/scripts/vnet/source_and_port_range_check | 63 + src/scripts/vnet/speed | 14 + src/scripts/vnet/sr/left-linux-ping.sh | 3 + src/scripts/vnet/sr/leftpeer.conf | 27 + src/scripts/vnet/sr/right-linux-ping.sh | 4 + src/scripts/vnet/sr/rightpeer.conf | 22 + src/scripts/vnet/sr/srlocal.sh | 4 + src/scripts/vnet/srp | 27 + src/scripts/vnet/tcp | 16 + src/scripts/vnet/tcp-test | 6 + src/scripts/vnet/tf-ucs-1 | 16 + src/scripts/vnet/urpf | 86 + src/scripts/vnet/virl/ip6sr.virl | 874 + src/scripts/vnet/virl/ip6sr_notes.txt | 38 + src/scripts/vnet/virl/mplsogre.virl | 319 + src/scripts/vnet/virl/simple.virl | 389 + src/scripts/vnet/vlan | 23 + src/scripts/vppctl | 121 + src/suffix-rules.mk | 27 + src/svm.am | 31 + src/svm/dir.dox | 21 + src/svm/persist.c | 258 + src/svm/ssvm.c | 178 + src/svm/ssvm.h | 155 + src/svm/svm.c | 1237 ++ src/svm/svm.h | 207 + src/svm/svm_test.c | 79 + src/svm/svmdb.c | 671 + src/svm/svmdb.h | 135 + src/svm/svmdbtool.c | 537 + src/svm/svmtool.c | 528 + src/tests/vnet/README | 10 + src/tests/vnet/lisp-cp/test_cp_serdes.c | 639 + src/tests/vnet/lisp-cp/test_lisp_types.c | 565 + src/tests/vnet/lisp-gpe/test.c | 18 + src/tools/elftool/dir.dox | 19 + src/tools/elftool/elftool.c | 464 + src/tools/g2/clib.c | 154 + src/tools/g2/configure.ac | 12 + src/tools/g2/cpel.c | 470 + src/tools/g2/cpel.h | 83 + src/tools/g2/events.c | 475 + src/tools/g2/g2.h | 195 + src/tools/g2/g2version.c | 19 + src/tools/g2/main.c | 196 + src/tools/g2/menu1.c | 565 + src/tools/g2/mkversion.c | 77 + src/tools/g2/pointsel.c | 854 + src/tools/g2/props.c | 279 + src/tools/g2/props.h | 21 + src/tools/g2/view1.c | 3077 ++++ src/tools/perftool/c2cpel.c | 248 + src/tools/perftool/configure.ac | 12 + src/tools/perftool/cpel.h | 83 + src/tools/perftool/cpel_util.c | 456 + src/tools/perftool/cpel_util.h | 68 + src/tools/perftool/cpelatency.c | 927 + src/tools/perftool/cpeldump.c | 638 + src/tools/perftool/cpelinreg.c | 892 + src/tools/perftool/cpelstate.c | 822 + src/tools/perftool/delsvec.c | 315 + src/tools/perftool/linreg.c | 78 + src/tools/perftool/new.cpel | Bin 0 -> 1672 bytes src/tools/perftool/new.elog | Bin 0 -> 4525 bytes src/tools/perftool/props.c | 280 + src/tools/vppapigen/configure.ac | 14 + src/tools/vppapigen/gram.y | 90 + src/tools/vppapigen/lex.c | 1067 ++ src/tools/vppapigen/lex.h | 50 + src/tools/vppapigen/node.c | 1527 ++ src/tools/vppapigen/node.h | 94 + src/vat/api_format.c | 17829 +++++++++++++++++++ src/vat/json_format.c | 304 + src/vat/json_format.h | 254 + src/vat/json_test.c | 75 + src/vat/main.c | 421 + src/vat/plugin.c | 201 + src/vat/plugin.h | 61 + src/vat/plugin_api.c | 216 + src/vat/restart.c | 246 + src/vat/vat.h | 257 + src/vlib-api.am | 73 + src/vlib.am | 103 + src/vlib/buffer.c | 1987 +++ src/vlib/buffer.h | 417 + src/vlib/buffer_funcs.h | 755 + src/vlib/buffer_node.h | 337 + src/vlib/cli.c | 1173 ++ src/vlib/cli.h | 192 + src/vlib/cli_funcs.h | 58 + src/vlib/counter.c | 151 + src/vlib/counter.h | 379 + src/vlib/defs.h | 82 + src/vlib/dir.dox | 23 + src/vlib/elog_samples.c | 122 + src/vlib/error.c | 338 + src/vlib/error.h | 101 + src/vlib/error_funcs.h | 88 + src/vlib/format.c | 196 + src/vlib/format_funcs.h | 75 + src/vlib/global_funcs.h | 45 + src/vlib/i2c.c | 231 + src/vlib/i2c.h | 67 + src/vlib/init.c | 168 + src/vlib/init.h | 238 + src/vlib/lex.c | 271 + src/vlib/lex.h | 145 + src/vlib/main.c | 1703 ++ src/vlib/main.h | 333 + src/vlib/mc.c | 2609 +++ src/vlib/mc.h | 687 + src/vlib/node.c | 631 + src/vlib/node.h | 725 + src/vlib/node_cli.c | 466 + src/vlib/node_format.c | 187 + src/vlib/node_funcs.h | 1130 ++ src/vlib/parse.c | 1007 ++ src/vlib/parse.h | 221 + src/vlib/parse_builtin.c | 150 + src/vlib/pci/linux_pci.c | 642 + src/vlib/pci/pci.c | 264 + src/vlib/pci/pci.h | 251 + src/vlib/pci/pci_config.h | 731 + src/vlib/physmem.h | 108 + src/vlib/threads.c | 1492 ++ src/vlib/threads.h | 470 + src/vlib/threads_cli.c | 579 + src/vlib/trace.c | 545 + src/vlib/trace.h | 100 + src/vlib/trace_funcs.h | 185 + src/vlib/unix/cj.c | 271 + src/vlib/unix/cj.h | 79 + src/vlib/unix/cli.c | 2989 ++++ src/vlib/unix/dir.dox | 28 + src/vlib/unix/input.c | 265 + src/vlib/unix/main.c | 557 + src/vlib/unix/mc_socket.c | 1049 ++ src/vlib/unix/mc_socket.h | 137 + src/vlib/unix/physmem.c | 470 + src/vlib/unix/physmem.h | 65 + src/vlib/unix/plugin.c | 260 + src/vlib/unix/plugin.h | 98 + src/vlib/unix/unix.h | 232 + src/vlib/unix/util.c | 231 + src/vlib/vlib.h | 86 + src/vlib/vlib_process_doc.h | 147 + src/vlibapi/api.h | 281 + src/vlibapi/api_helper_macros.h | 243 + src/vlibapi/api_shared.c | 1375 ++ src/vlibapi/node_serialize.c | 399 + src/vlibmemory/api.h | 163 + src/vlibmemory/memclnt.api | 91 + src/vlibmemory/memory_client.c | 283 + src/vlibmemory/memory_shared.c | 852 + src/vlibmemory/memory_vlib.c | 1346 ++ src/vlibmemory/unix_shared_memory_queue.c | 324 + src/vlibmemory/unix_shared_memory_queue.h | 69 + src/vlibmemory/vl_memory_api_h.h | 32 + src/vlibmemory/vl_memory_msg_enum.h | 42 + src/vlibsocket/api.h | 87 + src/vlibsocket/sock_test.c | 155 + src/vlibsocket/sockclnt.api | 50 + src/vlibsocket/sockclnt_vlib.c | 209 + src/vlibsocket/socksvr_vlib.c | 706 + src/vlibsocket/vl_socket_api_h.h | 33 + src/vlibsocket/vl_socket_msg_enum.h | 42 + src/vnet.am | 972 + src/vnet/adj/adj.c | 454 + src/vnet/adj/adj.h | 122 + src/vnet/adj/adj_glean.c | 285 + src/vnet/adj/adj_glean.h | 61 + src/vnet/adj/adj_internal.h | 104 + src/vnet/adj/adj_l2.c | 194 + src/vnet/adj/adj_l2.h | 24 + src/vnet/adj/adj_midchain.c | 559 + src/vnet/adj/adj_midchain.h | 102 + src/vnet/adj/adj_nbr.c | 1087 ++ src/vnet/adj/adj_nbr.h | 176 + src/vnet/adj/adj_rewrite.c | 53 + src/vnet/adj/adj_rewrite.h | 49 + src/vnet/adj/adj_types.h | 53 + src/vnet/api_errno.h | 113 + src/vnet/bfd/bfd.api | 205 + src/vnet/bfd/bfd_api.c | 262 + src/vnet/bfd/bfd_api.h | 46 + src/vnet/bfd/bfd_debug.h | 79 + src/vnet/bfd/bfd_doc.md | 1 + src/vnet/bfd/bfd_main.c | 969 + src/vnet/bfd/bfd_main.h | 220 + src/vnet/bfd/bfd_protocol.c | 74 + src/vnet/bfd/bfd_protocol.h | 154 + src/vnet/bfd/bfd_udp.c | 639 + src/vnet/bfd/bfd_udp.h | 56 + src/vnet/bfd/dir.dox | 18 + src/vnet/buffer.h | 381 + src/vnet/cdp/cdp.pg | 7 + src/vnet/cdp/cdp_input.c | 506 + src/vnet/cdp/cdp_node.c | 208 + src/vnet/cdp/cdp_node.h | 147 + src/vnet/cdp/cdp_periodic.c | 512 + src/vnet/cdp/cdp_protocol.h | 186 + src/vnet/classify/README | 180 + src/vnet/classify/flow_classify.c | 212 + src/vnet/classify/flow_classify.h | 51 + src/vnet/classify/flow_classify_node.c | 338 + src/vnet/classify/input_acl.c | 283 + src/vnet/classify/input_acl.h | 54 + src/vnet/classify/ip_classify.c | 365 + src/vnet/classify/policer_classify.c | 227 + src/vnet/classify/policer_classify.h | 55 + src/vnet/classify/vnet_classify.c | 2436 +++ src/vnet/classify/vnet_classify.h | 523 + src/vnet/config.c | 361 + src/vnet/config.h | 176 + src/vnet/cop/cop.c | 387 + src/vnet/cop/cop.h | 89 + src/vnet/cop/ip4_whitelist.c | 356 + src/vnet/cop/ip6_whitelist.c | 298 + src/vnet/cop/node1.c | 319 + src/vnet/devices/af_packet/af_packet.api | 71 + src/vnet/devices/af_packet/af_packet.c | 366 + src/vnet/devices/af_packet/af_packet.h | 69 + src/vnet/devices/af_packet/af_packet_api.c | 143 + src/vnet/devices/af_packet/cli.c | 144 + src/vnet/devices/af_packet/device.c | 250 + src/vnet/devices/af_packet/node.c | 288 + src/vnet/devices/devices.c | 91 + src/vnet/devices/devices.h | 53 + src/vnet/devices/dpdk/cli.c | 1296 ++ src/vnet/devices/dpdk/device.c | 840 + src/vnet/devices/dpdk/dpdk.h | 534 + src/vnet/devices/dpdk/dpdk_priv.h | 132 + src/vnet/devices/dpdk/format.c | 763 + src/vnet/devices/dpdk/hqos.c | 775 + src/vnet/devices/dpdk/init.c | 1803 ++ src/vnet/devices/dpdk/ipsec/cli.c | 141 + src/vnet/devices/dpdk/ipsec/crypto_node.c | 210 + src/vnet/devices/dpdk/ipsec/dir.dox | 18 + .../devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md | 73 + src/vnet/devices/dpdk/ipsec/esp.h | 295 + src/vnet/devices/dpdk/ipsec/esp_decrypt.c | 583 + src/vnet/devices/dpdk/ipsec/esp_encrypt.c | 598 + src/vnet/devices/dpdk/ipsec/ipsec.c | 313 + src/vnet/devices/dpdk/ipsec/ipsec.h | 227 + src/vnet/devices/dpdk/node.c | 687 + src/vnet/devices/dpdk/qos_doc.md | 404 + src/vnet/devices/netmap/cli.c | 146 + src/vnet/devices/netmap/device.c | 261 + src/vnet/devices/netmap/net_netmap.h | 650 + src/vnet/devices/netmap/netmap.api | 74 + src/vnet/devices/netmap/netmap.c | 316 + src/vnet/devices/netmap/netmap.h | 164 + src/vnet/devices/netmap/netmap_api.c | 137 + src/vnet/devices/netmap/node.c | 300 + src/vnet/devices/nic/ixge.c | 2938 +++ src/vnet/devices/nic/ixge.h | 1293 ++ src/vnet/devices/nic/sfp.c | 117 + src/vnet/devices/nic/sfp.h | 117 + src/vnet/devices/ssvm/node.c | 343 + src/vnet/devices/ssvm/ssvm_eth.c | 491 + src/vnet/devices/ssvm/ssvm_eth.h | 141 + src/vnet/devices/virtio/dir.dox | 27 + src/vnet/devices/virtio/vhost-user.c | 3314 ++++ src/vnet/devices/virtio/vhost-user.h | 350 + src/vnet/devices/virtio/vhost_user.api | 125 + src/vnet/devices/virtio/vhost_user_api.c | 262 + src/vnet/dhcp/client.c | 1031 ++ src/vnet/dhcp/client.h | 118 + src/vnet/dhcp/packet.h | 61 + src/vnet/dhcp/proxy.h | 92 + src/vnet/dhcp/proxy_error.def | 30 + src/vnet/dhcp/proxy_node.c | 1114 ++ src/vnet/dhcpv6/packet.h | 183 + src/vnet/dhcpv6/proxy.h | 95 + src/vnet/dhcpv6/proxy_error.def | 29 + src/vnet/dhcpv6/proxy_node.c | 1191 ++ src/vnet/dpo/classify_dpo.c | 131 + src/vnet/dpo/classify_dpo.h | 56 + src/vnet/dpo/dpo.c | 500 + src/vnet/dpo/dpo.h | 381 + src/vnet/dpo/drop_dpo.c | 106 + src/vnet/dpo/drop_dpo.h | 31 + src/vnet/dpo/ip_null_dpo.c | 408 + src/vnet/dpo/ip_null_dpo.h | 56 + src/vnet/dpo/load_balance.c | 993 ++ src/vnet/dpo/load_balance.h | 211 + src/vnet/dpo/load_balance_map.c | 575 + src/vnet/dpo/load_balance_map.h | 79 + src/vnet/dpo/lookup_dpo.c | 1185 ++ src/vnet/dpo/lookup_dpo.h | 108 + src/vnet/dpo/mpls_label_dpo.c | 570 + src/vnet/dpo/mpls_label_dpo.h | 101 + src/vnet/dpo/punt_dpo.c | 100 + src/vnet/dpo/punt_dpo.h | 30 + src/vnet/dpo/receive_dpo.c | 165 + src/vnet/dpo/receive_dpo.h | 62 + src/vnet/ethernet/arp.c | 2355 +++ src/vnet/ethernet/arp_packet.h | 173 + src/vnet/ethernet/dir.dox | 24 + src/vnet/ethernet/error.def | 46 + src/vnet/ethernet/ethernet.h | 561 + src/vnet/ethernet/format.c | 366 + src/vnet/ethernet/init.c | 128 + src/vnet/ethernet/interface.c | 730 + src/vnet/ethernet/mac_swap.c | 397 + src/vnet/ethernet/node.c | 1368 ++ src/vnet/ethernet/packet.h | 152 + src/vnet/ethernet/pg.c | 183 + src/vnet/ethernet/types.def | 113 + src/vnet/feature/feature.c | 463 + src/vnet/feature/feature.h | 382 + src/vnet/feature/registration.c | 301 + src/vnet/fib/fib.c | 41 + src/vnet/fib/fib.h | 652 + src/vnet/fib/fib_api.h | 54 + src/vnet/fib/fib_attached_export.c | 572 + src/vnet/fib/fib_attached_export.h | 57 + src/vnet/fib/fib_entry.c | 1503 ++ src/vnet/fib/fib_entry.h | 530 + src/vnet/fib/fib_entry_cover.c | 225 + src/vnet/fib/fib_entry_cover.h | 47 + src/vnet/fib/fib_entry_delegate.c | 149 + src/vnet/fib/fib_entry_delegate.h | 124 + src/vnet/fib/fib_entry_src.c | 1456 ++ src/vnet/fib/fib_entry_src.h | 296 + src/vnet/fib/fib_entry_src_adj.c | 207 + src/vnet/fib/fib_entry_src_api.c | 119 + src/vnet/fib/fib_entry_src_default.c | 121 + src/vnet/fib/fib_entry_src_default_route.c | 58 + src/vnet/fib/fib_entry_src_interface.c | 195 + src/vnet/fib/fib_entry_src_lisp.c | 133 + src/vnet/fib/fib_entry_src_mpls.c | 196 + src/vnet/fib/fib_entry_src_rr.c | 293 + src/vnet/fib/fib_entry_src_special.c | 71 + src/vnet/fib/fib_internal.h | 69 + src/vnet/fib/fib_node.c | 277 + src/vnet/fib/fib_node.h | 371 + src/vnet/fib/fib_node_list.c | 390 + src/vnet/fib/fib_node_list.h | 64 + src/vnet/fib/fib_path.c | 2001 +++ src/vnet/fib/fib_path.h | 158 + src/vnet/fib/fib_path_ext.c | 231 + src/vnet/fib/fib_path_ext.h | 69 + src/vnet/fib/fib_path_list.c | 1223 ++ src/vnet/fib/fib_path_list.h | 158 + src/vnet/fib/fib_table.c | 1104 ++ src/vnet/fib/fib_table.h | 732 + src/vnet/fib/fib_test.c | 7112 ++++++++ src/vnet/fib/fib_types.c | 326 + src/vnet/fib/fib_types.h | 340 + src/vnet/fib/fib_urpf_list.c | 260 + src/vnet/fib/fib_urpf_list.h | 146 + src/vnet/fib/fib_walk.c | 1108 ++ src/vnet/fib/fib_walk.h | 58 + src/vnet/fib/ip4_fib.c | 664 + src/vnet/fib/ip4_fib.h | 141 + src/vnet/fib/ip6_fib.c | 784 + src/vnet/fib/ip6_fib.h | 130 + src/vnet/fib/mpls_fib.c | 439 + src/vnet/fib/mpls_fib.h | 106 + src/vnet/flow/flow_report.c | 502 + src/vnet/flow/flow_report.h | 145 + src/vnet/flow/flow_report_classify.c | 529 + src/vnet/flow/flow_report_classify.h | 122 + src/vnet/flow/ipfix_info_elements.h | 429 + src/vnet/flow/ipfix_packet.h | 188 + src/vnet/global_funcs.h | 32 + src/vnet/gre/error.def | 23 + src/vnet/gre/gre.api | 57 + src/vnet/gre/gre.c | 455 + src/vnet/gre/gre.h | 235 + src/vnet/gre/gre_api.c | 204 + src/vnet/gre/interface.c | 606 + src/vnet/gre/node.c | 531 + src/vnet/gre/packet.h | 55 + src/vnet/gre/pg.c | 77 + src/vnet/handoff.c | 594 + src/vnet/handoff.h | 259 + src/vnet/hdlc/error.def | 42 + src/vnet/hdlc/hdlc.c | 249 + src/vnet/hdlc/hdlc.h | 127 + src/vnet/hdlc/node.c | 351 + src/vnet/hdlc/packet.h | 72 + src/vnet/hdlc/pg.c | 105 + src/vnet/interface.api | 339 + src/vnet/interface.c | 1398 ++ src/vnet/interface.h | 658 + src/vnet/interface_api.c | 725 + src/vnet/interface_cli.c | 1165 ++ src/vnet/interface_format.c | 401 + src/vnet/interface_funcs.h | 318 + src/vnet/interface_output.c | 1404 ++ src/vnet/ip/dir.dox | 26 + src/vnet/ip/format.c | 121 + src/vnet/ip/format.h | 114 + src/vnet/ip/icmp4.c | 784 + src/vnet/ip/icmp4.h | 60 + src/vnet/ip/icmp46_packet.h | 398 + src/vnet/ip/icmp6.c | 882 + src/vnet/ip/icmp6.h | 86 + src/vnet/ip/igmp_packet.h | 155 + src/vnet/ip/ip.api | 434 + src/vnet/ip/ip.h | 195 + src/vnet/ip/ip4.h | 322 + src/vnet/ip/ip46_cli.c | 236 + src/vnet/ip/ip4_error.h | 95 + src/vnet/ip/ip4_format.c | 256 + src/vnet/ip/ip4_forward.c | 3345 ++++ src/vnet/ip/ip4_input.c | 507 + src/vnet/ip/ip4_mtrie.c | 568 + src/vnet/ip/ip4_mtrie.h | 188 + src/vnet/ip/ip4_packet.h | 384 + src/vnet/ip/ip4_pg.c | 387 + src/vnet/ip/ip4_source_and_port_range_check.c | 1415 ++ src/vnet/ip/ip4_source_check.c | 573 + src/vnet/ip/ip4_test.c | 340 + src/vnet/ip/ip6.h | 476 + src/vnet/ip/ip6_error.h | 92 + src/vnet/ip/ip6_format.c | 383 + src/vnet/ip/ip6_forward.c | 3402 ++++ src/vnet/ip/ip6_hop_by_hop.c | 1194 ++ src/vnet/ip/ip6_hop_by_hop.h | 217 + src/vnet/ip/ip6_hop_by_hop_packet.h | 66 + src/vnet/ip/ip6_input.c | 353 + src/vnet/ip/ip6_neighbor.c | 4088 +++++ src/vnet/ip/ip6_neighbor.h | 52 + src/vnet/ip/ip6_packet.h | 499 + src/vnet/ip/ip6_pg.c | 231 + src/vnet/ip/ip_api.c | 1196 ++ src/vnet/ip/ip_checksum.c | 228 + src/vnet/ip/ip_frag.c | 581 + src/vnet/ip/ip_frag.h | 96 + src/vnet/ip/ip_init.c | 152 + src/vnet/ip/ip_input_acl.c | 450 + src/vnet/ip/ip_packet.h | 180 + src/vnet/ip/ip_source_and_port_range_check.h | 148 + src/vnet/ip/lookup.c | 967 + src/vnet/ip/lookup.h | 498 + src/vnet/ip/ping.c | 888 + src/vnet/ip/ping.h | 108 + src/vnet/ip/ports.def | 757 + src/vnet/ip/protocols.def | 162 + src/vnet/ip/punt.c | 323 + src/vnet/ip/punt.h | 43 + src/vnet/ip/punt_error.def | 19 + src/vnet/ip/tcp_packet.h | 138 + src/vnet/ip/udp.h | 313 + src/vnet/ip/udp_error.def | 21 + src/vnet/ip/udp_format.c | 91 + src/vnet/ip/udp_init.c | 71 + src/vnet/ip/udp_local.c | 645 + src/vnet/ip/udp_packet.h | 65 + src/vnet/ip/udp_pg.c | 237 + src/vnet/ipsec-gre/dir.dox | 18 + src/vnet/ipsec-gre/error.def | 26 + src/vnet/ipsec-gre/interface.c | 311 + src/vnet/ipsec-gre/ipsec_gre.api | 79 + src/vnet/ipsec-gre/ipsec_gre.c | 407 + src/vnet/ipsec-gre/ipsec_gre.h | 114 + src/vnet/ipsec-gre/ipsec_gre_api.c | 190 + src/vnet/ipsec-gre/ipsec_gre_doc.md | 74 + src/vnet/ipsec-gre/node.c | 433 + src/vnet/ipsec/esp.h | 320 + src/vnet/ipsec/esp_decrypt.c | 430 + src/vnet/ipsec/esp_encrypt.c | 425 + src/vnet/ipsec/ikev2.c | 2186 +++ src/vnet/ipsec/ikev2.h | 410 + src/vnet/ipsec/ikev2_cli.c | 479 + src/vnet/ipsec/ikev2_crypto.c | 765 + src/vnet/ipsec/ikev2_format.c | 155 + src/vnet/ipsec/ikev2_payload.c | 535 + src/vnet/ipsec/ikev2_priv.h | 321 + src/vnet/ipsec/ipsec.api | 457 + src/vnet/ipsec/ipsec.c | 581 + src/vnet/ipsec/ipsec.h | 344 + src/vnet/ipsec/ipsec_api.c | 537 + src/vnet/ipsec/ipsec_cli.c | 807 + src/vnet/ipsec/ipsec_format.c | 141 + src/vnet/ipsec/ipsec_if.c | 372 + src/vnet/ipsec/ipsec_if_in.c | 175 + src/vnet/ipsec/ipsec_if_out.c | 161 + src/vnet/ipsec/ipsec_input.c | 455 + src/vnet/ipsec/ipsec_output.c | 478 + src/vnet/l2/dir.dox | 24 + src/vnet/l2/feat_bitmap.c | 185 + src/vnet/l2/feat_bitmap.h | 96 + src/vnet/l2/l2.api | 38 + src/vnet/l2/l2_api.c | 140 + src/vnet/l2/l2_bd.c | 1079 ++ src/vnet/l2/l2_bd.h | 150 + src/vnet/l2/l2_bvi.c | 40 + src/vnet/l2/l2_bvi.h | 117 + src/vnet/l2/l2_classify.h | 116 + src/vnet/l2/l2_efp_filter.c | 614 + src/vnet/l2/l2_efp_filter.h | 33 + src/vnet/l2/l2_fib.c | 857 + src/vnet/l2/l2_fib.h | 341 + src/vnet/l2/l2_flood.c | 568 + src/vnet/l2/l2_flood.h | 35 + src/vnet/l2/l2_fwd.c | 544 + src/vnet/l2/l2_fwd.h | 36 + src/vnet/l2/l2_input.c | 1116 ++ src/vnet/l2/l2_input.h | 266 + src/vnet/l2/l2_input_acl.c | 434 + src/vnet/l2/l2_input_classify.c | 655 + src/vnet/l2/l2_input_vtr.c | 401 + src/vnet/l2/l2_input_vtr.h | 54 + src/vnet/l2/l2_learn.c | 597 + src/vnet/l2/l2_learn.h | 64 + src/vnet/l2/l2_output.c | 708 + src/vnet/l2/l2_output.h | 285 + src/vnet/l2/l2_output_acl.c | 358 + src/vnet/l2/l2_output_classify.c | 657 + src/vnet/l2/l2_patch.c | 452 + src/vnet/l2/l2_rw.c | 719 + src/vnet/l2/l2_rw.h | 95 + src/vnet/l2/l2_vtr.c | 770 + src/vnet/l2/l2_vtr.h | 270 + src/vnet/l2/l2_xcrw.c | 591 + src/vnet/l2/l2_xcrw.h | 91 + src/vnet/l2tp/decap.c | 309 + src/vnet/l2tp/encap.c | 238 + src/vnet/l2tp/l2tp.api | 126 + src/vnet/l2tp/l2tp.c | 739 + src/vnet/l2tp/l2tp.h | 147 + src/vnet/l2tp/l2tp_api.c | 267 + src/vnet/l2tp/packet.h | 44 + src/vnet/l2tp/pg.c | 106 + src/vnet/l3_types.h | 59 + src/vnet/lawful-intercept/lawful_intercept.c | 112 + src/vnet/lawful-intercept/lawful_intercept.h | 45 + src/vnet/lawful-intercept/node.c | 275 + src/vnet/lisp-cp/control.c | 4950 +++++ src/vnet/lisp-cp/control.h | 314 + src/vnet/lisp-cp/gid_dictionary.c | 865 + src/vnet/lisp-cp/gid_dictionary.h | 120 + src/vnet/lisp-cp/lisp.api | 835 + src/vnet/lisp-cp/lisp_api.c | 1257 ++ src/vnet/lisp-cp/lisp_cp_dpo.c | 117 + src/vnet/lisp-cp/lisp_cp_dpo.h | 45 + src/vnet/lisp-cp/lisp_cp_messages.h | 613 + src/vnet/lisp-cp/lisp_msg_serdes.c | 372 + src/vnet/lisp-cp/lisp_msg_serdes.h | 58 + src/vnet/lisp-cp/lisp_types.c | 1574 ++ src/vnet/lisp-cp/lisp_types.h | 354 + src/vnet/lisp-cp/packets.c | 269 + src/vnet/lisp-cp/packets.h | 82 + src/vnet/lisp-gpe/decap.c | 501 + src/vnet/lisp-gpe/dir.dox | 26 + src/vnet/lisp-gpe/interface.c | 709 + src/vnet/lisp-gpe/lisp_gpe.api | 143 + src/vnet/lisp-gpe/lisp_gpe.c | 327 + src/vnet/lisp-gpe/lisp_gpe.h | 257 + src/vnet/lisp-gpe/lisp_gpe_adjacency.c | 542 + src/vnet/lisp-gpe/lisp_gpe_adjacency.h | 136 + src/vnet/lisp-gpe/lisp_gpe_api.c | 304 + src/vnet/lisp-gpe/lisp_gpe_error.def | 18 + src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 1053 ++ src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 188 + src/vnet/lisp-gpe/lisp_gpe_packet.h | 149 + src/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 278 + src/vnet/lisp-gpe/lisp_gpe_sub_interface.h | 157 + src/vnet/lisp-gpe/lisp_gpe_tenant.c | 330 + src/vnet/lisp-gpe/lisp_gpe_tenant.h | 88 + src/vnet/lisp-gpe/lisp_gpe_tunnel.c | 289 + src/vnet/lisp-gpe/lisp_gpe_tunnel.h | 89 + src/vnet/lisp-gpe/rfc.txt | 826 + src/vnet/llc/llc.c | 241 + src/vnet/llc/llc.h | 194 + src/vnet/llc/node.c | 331 + src/vnet/llc/pg.c | 113 + src/vnet/lldp/dir.dox | 18 + src/vnet/lldp/lldp_cli.c | 646 + src/vnet/lldp/lldp_doc.md | 84 + src/vnet/lldp/lldp_input.c | 302 + src/vnet/lldp/lldp_node.c | 341 + src/vnet/lldp/lldp_node.h | 145 + src/vnet/lldp/lldp_output.c | 216 + src/vnet/lldp/lldp_protocol.h | 142 + src/vnet/map/examples/gen-rules.py | 186 + src/vnet/map/examples/health_check.c | 109 + src/vnet/map/examples/test_map.py | 141 + src/vnet/map/gen-rules.py | 107 + src/vnet/map/ip4_map.c | 813 + src/vnet/map/ip4_map_t.c | 1363 ++ src/vnet/map/ip6_map.c | 1269 ++ src/vnet/map/ip6_map_t.c | 1517 ++ src/vnet/map/map.api | 178 + src/vnet/map/map.c | 2166 +++ src/vnet/map/map.h | 591 + src/vnet/map/map_api.c | 295 + src/vnet/map/map_doc.md | 69 + src/vnet/map/map_dpo.c | 191 + src/vnet/map/map_dpo.h | 67 + src/vnet/map/test.c | 205 + src/vnet/mcast/mcast.c | 565 + src/vnet/mcast/mcast.h | 50 + src/vnet/mcast/mcast_test.c | 149 + src/vnet/misc.c | 124 + src/vnet/mpls/error.def | 31 + src/vnet/mpls/interface.c | 121 + src/vnet/mpls/mpls.c | 511 + src/vnet/mpls/mpls.h | 172 + src/vnet/mpls/mpls_features.c | 156 + src/vnet/mpls/mpls_lookup.c | 531 + src/vnet/mpls/mpls_output.c | 479 + src/vnet/mpls/mpls_tunnel.c | 787 + src/vnet/mpls/mpls_tunnel.h | 98 + src/vnet/mpls/mpls_types.h | 39 + src/vnet/mpls/node.c | 303 + src/vnet/mpls/packet.h | 125 + src/vnet/mpls/pg.c | 71 + src/vnet/osi/node.c | 326 + src/vnet/osi/osi.c | 201 + src/vnet/osi/osi.h | 171 + src/vnet/osi/pg.c | 106 + src/vnet/pg/cli.c | 636 + src/vnet/pg/edit.c | 186 + src/vnet/pg/edit.h | 210 + src/vnet/pg/example.script | 6 + src/vnet/pg/init.c | 72 + src/vnet/pg/input.c | 1667 ++ src/vnet/pg/output.c | 85 + src/vnet/pg/pg.h | 383 + src/vnet/pg/stream.c | 497 + src/vnet/pipeline.h | 456 + src/vnet/plugin/p1.c | 52 + src/vnet/plugin/plugin.h | 32 + src/vnet/policer/node_funcs.c | 938 + src/vnet/policer/police.h | 214 + src/vnet/policer/policer.c | 528 + src/vnet/policer/policer.h | 107 + src/vnet/policer/xlate.c | 1505 ++ src/vnet/policer/xlate.h | 186 + src/vnet/ppp/error.def | 42 + src/vnet/ppp/node.c | 368 + src/vnet/ppp/packet.h | 199 + src/vnet/ppp/pg.c | 114 + src/vnet/ppp/ppp.c | 261 + src/vnet/ppp/ppp.h | 135 + src/vnet/replication.c | 293 + src/vnet/replication.h | 136 + src/vnet/rewrite.c | 329 + src/vnet/rewrite.h | 305 + src/vnet/snap/node.c | 353 + src/vnet/snap/pg.c | 116 + src/vnet/snap/snap.c | 204 + src/vnet/snap/snap.h | 209 + src/vnet/span/node.c | 286 + src/vnet/span/span.api | 60 + src/vnet/span/span.c | 197 + src/vnet/span/span.h | 62 + src/vnet/span/span.md | 65 + src/vnet/span/span_api.c | 153 + src/vnet/sr/dir.dox | 25 + src/vnet/sr/examples/sr_multicastmap.script | 4 + src/vnet/sr/rfc_draft_05.txt | 1265 ++ src/vnet/sr/sr.c | 3333 ++++ src/vnet/sr/sr.h | 262 + src/vnet/sr/sr_error.def | 20 + src/vnet/sr/sr_fix_dst_error.def | 17 + src/vnet/sr/sr_packet.h | 251 + src/vnet/sr/sr_replicate.c | 490 + src/vnet/srp/format.c | 147 + src/vnet/srp/interface.c | 458 + src/vnet/srp/node.c | 932 + src/vnet/srp/packet.h | 204 + src/vnet/srp/pg.c | 157 + src/vnet/srp/srp.h | 222 + src/vnet/unix/gdb_funcs.c | 171 + src/vnet/unix/pcap.c | 241 + src/vnet/unix/pcap.h | 230 + src/vnet/unix/pcap2pg.c | 182 + src/vnet/unix/tap.api | 123 + src/vnet/unix/tap_api.c | 257 + src/vnet/unix/tapcli.c | 1328 ++ src/vnet/unix/tapcli.h | 52 + src/vnet/unix/tuntap.c | 1000 ++ src/vnet/unix/tuntap.h | 36 + src/vnet/vnet.h | 96 + src/vnet/vnet_all_api_h.h | 57 + src/vnet/vnet_msg_enum.h | 37 + src/vnet/vxlan-gpe/decap.c | 733 + src/vnet/vxlan-gpe/dir.dox | 32 + src/vnet/vxlan-gpe/encap.c | 388 + src/vnet/vxlan-gpe/vxlan-gpe-rfc.txt | 868 + src/vnet/vxlan-gpe/vxlan_gpe.api | 61 + src/vnet/vxlan-gpe/vxlan_gpe.c | 659 + src/vnet/vxlan-gpe/vxlan_gpe.h | 221 + src/vnet/vxlan-gpe/vxlan_gpe_api.c | 249 + src/vnet/vxlan-gpe/vxlan_gpe_error.def | 16 + src/vnet/vxlan-gpe/vxlan_gpe_packet.h | 110 + src/vnet/vxlan/decap.c | 1130 ++ src/vnet/vxlan/dir.dox | 24 + src/vnet/vxlan/encap.c | 553 + src/vnet/vxlan/vxlan.api | 81 + src/vnet/vxlan/vxlan.c | 899 + src/vnet/vxlan/vxlan.h | 199 + src/vnet/vxlan/vxlan_api.c | 253 + src/vnet/vxlan/vxlan_error.def | 17 + src/vnet/vxlan/vxlan_packet.h | 69 + src/vpp-api-test.am | 64 + src/vpp-api/python/Makefile.am | 60 + src/vpp-api/python/README.rst | 0 src/vpp-api/python/pneum/pneum.c | 259 + src/vpp-api/python/pneum/pneum.h | 31 + src/vpp-api/python/pneum/test_pneum.c | 143 + src/vpp-api/python/setup.cfg | 5 + src/vpp-api/python/setup.py | 34 + src/vpp-api/python/tests/test_cli.py | 52 + src/vpp-api/python/tests/test_modules.py | 18 + src/vpp-api/python/tests/test_papi.py | 119 + src/vpp-api/python/tests/test_version.py | 35 + src/vpp-api/python/tests/test_vpp_papi2.py | 487 + src/vpp-api/python/vpp_papi/__init__.py | 3 + src/vpp-api/python/vpp_papi/pneum_wrap.c | 200 + src/vpp-api/python/vpp_papi/vpp_papi.py | 450 + src/vpp.am | 159 + src/vpp/api/api.c | 4922 +++++ src/vpp/api/api_format.c | 1 + src/vpp/api/api_main.c | 192 + src/vpp/api/custom_dump.c | 3139 ++++ src/vpp/api/gmon.c | 319 + src/vpp/api/json_format.c | 304 + src/vpp/api/json_format.h | 254 + src/vpp/api/summary_stats_client.c | 302 + src/vpp/api/test_client.c | 1531 ++ src/vpp/api/test_ha.c | 249 + src/vpp/api/vat.h | 1 + src/vpp/api/vpe.api | 2782 +++ src/vpp/api/vpe_all_api_h.h | 37 + src/vpp/api/vpe_msg_enum.h | 37 + src/vpp/api/vpp_get_metrics.c | 253 + src/vpp/app/l2t.c | 557 + src/vpp/app/l2t_l2.c | 267 + src/vpp/app/sticky_hash.c | 581 + src/vpp/app/version.c | 102 + src/vpp/app/vpe_cli.c | 123 + src/vpp/conf/80-vpp.conf | 15 + src/vpp/conf/startup.conf | 99 + src/vpp/conf/startup.uiopcigeneric.conf | 18 + src/vpp/oam/oam.c | 648 + src/vpp/oam/oam.h | 96 + src/vpp/stats/stats.c | 987 + src/vpp/stats/stats.h | 76 + src/vpp/vnet/main.c | 415 + src/vppapigen.am | 27 + src/vppinfra.am | 276 + src/vppinfra/README | 43 + src/vppinfra/anneal.c | 172 + src/vppinfra/anneal.h | 89 + src/vppinfra/asm_mips.h | 351 + src/vppinfra/asm_x86.c | 1947 ++ src/vppinfra/asm_x86.h | 125 + src/vppinfra/backtrace.c | 267 + src/vppinfra/bihash_24_8.h | 85 + src/vppinfra/bihash_8_8.h | 98 + src/vppinfra/bihash_doc.h | 149 + src/vppinfra/bihash_template.c | 455 + src/vppinfra/bihash_template.h | 214 + src/vppinfra/bitmap.h | 774 + src/vppinfra/bitops.h | 179 + src/vppinfra/byte_order.h | 202 + src/vppinfra/cache.h | 104 + src/vppinfra/clib.h | 359 + src/vppinfra/cpu.c | 133 + src/vppinfra/cpu.h | 112 + src/vppinfra/dir.dox | 19 + src/vppinfra/dlist.h | 156 + src/vppinfra/elf.c | 2040 +++ src/vppinfra/elf.h | 1062 ++ src/vppinfra/elf_clib.c | 377 + src/vppinfra/elf_clib.h | 144 + src/vppinfra/elog.c | 1061 ++ src/vppinfra/elog.h | 460 + src/vppinfra/error.c | 292 + src/vppinfra/error.h | 201 + src/vppinfra/error_bootstrap.h | 106 + src/vppinfra/fheap.c | 473 + src/vppinfra/fheap.h | 140 + src/vppinfra/fifo.c | 137 + src/vppinfra/fifo.h | 304 + src/vppinfra/format.c | 814 + src/vppinfra/format.h | 331 + src/vppinfra/graph.c | 182 + src/vppinfra/graph.h | 127 + src/vppinfra/hash.c | 1095 ++ src/vppinfra/hash.h | 699 + src/vppinfra/heap.c | 828 + src/vppinfra/heap.h | 357 + src/vppinfra/longjmp.S | 690 + src/vppinfra/longjmp.h | 124 + src/vppinfra/macros.c | 266 + src/vppinfra/macros.h | 54 + src/vppinfra/math.h | 63 + src/vppinfra/md5.c | 317 + src/vppinfra/md5.h | 57 + src/vppinfra/mem.h | 291 + src/vppinfra/mem_mheap.c | 165 + src/vppinfra/memcheck.h | 317 + src/vppinfra/memcpy_avx.h | 293 + src/vppinfra/memcpy_sse3.h | 355 + src/vppinfra/mhash.c | 408 + src/vppinfra/mhash.h | 179 + src/vppinfra/mheap.c | 1649 ++ src/vppinfra/mheap.h | 94 + src/vppinfra/mheap_bootstrap.h | 374 + src/vppinfra/mod_test_hash.c | 27 + src/vppinfra/os.h | 72 + src/vppinfra/pfhash.c | 689 + src/vppinfra/pfhash.h | 276 + src/vppinfra/phash.c | 1017 ++ src/vppinfra/phash.h | 194 + src/vppinfra/pipeline.h | 176 + src/vppinfra/pool.h | 405 + src/vppinfra/ptclosure.c | 125 + src/vppinfra/ptclosure.h | 40 + src/vppinfra/qhash.c | 858 + src/vppinfra/qhash.h | 169 + src/vppinfra/qsort.c | 269 + src/vppinfra/random.c | 51 + src/vppinfra/random.h | 178 + src/vppinfra/random_buffer.c | 86 + src/vppinfra/random_buffer.h | 118 + src/vppinfra/random_isaac.c | 434 + src/vppinfra/random_isaac.h | 81 + src/vppinfra/serialize.c | 1254 ++ src/vppinfra/serialize.h | 443 + src/vppinfra/slist.c | 336 + src/vppinfra/slist.h | 145 + src/vppinfra/smp.c | 325 + src/vppinfra/smp.h | 81 + src/vppinfra/smp_fifo.c | 91 + src/vppinfra/smp_fifo.h | 313 + src/vppinfra/socket.c | 422 + src/vppinfra/socket.h | 160 + src/vppinfra/sparse_vec.h | 244 + src/vppinfra/std-formats.c | 330 + src/vppinfra/string.c | 94 + src/vppinfra/string.h | 83 + src/vppinfra/test_bihash_template.c | 297 + src/vppinfra/test_dlist.c | 193 + src/vppinfra/test_elf.c | 217 + src/vppinfra/test_elog.c | 262 + src/vppinfra/test_fifo.c | 144 + src/vppinfra/test_format.c | 199 + src/vppinfra/test_hash.c | 458 + src/vppinfra/test_heap.c | 198 + src/vppinfra/test_longjmp.c | 129 + src/vppinfra/test_macros.c | 64 + src/vppinfra/test_md5.c | 141 + src/vppinfra/test_mheap.c | 242 + src/vppinfra/test_pfhash.c | 322 + src/vppinfra/test_phash.c | 149 + src/vppinfra/test_pool.c | 86 + src/vppinfra/test_pool_iterate.c | 59 + src/vppinfra/test_ptclosure.c | 212 + src/vppinfra/test_qhash.c | 333 + src/vppinfra/test_random.c | 148 + src/vppinfra/test_random_isaac.c | 142 + src/vppinfra/test_serialize.c | 274 + src/vppinfra/test_slist.c | 228 + src/vppinfra/test_socket.c | 134 + src/vppinfra/test_time.c | 104 + src/vppinfra/test_timing_wheel.c | 389 + src/vppinfra/test_vec.c | 1159 ++ src/vppinfra/test_vec.h | 243 + src/vppinfra/test_vhash.c | 757 + src/vppinfra/test_zvec.c | 117 + src/vppinfra/time.c | 226 + src/vppinfra/time.h | 298 + src/vppinfra/timer.c | 322 + src/vppinfra/timer.h | 46 + src/vppinfra/timing_wheel.c | 750 + src/vppinfra/timing_wheel.h | 155 + src/vppinfra/types.h | 174 + src/vppinfra/unformat.c | 1077 ++ src/vppinfra/unix-formats.c | 918 + src/vppinfra/unix-kelog.c | 415 + src/vppinfra/unix-misc.c | 242 + src/vppinfra/unix.h | 64 + src/vppinfra/unix_error.def | 145 + src/vppinfra/valgrind.h | 4030 +++++ src/vppinfra/vec.c | 171 + src/vppinfra/vec.h | 973 + src/vppinfra/vec_bootstrap.h | 201 + src/vppinfra/vector.c | 54 + src/vppinfra/vector.h | 268 + src/vppinfra/vector_altivec.h | 178 + src/vppinfra/vector_funcs.h | 334 + src/vppinfra/vector_iwmmxt.h | 149 + src/vppinfra/vector_neon.h | 71 + src/vppinfra/vector_sse2.h | 711 + src/vppinfra/vhash.c | 772 + src/vppinfra/vhash.h | 850 + src/vppinfra/vm_linux_kernel.h | 78 + src/vppinfra/vm_standalone.h | 74 + src/vppinfra/vm_unix.h | 106 + src/vppinfra/xxhash.h | 86 + src/vppinfra/xy.h | 56 + src/vppinfra/zvec.c | 442 + src/vppinfra/zvec.h | 166 + svm/Makefile.am | 30 - svm/configure.ac | 7 - svm/dir.dox | 21 - svm/persist.c | 258 - svm/ssvm.c | 178 - svm/ssvm.h | 155 - svm/svm.c | 1237 -- svm/svm.h | 207 - svm/svm_test.c | 79 - svm/svmdb.c | 671 - svm/svmdb.h | 135 - svm/svmdbtool.c | 537 - svm/svmtool.c | 528 - vlib-api/Makefile.am | 84 - vlib-api/configure.ac | 9 - vlib-api/suffix-rules.mk | 1 - vlib-api/vlibapi/api.h | 281 - vlib-api/vlibapi/api_helper_macros.h | 243 - vlib-api/vlibapi/api_shared.c | 1375 -- vlib-api/vlibapi/node_serialize.c | 399 - vlib-api/vlibmemory/api.h | 163 - vlib-api/vlibmemory/memclnt.api | 91 - vlib-api/vlibmemory/memory_client.c | 283 - vlib-api/vlibmemory/memory_shared.c | 852 - vlib-api/vlibmemory/memory_vlib.c | 1346 -- vlib-api/vlibmemory/unix_shared_memory_queue.c | 324 - vlib-api/vlibmemory/unix_shared_memory_queue.h | 69 - vlib-api/vlibmemory/vl_memory_api_h.h | 32 - vlib-api/vlibmemory/vl_memory_msg_enum.h | 42 - vlib-api/vlibsocket/api.h | 87 - vlib-api/vlibsocket/sock_test.c | 155 - vlib-api/vlibsocket/sockclnt.api | 50 - vlib-api/vlibsocket/sockclnt_vlib.c | 209 - vlib-api/vlibsocket/socksvr_vlib.c | 706 - vlib-api/vlibsocket/vl_socket_api_h.h | 33 - vlib-api/vlibsocket/vl_socket_msg_enum.h | 42 - vlib/.gitignore | 1 - vlib/Makefile.am | 104 - vlib/configure.ac | 25 - vlib/dir.dox | 21 - vlib/example/dir.dox | 22 - vlib/example/main_stub.c | 418 - vlib/example/mc_test.c | 384 - vlib/example/plex_test.c | 527 - vlib/vlib/buffer.c | 1987 --- vlib/vlib/buffer.h | 417 - vlib/vlib/buffer_funcs.h | 755 - vlib/vlib/buffer_node.h | 337 - vlib/vlib/cli.c | 1173 -- vlib/vlib/cli.h | 192 - vlib/vlib/cli_funcs.h | 58 - vlib/vlib/counter.c | 151 - vlib/vlib/counter.h | 379 - vlib/vlib/defs.h | 82 - vlib/vlib/dir.dox | 23 - vlib/vlib/elog_samples.c | 122 - vlib/vlib/error.c | 338 - vlib/vlib/error.h | 101 - vlib/vlib/error_funcs.h | 88 - vlib/vlib/format.c | 196 - vlib/vlib/format_funcs.h | 75 - vlib/vlib/global_funcs.h | 45 - vlib/vlib/i2c.c | 231 - vlib/vlib/i2c.h | 67 - vlib/vlib/init.c | 168 - vlib/vlib/init.h | 238 - vlib/vlib/lex.c | 271 - vlib/vlib/lex.h | 145 - vlib/vlib/main.c | 1703 -- vlib/vlib/main.h | 333 - vlib/vlib/mc.c | 2609 --- vlib/vlib/mc.h | 687 - vlib/vlib/node.c | 631 - vlib/vlib/node.h | 725 - vlib/vlib/node_cli.c | 466 - vlib/vlib/node_format.c | 187 - vlib/vlib/node_funcs.h | 1130 -- vlib/vlib/parse.c | 1007 -- vlib/vlib/parse.h | 221 - vlib/vlib/parse_builtin.c | 150 - vlib/vlib/pci/linux_pci.c | 642 - vlib/vlib/pci/pci.c | 264 - vlib/vlib/pci/pci.h | 251 - vlib/vlib/pci/pci_config.h | 731 - vlib/vlib/physmem.h | 108 - vlib/vlib/threads.c | 1492 -- vlib/vlib/threads.h | 470 - vlib/vlib/threads_cli.c | 579 - vlib/vlib/trace.c | 545 - vlib/vlib/trace.h | 100 - vlib/vlib/trace_funcs.h | 185 - vlib/vlib/unix/cj.c | 271 - vlib/vlib/unix/cj.h | 79 - vlib/vlib/unix/cli.c | 2989 ---- vlib/vlib/unix/dir.dox | 28 - vlib/vlib/unix/input.c | 265 - vlib/vlib/unix/main.c | 557 - vlib/vlib/unix/mc_socket.c | 1049 -- vlib/vlib/unix/mc_socket.h | 137 - vlib/vlib/unix/physmem.c | 470 - vlib/vlib/unix/physmem.h | 65 - vlib/vlib/unix/plugin.c | 260 - vlib/vlib/unix/plugin.h | 98 - vlib/vlib/unix/unix.h | 232 - vlib/vlib/unix/util.c | 231 - vlib/vlib/vlib.h | 86 - vlib/vlib/vlib_process_doc.h | 147 - vnet/.gitignore | 1 - vnet/Makefile.am | 993 -- vnet/configure.ac | 49 - vnet/etc/scripts/arp4 | 21 - vnet/etc/scripts/arp4-mpls | 24 - vnet/etc/scripts/arp6 | 21 - vnet/etc/scripts/bvi | 76 - vnet/etc/scripts/dhcp/dhcpd.conf | 8 - vnet/etc/scripts/dhcp/left-ping-target.sh | 4 - vnet/etc/scripts/dhcp/leftpeer.conf | 17 - vnet/etc/scripts/icmp | 16 - vnet/etc/scripts/icmp6 | 16 - vnet/etc/scripts/ige | 19 - vnet/etc/scripts/ip6 | 15 - vnet/etc/scripts/ip6-hbh | 84 - vnet/etc/scripts/ixge | 15 - vnet/etc/scripts/l2efpfilter | 83 - vnet/etc/scripts/l2efpfilter_perf | 58 - vnet/etc/scripts/l2fib | 46 - vnet/etc/scripts/l2fib_perf | 29 - vnet/etc/scripts/l2fib_xc | 31 - vnet/etc/scripts/l2flood | 42 - vnet/etc/scripts/l2tp | 134 - vnet/etc/scripts/leftpeer/leftpeer-classify | 8 - vnet/etc/scripts/leftpeer/leftpeer-classify6 | 5 - vnet/etc/scripts/leftpeer/leftpeer-classifyl2 | 8 - vnet/etc/scripts/leftpeer/leftpeer-dhcp | 23 - vnet/etc/scripts/leftpeer/leftpeer-ioam.conf | 15 - vnet/etc/scripts/leftpeer/leftpeer-l3vxlan.conf | 12 - vnet/etc/scripts/leftpeer/leftpeer-lisp.conf | 18 - vnet/etc/scripts/leftpeer/leftpeer-mpls.conf | 17 - vnet/etc/scripts/leftpeer/leftpeer-sr.conf | 24 - vnet/etc/scripts/leftpeer/leftpeer-vxlan.conf | 17 - vnet/etc/scripts/leftpeer/leftpeer.script | 9 - vnet/etc/scripts/lfib/ip4-to-mpls | 26 - vnet/etc/scripts/lfib/mpls-pop-to-mpls | 28 - vnet/etc/scripts/lfib/mpls-to-ip4 | 27 - vnet/etc/scripts/lfib/mpls-to-mpls | 26 - vnet/etc/scripts/mpls-o-ethernet/leftpeer.conf | 17 - vnet/etc/scripts/mpls-o-ethernet/pg | 10 - vnet/etc/scripts/mpls-o-ethernet/rightpeer.conf | 15 - vnet/etc/scripts/mpls-o-ethernet/single.conf | 17 - vnet/etc/scripts/mpls-o-gre/dhcpd.conf | 116 - vnet/etc/scripts/mpls-o-gre/leftpeer.conf | 14 - vnet/etc/scripts/mpls-o-gre/rightpeer.conf | 14 - vnet/etc/scripts/mpls-tunnel | 87 - vnet/etc/scripts/pcap | 18 - vnet/etc/scripts/probe4 | 11 - vnet/etc/scripts/probe6 | 7 - vnet/etc/scripts/rewrite | 62 - vnet/etc/scripts/rightpeer/rightpeer-ioam.conf | 14 - vnet/etc/scripts/rightpeer/rightpeer-l3vxlan.conf | 9 - vnet/etc/scripts/rightpeer/rightpeer-lisp.conf | 16 - vnet/etc/scripts/rightpeer/rightpeer-mpls-l2.conf | 24 - vnet/etc/scripts/rightpeer/rightpeer-mpls.conf | 17 - vnet/etc/scripts/rightpeer/rightpeer-sr.conf | 28 - vnet/etc/scripts/rightpeer/rightpeer-vxlan.conf | 16 - vnet/etc/scripts/rightpeer/rightpeer.script | 9 - vnet/etc/scripts/rpf | 18 - vnet/etc/scripts/rtt-test | 31 - vnet/etc/scripts/snat | 34 - vnet/etc/scripts/snat_static | 44 - vnet/etc/scripts/snat_static_with_port | 44 - vnet/etc/scripts/source_and_port_range_check | 63 - vnet/etc/scripts/speed | 14 - vnet/etc/scripts/sr/left-linux-ping.sh | 3 - vnet/etc/scripts/sr/leftpeer.conf | 27 - vnet/etc/scripts/sr/right-linux-ping.sh | 4 - vnet/etc/scripts/sr/rightpeer.conf | 22 - vnet/etc/scripts/sr/srlocal.sh | 4 - vnet/etc/scripts/srp | 27 - vnet/etc/scripts/tcp | 16 - vnet/etc/scripts/tcp-test | 6 - vnet/etc/scripts/tf-ucs-1 | 16 - vnet/etc/scripts/urpf | 86 - vnet/etc/scripts/virl/ip6sr.virl | 874 - vnet/etc/scripts/virl/ip6sr_notes.txt | 38 - vnet/etc/scripts/virl/mplsogre.virl | 319 - vnet/etc/scripts/virl/simple.virl | 389 - vnet/etc/scripts/vlan | 23 - vnet/suffix-rules.mk | 1 - vnet/test/README | 10 - vnet/test/lisp-cp/test_cp_serdes.c | 635 - vnet/test/lisp-cp/test_lisp_types.c | 561 - vnet/test/lisp-gpe/test.c | 18 - vnet/vnet/adj/adj.c | 454 - vnet/vnet/adj/adj.h | 122 - vnet/vnet/adj/adj_glean.c | 285 - vnet/vnet/adj/adj_glean.h | 61 - vnet/vnet/adj/adj_internal.h | 104 - vnet/vnet/adj/adj_l2.c | 194 - vnet/vnet/adj/adj_l2.h | 24 - vnet/vnet/adj/adj_midchain.c | 559 - vnet/vnet/adj/adj_midchain.h | 102 - vnet/vnet/adj/adj_nbr.c | 1087 -- vnet/vnet/adj/adj_nbr.h | 176 - vnet/vnet/adj/adj_rewrite.c | 53 - vnet/vnet/adj/adj_rewrite.h | 49 - vnet/vnet/adj/adj_types.h | 53 - vnet/vnet/api_errno.h | 113 - vnet/vnet/bfd/bfd.api | 205 - vnet/vnet/bfd/bfd_api.c | 262 - vnet/vnet/bfd/bfd_api.h | 46 - vnet/vnet/bfd/bfd_debug.h | 79 - vnet/vnet/bfd/bfd_doc.md | 1 - vnet/vnet/bfd/bfd_main.c | 969 - vnet/vnet/bfd/bfd_main.h | 220 - vnet/vnet/bfd/bfd_protocol.c | 74 - vnet/vnet/bfd/bfd_protocol.h | 154 - vnet/vnet/bfd/bfd_udp.c | 639 - vnet/vnet/bfd/bfd_udp.h | 56 - vnet/vnet/bfd/dir.dox | 18 - vnet/vnet/buffer.h | 381 - vnet/vnet/cdp/cdp.pg | 7 - vnet/vnet/cdp/cdp_input.c | 506 - vnet/vnet/cdp/cdp_node.c | 208 - vnet/vnet/cdp/cdp_node.h | 147 - vnet/vnet/cdp/cdp_periodic.c | 512 - vnet/vnet/cdp/cdp_protocol.h | 186 - vnet/vnet/classify/README | 180 - vnet/vnet/classify/flow_classify.c | 212 - vnet/vnet/classify/flow_classify.h | 51 - vnet/vnet/classify/flow_classify_node.c | 338 - vnet/vnet/classify/input_acl.c | 283 - vnet/vnet/classify/input_acl.h | 54 - vnet/vnet/classify/ip_classify.c | 365 - vnet/vnet/classify/policer_classify.c | 227 - vnet/vnet/classify/policer_classify.h | 55 - vnet/vnet/classify/vnet_classify.c | 2436 --- vnet/vnet/classify/vnet_classify.h | 523 - vnet/vnet/config.c | 361 - vnet/vnet/config.h | 176 - vnet/vnet/cop/cop.c | 387 - vnet/vnet/cop/cop.h | 89 - vnet/vnet/cop/ip4_whitelist.c | 356 - vnet/vnet/cop/ip6_whitelist.c | 298 - vnet/vnet/cop/node1.c | 319 - vnet/vnet/devices/af_packet/af_packet.api | 71 - vnet/vnet/devices/af_packet/af_packet.c | 366 - vnet/vnet/devices/af_packet/af_packet.h | 69 - vnet/vnet/devices/af_packet/af_packet_api.c | 143 - vnet/vnet/devices/af_packet/cli.c | 144 - vnet/vnet/devices/af_packet/device.c | 250 - vnet/vnet/devices/af_packet/node.c | 288 - vnet/vnet/devices/devices.c | 91 - vnet/vnet/devices/devices.h | 53 - vnet/vnet/devices/dpdk/cli.c | 1296 -- vnet/vnet/devices/dpdk/device.c | 840 - vnet/vnet/devices/dpdk/dpdk.h | 534 - vnet/vnet/devices/dpdk/dpdk_priv.h | 132 - vnet/vnet/devices/dpdk/format.c | 763 - vnet/vnet/devices/dpdk/hqos.c | 775 - vnet/vnet/devices/dpdk/init.c | 1803 -- vnet/vnet/devices/dpdk/ipsec/cli.c | 141 - vnet/vnet/devices/dpdk/ipsec/crypto_node.c | 210 - vnet/vnet/devices/dpdk/ipsec/dir.dox | 18 - .../devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md | 73 - vnet/vnet/devices/dpdk/ipsec/esp.h | 295 - vnet/vnet/devices/dpdk/ipsec/esp_decrypt.c | 583 - vnet/vnet/devices/dpdk/ipsec/esp_encrypt.c | 598 - vnet/vnet/devices/dpdk/ipsec/ipsec.c | 313 - vnet/vnet/devices/dpdk/ipsec/ipsec.h | 227 - vnet/vnet/devices/dpdk/node.c | 687 - vnet/vnet/devices/dpdk/qos_doc.md | 404 - vnet/vnet/devices/netmap/cli.c | 146 - vnet/vnet/devices/netmap/device.c | 261 - vnet/vnet/devices/netmap/net_netmap.h | 650 - vnet/vnet/devices/netmap/netmap.api | 74 - vnet/vnet/devices/netmap/netmap.c | 316 - vnet/vnet/devices/netmap/netmap.h | 164 - vnet/vnet/devices/netmap/netmap_api.c | 137 - vnet/vnet/devices/netmap/node.c | 300 - vnet/vnet/devices/nic/ixge.c | 2938 --- vnet/vnet/devices/nic/ixge.h | 1293 -- vnet/vnet/devices/nic/sfp.c | 117 - vnet/vnet/devices/nic/sfp.h | 117 - vnet/vnet/devices/ssvm/node.c | 343 - vnet/vnet/devices/ssvm/ssvm_eth.c | 491 - vnet/vnet/devices/ssvm/ssvm_eth.h | 141 - vnet/vnet/devices/virtio/dir.dox | 27 - vnet/vnet/devices/virtio/vhost-user.c | 3314 ---- vnet/vnet/devices/virtio/vhost-user.h | 350 - vnet/vnet/devices/virtio/vhost_user.api | 125 - vnet/vnet/devices/virtio/vhost_user_api.c | 262 - vnet/vnet/dhcp/client.c | 1031 -- vnet/vnet/dhcp/client.h | 118 - vnet/vnet/dhcp/packet.h | 61 - vnet/vnet/dhcp/proxy.h | 92 - vnet/vnet/dhcp/proxy_error.def | 30 - vnet/vnet/dhcp/proxy_node.c | 1114 -- vnet/vnet/dhcpv6/packet.h | 183 - vnet/vnet/dhcpv6/proxy.h | 95 - vnet/vnet/dhcpv6/proxy_error.def | 29 - vnet/vnet/dhcpv6/proxy_node.c | 1191 -- vnet/vnet/dpo/classify_dpo.c | 131 - vnet/vnet/dpo/classify_dpo.h | 56 - vnet/vnet/dpo/dpo.c | 500 - vnet/vnet/dpo/dpo.h | 381 - vnet/vnet/dpo/drop_dpo.c | 106 - vnet/vnet/dpo/drop_dpo.h | 31 - vnet/vnet/dpo/ip_null_dpo.c | 408 - vnet/vnet/dpo/ip_null_dpo.h | 56 - vnet/vnet/dpo/load_balance.c | 993 -- vnet/vnet/dpo/load_balance.h | 211 - vnet/vnet/dpo/load_balance_map.c | 575 - vnet/vnet/dpo/load_balance_map.h | 79 - vnet/vnet/dpo/lookup_dpo.c | 1185 -- vnet/vnet/dpo/lookup_dpo.h | 108 - vnet/vnet/dpo/mpls_label_dpo.c | 570 - vnet/vnet/dpo/mpls_label_dpo.h | 101 - vnet/vnet/dpo/punt_dpo.c | 100 - vnet/vnet/dpo/punt_dpo.h | 30 - vnet/vnet/dpo/receive_dpo.c | 165 - vnet/vnet/dpo/receive_dpo.h | 62 - vnet/vnet/ethernet/arp.c | 2355 --- vnet/vnet/ethernet/arp_packet.h | 173 - vnet/vnet/ethernet/dir.dox | 24 - vnet/vnet/ethernet/error.def | 46 - vnet/vnet/ethernet/ethernet.h | 561 - vnet/vnet/ethernet/format.c | 366 - vnet/vnet/ethernet/init.c | 128 - vnet/vnet/ethernet/interface.c | 730 - vnet/vnet/ethernet/mac_swap.c | 397 - vnet/vnet/ethernet/node.c | 1368 -- vnet/vnet/ethernet/packet.h | 152 - vnet/vnet/ethernet/pg.c | 183 - vnet/vnet/ethernet/types.def | 113 - vnet/vnet/feature/feature.c | 463 - vnet/vnet/feature/feature.h | 382 - vnet/vnet/feature/registration.c | 301 - vnet/vnet/fib/fib.c | 41 - vnet/vnet/fib/fib.h | 652 - vnet/vnet/fib/fib_api.h | 54 - vnet/vnet/fib/fib_attached_export.c | 572 - vnet/vnet/fib/fib_attached_export.h | 57 - vnet/vnet/fib/fib_entry.c | 1503 -- vnet/vnet/fib/fib_entry.h | 530 - vnet/vnet/fib/fib_entry_cover.c | 225 - vnet/vnet/fib/fib_entry_cover.h | 47 - vnet/vnet/fib/fib_entry_delegate.c | 149 - vnet/vnet/fib/fib_entry_delegate.h | 124 - vnet/vnet/fib/fib_entry_src.c | 1456 -- vnet/vnet/fib/fib_entry_src.h | 296 - vnet/vnet/fib/fib_entry_src_adj.c | 207 - vnet/vnet/fib/fib_entry_src_api.c | 119 - vnet/vnet/fib/fib_entry_src_default.c | 121 - vnet/vnet/fib/fib_entry_src_default_route.c | 58 - vnet/vnet/fib/fib_entry_src_interface.c | 195 - vnet/vnet/fib/fib_entry_src_lisp.c | 133 - vnet/vnet/fib/fib_entry_src_mpls.c | 196 - vnet/vnet/fib/fib_entry_src_rr.c | 293 - vnet/vnet/fib/fib_entry_src_special.c | 71 - vnet/vnet/fib/fib_internal.h | 69 - vnet/vnet/fib/fib_node.c | 277 - vnet/vnet/fib/fib_node.h | 371 - vnet/vnet/fib/fib_node_list.c | 390 - vnet/vnet/fib/fib_node_list.h | 64 - vnet/vnet/fib/fib_path.c | 2001 --- vnet/vnet/fib/fib_path.h | 158 - vnet/vnet/fib/fib_path_ext.c | 231 - vnet/vnet/fib/fib_path_ext.h | 69 - vnet/vnet/fib/fib_path_list.c | 1223 -- vnet/vnet/fib/fib_path_list.h | 158 - vnet/vnet/fib/fib_table.c | 1104 -- vnet/vnet/fib/fib_table.h | 732 - vnet/vnet/fib/fib_test.c | 7112 -------- vnet/vnet/fib/fib_types.c | 326 - vnet/vnet/fib/fib_types.h | 340 - vnet/vnet/fib/fib_urpf_list.c | 260 - vnet/vnet/fib/fib_urpf_list.h | 146 - vnet/vnet/fib/fib_walk.c | 1108 -- vnet/vnet/fib/fib_walk.h | 58 - vnet/vnet/fib/ip4_fib.c | 664 - vnet/vnet/fib/ip4_fib.h | 141 - vnet/vnet/fib/ip6_fib.c | 784 - vnet/vnet/fib/ip6_fib.h | 130 - vnet/vnet/fib/mpls_fib.c | 439 - vnet/vnet/fib/mpls_fib.h | 106 - vnet/vnet/flow/flow_report.c | 502 - vnet/vnet/flow/flow_report.h | 145 - vnet/vnet/flow/flow_report_classify.c | 529 - vnet/vnet/flow/flow_report_classify.h | 122 - vnet/vnet/flow/ipfix_info_elements.h | 429 - vnet/vnet/flow/ipfix_packet.h | 188 - vnet/vnet/global_funcs.h | 32 - vnet/vnet/gre/error.def | 23 - vnet/vnet/gre/gre.api | 57 - vnet/vnet/gre/gre.c | 455 - vnet/vnet/gre/gre.h | 235 - vnet/vnet/gre/gre_api.c | 204 - vnet/vnet/gre/interface.c | 606 - vnet/vnet/gre/node.c | 531 - vnet/vnet/gre/packet.h | 55 - vnet/vnet/gre/pg.c | 77 - vnet/vnet/handoff.c | 594 - vnet/vnet/handoff.h | 259 - vnet/vnet/hdlc/error.def | 42 - vnet/vnet/hdlc/hdlc.c | 249 - vnet/vnet/hdlc/hdlc.h | 127 - vnet/vnet/hdlc/node.c | 351 - vnet/vnet/hdlc/packet.h | 72 - vnet/vnet/hdlc/pg.c | 105 - vnet/vnet/interface.api | 339 - vnet/vnet/interface.c | 1398 -- vnet/vnet/interface.h | 658 - vnet/vnet/interface_api.c | 725 - vnet/vnet/interface_cli.c | 1165 -- vnet/vnet/interface_format.c | 401 - vnet/vnet/interface_funcs.h | 318 - vnet/vnet/interface_output.c | 1404 -- vnet/vnet/ip/dir.dox | 26 - vnet/vnet/ip/format.c | 121 - vnet/vnet/ip/format.h | 114 - vnet/vnet/ip/icmp4.c | 784 - vnet/vnet/ip/icmp4.h | 60 - vnet/vnet/ip/icmp46_packet.h | 398 - vnet/vnet/ip/icmp6.c | 882 - vnet/vnet/ip/icmp6.h | 86 - vnet/vnet/ip/igmp_packet.h | 155 - vnet/vnet/ip/ip.api | 434 - vnet/vnet/ip/ip.h | 195 - vnet/vnet/ip/ip4.h | 322 - vnet/vnet/ip/ip46_cli.c | 236 - vnet/vnet/ip/ip4_error.h | 95 - vnet/vnet/ip/ip4_format.c | 256 - vnet/vnet/ip/ip4_forward.c | 3345 ---- vnet/vnet/ip/ip4_input.c | 507 - vnet/vnet/ip/ip4_mtrie.c | 568 - vnet/vnet/ip/ip4_mtrie.h | 188 - vnet/vnet/ip/ip4_packet.h | 384 - vnet/vnet/ip/ip4_pg.c | 387 - vnet/vnet/ip/ip4_source_and_port_range_check.c | 1415 -- vnet/vnet/ip/ip4_source_check.c | 573 - vnet/vnet/ip/ip4_test.c | 340 - vnet/vnet/ip/ip6.h | 476 - vnet/vnet/ip/ip6_error.h | 92 - vnet/vnet/ip/ip6_format.c | 383 - vnet/vnet/ip/ip6_forward.c | 3402 ---- vnet/vnet/ip/ip6_hop_by_hop.c | 1194 -- vnet/vnet/ip/ip6_hop_by_hop.h | 217 - vnet/vnet/ip/ip6_hop_by_hop_packet.h | 66 - vnet/vnet/ip/ip6_input.c | 353 - vnet/vnet/ip/ip6_neighbor.c | 4088 ----- vnet/vnet/ip/ip6_neighbor.h | 52 - vnet/vnet/ip/ip6_packet.h | 499 - vnet/vnet/ip/ip6_pg.c | 231 - vnet/vnet/ip/ip_api.c | 1196 -- vnet/vnet/ip/ip_checksum.c | 228 - vnet/vnet/ip/ip_frag.c | 581 - vnet/vnet/ip/ip_frag.h | 96 - vnet/vnet/ip/ip_init.c | 152 - vnet/vnet/ip/ip_input_acl.c | 450 - vnet/vnet/ip/ip_packet.h | 180 - vnet/vnet/ip/ip_source_and_port_range_check.h | 148 - vnet/vnet/ip/lookup.c | 967 - vnet/vnet/ip/lookup.h | 498 - vnet/vnet/ip/ping.c | 888 - vnet/vnet/ip/ping.h | 108 - vnet/vnet/ip/ports.def | 757 - vnet/vnet/ip/protocols.def | 162 - vnet/vnet/ip/punt.c | 323 - vnet/vnet/ip/punt.h | 43 - vnet/vnet/ip/punt_error.def | 19 - vnet/vnet/ip/tcp_packet.h | 138 - vnet/vnet/ip/udp.h | 313 - vnet/vnet/ip/udp_error.def | 21 - vnet/vnet/ip/udp_format.c | 91 - vnet/vnet/ip/udp_init.c | 71 - vnet/vnet/ip/udp_local.c | 645 - vnet/vnet/ip/udp_packet.h | 65 - vnet/vnet/ip/udp_pg.c | 237 - vnet/vnet/ipsec-gre/dir.dox | 18 - vnet/vnet/ipsec-gre/error.def | 26 - vnet/vnet/ipsec-gre/interface.c | 311 - vnet/vnet/ipsec-gre/ipsec_gre.api | 79 - vnet/vnet/ipsec-gre/ipsec_gre.c | 407 - vnet/vnet/ipsec-gre/ipsec_gre.h | 114 - vnet/vnet/ipsec-gre/ipsec_gre_api.c | 190 - vnet/vnet/ipsec-gre/ipsec_gre_doc.md | 74 - vnet/vnet/ipsec-gre/node.c | 433 - vnet/vnet/ipsec/esp.h | 320 - vnet/vnet/ipsec/esp_decrypt.c | 430 - vnet/vnet/ipsec/esp_encrypt.c | 425 - vnet/vnet/ipsec/ikev2.c | 2186 --- vnet/vnet/ipsec/ikev2.h | 410 - vnet/vnet/ipsec/ikev2_cli.c | 479 - vnet/vnet/ipsec/ikev2_crypto.c | 765 - vnet/vnet/ipsec/ikev2_format.c | 155 - vnet/vnet/ipsec/ikev2_payload.c | 535 - vnet/vnet/ipsec/ikev2_priv.h | 321 - vnet/vnet/ipsec/ipsec.api | 457 - vnet/vnet/ipsec/ipsec.c | 581 - vnet/vnet/ipsec/ipsec.h | 344 - vnet/vnet/ipsec/ipsec_api.c | 537 - vnet/vnet/ipsec/ipsec_cli.c | 807 - vnet/vnet/ipsec/ipsec_format.c | 141 - vnet/vnet/ipsec/ipsec_if.c | 372 - vnet/vnet/ipsec/ipsec_if_in.c | 175 - vnet/vnet/ipsec/ipsec_if_out.c | 161 - vnet/vnet/ipsec/ipsec_input.c | 455 - vnet/vnet/ipsec/ipsec_output.c | 478 - vnet/vnet/l2/dir.dox | 24 - vnet/vnet/l2/feat_bitmap.c | 185 - vnet/vnet/l2/feat_bitmap.h | 96 - vnet/vnet/l2/l2.api | 38 - vnet/vnet/l2/l2_api.c | 140 - vnet/vnet/l2/l2_bd.c | 1079 -- vnet/vnet/l2/l2_bd.h | 150 - vnet/vnet/l2/l2_bvi.c | 40 - vnet/vnet/l2/l2_bvi.h | 117 - vnet/vnet/l2/l2_classify.h | 116 - vnet/vnet/l2/l2_efp_filter.c | 614 - vnet/vnet/l2/l2_efp_filter.h | 33 - vnet/vnet/l2/l2_fib.c | 857 - vnet/vnet/l2/l2_fib.h | 341 - vnet/vnet/l2/l2_flood.c | 568 - vnet/vnet/l2/l2_flood.h | 35 - vnet/vnet/l2/l2_fwd.c | 544 - vnet/vnet/l2/l2_fwd.h | 36 - vnet/vnet/l2/l2_input.c | 1116 -- vnet/vnet/l2/l2_input.h | 266 - vnet/vnet/l2/l2_input_acl.c | 434 - vnet/vnet/l2/l2_input_classify.c | 655 - vnet/vnet/l2/l2_input_vtr.c | 401 - vnet/vnet/l2/l2_input_vtr.h | 54 - vnet/vnet/l2/l2_learn.c | 597 - vnet/vnet/l2/l2_learn.h | 64 - vnet/vnet/l2/l2_output.c | 708 - vnet/vnet/l2/l2_output.h | 285 - vnet/vnet/l2/l2_output_acl.c | 358 - vnet/vnet/l2/l2_output_classify.c | 657 - vnet/vnet/l2/l2_patch.c | 452 - vnet/vnet/l2/l2_rw.c | 719 - vnet/vnet/l2/l2_rw.h | 95 - vnet/vnet/l2/l2_vtr.c | 770 - vnet/vnet/l2/l2_vtr.h | 270 - vnet/vnet/l2/l2_xcrw.c | 591 - vnet/vnet/l2/l2_xcrw.h | 91 - vnet/vnet/l2tp/decap.c | 309 - vnet/vnet/l2tp/encap.c | 238 - vnet/vnet/l2tp/l2tp.api | 126 - vnet/vnet/l2tp/l2tp.c | 739 - vnet/vnet/l2tp/l2tp.h | 147 - vnet/vnet/l2tp/l2tp_api.c | 267 - vnet/vnet/l2tp/packet.h | 44 - vnet/vnet/l2tp/pg.c | 106 - vnet/vnet/l3_types.h | 59 - vnet/vnet/lawful-intercept/lawful_intercept.c | 112 - vnet/vnet/lawful-intercept/lawful_intercept.h | 45 - vnet/vnet/lawful-intercept/node.c | 275 - vnet/vnet/lisp-cp/control.c | 4950 ----- vnet/vnet/lisp-cp/control.h | 314 - vnet/vnet/lisp-cp/gid_dictionary.c | 865 - vnet/vnet/lisp-cp/gid_dictionary.h | 120 - vnet/vnet/lisp-cp/lisp.api | 835 - vnet/vnet/lisp-cp/lisp_api.c | 1257 -- vnet/vnet/lisp-cp/lisp_cp_dpo.c | 117 - vnet/vnet/lisp-cp/lisp_cp_dpo.h | 45 - vnet/vnet/lisp-cp/lisp_cp_messages.h | 613 - vnet/vnet/lisp-cp/lisp_msg_serdes.c | 372 - vnet/vnet/lisp-cp/lisp_msg_serdes.h | 58 - vnet/vnet/lisp-cp/lisp_types.c | 1574 -- vnet/vnet/lisp-cp/lisp_types.h | 354 - vnet/vnet/lisp-cp/packets.c | 269 - vnet/vnet/lisp-cp/packets.h | 82 - vnet/vnet/lisp-gpe/decap.c | 501 - vnet/vnet/lisp-gpe/dir.dox | 26 - vnet/vnet/lisp-gpe/interface.c | 709 - vnet/vnet/lisp-gpe/lisp_gpe.api | 143 - vnet/vnet/lisp-gpe/lisp_gpe.c | 327 - vnet/vnet/lisp-gpe/lisp_gpe.h | 257 - vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c | 542 - vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h | 136 - vnet/vnet/lisp-gpe/lisp_gpe_api.c | 304 - vnet/vnet/lisp-gpe/lisp_gpe_error.def | 18 - vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 1053 -- vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.h | 188 - vnet/vnet/lisp-gpe/lisp_gpe_packet.h | 149 - vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c | 278 - vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h | 157 - vnet/vnet/lisp-gpe/lisp_gpe_tenant.c | 330 - vnet/vnet/lisp-gpe/lisp_gpe_tenant.h | 88 - vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c | 289 - vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h | 89 - vnet/vnet/lisp-gpe/rfc.txt | 826 - vnet/vnet/llc/llc.c | 241 - vnet/vnet/llc/llc.h | 194 - vnet/vnet/llc/node.c | 331 - vnet/vnet/llc/pg.c | 113 - vnet/vnet/lldp/dir.dox | 18 - vnet/vnet/lldp/lldp_cli.c | 646 - vnet/vnet/lldp/lldp_doc.md | 84 - vnet/vnet/lldp/lldp_input.c | 302 - vnet/vnet/lldp/lldp_node.c | 341 - vnet/vnet/lldp/lldp_node.h | 145 - vnet/vnet/lldp/lldp_output.c | 216 - vnet/vnet/lldp/lldp_protocol.h | 142 - vnet/vnet/map/examples/gen-rules.py | 186 - vnet/vnet/map/examples/health_check.c | 109 - vnet/vnet/map/examples/test_map.py | 141 - vnet/vnet/map/gen-rules.py | 107 - vnet/vnet/map/ip4_map.c | 813 - vnet/vnet/map/ip4_map_t.c | 1363 -- vnet/vnet/map/ip6_map.c | 1269 -- vnet/vnet/map/ip6_map_t.c | 1517 -- vnet/vnet/map/map.api | 178 - vnet/vnet/map/map.c | 2166 --- vnet/vnet/map/map.h | 591 - vnet/vnet/map/map_api.c | 295 - vnet/vnet/map/map_doc.md | 69 - vnet/vnet/map/map_dpo.c | 191 - vnet/vnet/map/map_dpo.h | 67 - vnet/vnet/map/test.c | 205 - vnet/vnet/mcast/mcast.c | 565 - vnet/vnet/mcast/mcast.h | 50 - vnet/vnet/mcast/mcast_test.c | 149 - vnet/vnet/misc.c | 124 - vnet/vnet/mpls/error.def | 31 - vnet/vnet/mpls/interface.c | 121 - vnet/vnet/mpls/mpls.c | 511 - vnet/vnet/mpls/mpls.h | 172 - vnet/vnet/mpls/mpls_features.c | 156 - vnet/vnet/mpls/mpls_lookup.c | 531 - vnet/vnet/mpls/mpls_output.c | 479 - vnet/vnet/mpls/mpls_tunnel.c | 787 - vnet/vnet/mpls/mpls_tunnel.h | 98 - vnet/vnet/mpls/mpls_types.h | 39 - vnet/vnet/mpls/node.c | 303 - vnet/vnet/mpls/packet.h | 125 - vnet/vnet/mpls/pg.c | 71 - vnet/vnet/osi/node.c | 326 - vnet/vnet/osi/osi.c | 201 - vnet/vnet/osi/osi.h | 171 - vnet/vnet/osi/pg.c | 106 - vnet/vnet/pg/cli.c | 636 - vnet/vnet/pg/edit.c | 186 - vnet/vnet/pg/edit.h | 210 - vnet/vnet/pg/example.script | 6 - vnet/vnet/pg/init.c | 72 - vnet/vnet/pg/input.c | 1667 -- vnet/vnet/pg/output.c | 85 - vnet/vnet/pg/pg.h | 383 - vnet/vnet/pg/stream.c | 497 - vnet/vnet/pipeline.h | 456 - vnet/vnet/plugin/p1.c | 52 - vnet/vnet/plugin/plugin.h | 32 - vnet/vnet/policer/node_funcs.c | 938 - vnet/vnet/policer/police.h | 214 - vnet/vnet/policer/policer.c | 528 - vnet/vnet/policer/policer.h | 107 - vnet/vnet/policer/xlate.c | 1505 -- vnet/vnet/policer/xlate.h | 186 - vnet/vnet/ppp/error.def | 42 - vnet/vnet/ppp/node.c | 368 - vnet/vnet/ppp/packet.h | 199 - vnet/vnet/ppp/pg.c | 114 - vnet/vnet/ppp/ppp.c | 261 - vnet/vnet/ppp/ppp.h | 135 - vnet/vnet/replication.c | 293 - vnet/vnet/replication.h | 136 - vnet/vnet/rewrite.c | 329 - vnet/vnet/rewrite.h | 305 - vnet/vnet/snap/node.c | 353 - vnet/vnet/snap/pg.c | 116 - vnet/vnet/snap/snap.c | 204 - vnet/vnet/snap/snap.h | 209 - vnet/vnet/span/node.c | 286 - vnet/vnet/span/span.api | 60 - vnet/vnet/span/span.c | 197 - vnet/vnet/span/span.h | 62 - vnet/vnet/span/span.md | 65 - vnet/vnet/span/span_api.c | 153 - vnet/vnet/sr/dir.dox | 25 - vnet/vnet/sr/examples/sr_multicastmap.script | 4 - vnet/vnet/sr/rfc_draft_05.txt | 1265 -- vnet/vnet/sr/sr.c | 3333 ---- vnet/vnet/sr/sr.h | 262 - vnet/vnet/sr/sr_error.def | 20 - vnet/vnet/sr/sr_fix_dst_error.def | 17 - vnet/vnet/sr/sr_packet.h | 251 - vnet/vnet/sr/sr_replicate.c | 490 - vnet/vnet/srp/format.c | 147 - vnet/vnet/srp/interface.c | 458 - vnet/vnet/srp/node.c | 932 - vnet/vnet/srp/packet.h | 204 - vnet/vnet/srp/pg.c | 157 - vnet/vnet/srp/srp.h | 222 - vnet/vnet/unix/gdb_funcs.c | 171 - vnet/vnet/unix/pcap.c | 241 - vnet/vnet/unix/pcap.h | 230 - vnet/vnet/unix/pcap2pg.c | 182 - vnet/vnet/unix/tap.api | 123 - vnet/vnet/unix/tap_api.c | 257 - vnet/vnet/unix/tapcli.c | 1328 -- vnet/vnet/unix/tapcli.h | 52 - vnet/vnet/unix/tuntap.c | 1000 -- vnet/vnet/unix/tuntap.h | 36 - vnet/vnet/vnet.h | 96 - vnet/vnet/vnet_all_api_h.h | 57 - vnet/vnet/vnet_msg_enum.h | 37 - vnet/vnet/vxlan-gpe/decap.c | 733 - vnet/vnet/vxlan-gpe/dir.dox | 32 - vnet/vnet/vxlan-gpe/encap.c | 388 - vnet/vnet/vxlan-gpe/vxlan-gpe-rfc.txt | 868 - vnet/vnet/vxlan-gpe/vxlan_gpe.api | 61 - vnet/vnet/vxlan-gpe/vxlan_gpe.c | 659 - vnet/vnet/vxlan-gpe/vxlan_gpe.h | 221 - vnet/vnet/vxlan-gpe/vxlan_gpe_api.c | 249 - vnet/vnet/vxlan-gpe/vxlan_gpe_error.def | 16 - vnet/vnet/vxlan-gpe/vxlan_gpe_packet.h | 110 - vnet/vnet/vxlan/decap.c | 1130 -- vnet/vnet/vxlan/dir.dox | 24 - vnet/vnet/vxlan/encap.c | 553 - vnet/vnet/vxlan/vxlan.api | 81 - vnet/vnet/vxlan/vxlan.c | 899 - vnet/vnet/vxlan/vxlan.h | 199 - vnet/vnet/vxlan/vxlan_api.c | 253 - vnet/vnet/vxlan/vxlan_error.def | 17 - vnet/vnet/vxlan/vxlan_packet.h | 69 - vpp-api-test/Makefile.am | 37 - vpp-api-test/configure.ac | 40 - vpp-api-test/scripts/vppctl | 121 - vpp-api-test/vat/api_format.c | 17827 ------------------ vpp-api-test/vat/json_format.c | 304 - vpp-api-test/vat/json_format.h | 254 - vpp-api-test/vat/json_test.c | 75 - vpp-api-test/vat/main.c | 418 - vpp-api-test/vat/plugin.c | 201 - vpp-api-test/vat/plugin.h | 61 - vpp-api-test/vat/plugin_api.c | 216 - vpp-api-test/vat/restart.c | 246 - vpp-api-test/vat/vat.h | 257 - vpp-api/Makefile.am | 4 +- vpp-api/configure.ac | 1 - vpp-api/java/Makefile.am | 3 +- vpp-api/java/jvpp-core/jvpp_core.c | 8 +- vpp-api/java/jvpp-registry/jvpp_registry.c | 10 +- vpp-api/java/jvpp/gen/jvpp_gen.py | 5 + vpp-api/python/Makefile.am | 51 - vpp-api/python/README.rst | 0 vpp-api/python/pneum/pneum.c | 259 - vpp-api/python/pneum/pneum.h | 31 - vpp-api/python/pneum/test_pneum.c | 143 - vpp-api/python/setup.cfg | 5 - vpp-api/python/setup.py | 34 - vpp-api/python/tests/test_cli.py | 52 - vpp-api/python/tests/test_modules.py | 18 - vpp-api/python/tests/test_papi.py | 119 - vpp-api/python/tests/test_version.py | 35 - vpp-api/python/tests/test_vpp_papi2.py | 487 - vpp-api/python/vpp_papi/__init__.py | 3 - vpp-api/python/vpp_papi/pneum_wrap.c | 200 - vpp-api/python/vpp_papi/vpp_papi.py | 450 - vpp/Makefile.am | 166 - vpp/app/l2t.c | 557 - vpp/app/l2t_l2.c | 267 - vpp/app/sticky_hash.c | 581 - vpp/app/version.c | 102 - vpp/app/vpe_cli.c | 123 - vpp/conf/80-vpp.conf | 15 - vpp/conf/startup.conf | 99 - vpp/conf/startup.uiopcigeneric.conf | 18 - vpp/configure.ac | 80 - vpp/oam/oam.c | 648 - vpp/oam/oam.h | 96 - vpp/stats/stats.c | 987 - vpp/stats/stats.h | 76 - vpp/suffix-rules.mk | 1 - vpp/vnet/main.c | 414 - vpp/vpp-api/api.c | 4921 ----- vpp/vpp-api/api_format.c | 1 - vpp/vpp-api/api_main.c | 192 - vpp/vpp-api/custom_dump.c | 3139 ---- vpp/vpp-api/gmon.c | 319 - vpp/vpp-api/json_format.c | 304 - vpp/vpp-api/json_format.h | 254 - vpp/vpp-api/summary_stats_client.c | 302 - vpp/vpp-api/test_client.c | 1531 -- vpp/vpp-api/test_ha.c | 249 - vpp/vpp-api/vat.h | 1 - vpp/vpp-api/vpe.api | 2782 --- vpp/vpp-api/vpe_all_api_h.h | 37 - vpp/vpp-api/vpe_msg_enum.h | 37 - vpp/vpp-api/vpp_get_metrics.c | 253 - vppapigen/Makefile.am | 29 - vppapigen/configure.ac | 14 - vppapigen/gram.y | 90 - vppapigen/lex.c | 1067 -- vppapigen/lex.h | 50 - vppapigen/node.c | 1531 -- vppapigen/node.h | 94 - vppinfra/.gitignore | 1 - vppinfra/INSTALL | 236 - vppinfra/Make.defs | 129 - vppinfra/Makefile.am | 275 - vppinfra/README | 43 - vppinfra/configure.ac | 52 - vppinfra/dir.dox | 19 - vppinfra/mkinstalldirs | 111 - vppinfra/tools/dir.dox | 19 - vppinfra/tools/elftool.c | 464 - vppinfra/unix_error.def | 145 - vppinfra/vppinfra/anneal.c | 172 - vppinfra/vppinfra/anneal.h | 89 - vppinfra/vppinfra/asm_mips.h | 351 - vppinfra/vppinfra/asm_x86.c | 1947 -- vppinfra/vppinfra/asm_x86.h | 125 - vppinfra/vppinfra/backtrace.c | 267 - vppinfra/vppinfra/bihash_24_8.h | 85 - vppinfra/vppinfra/bihash_8_8.h | 98 - vppinfra/vppinfra/bihash_doc.h | 149 - vppinfra/vppinfra/bihash_template.c | 455 - vppinfra/vppinfra/bihash_template.h | 214 - vppinfra/vppinfra/bitmap.h | 774 - vppinfra/vppinfra/bitops.h | 179 - vppinfra/vppinfra/byte_order.h | 202 - vppinfra/vppinfra/cache.h | 104 - vppinfra/vppinfra/clib.h | 359 - vppinfra/vppinfra/cpu.c | 133 - vppinfra/vppinfra/cpu.h | 112 - vppinfra/vppinfra/dir.dox | 19 - vppinfra/vppinfra/dlist.h | 156 - vppinfra/vppinfra/elf.c | 2040 --- vppinfra/vppinfra/elf.h | 1062 -- vppinfra/vppinfra/elf_clib.c | 377 - vppinfra/vppinfra/elf_clib.h | 144 - vppinfra/vppinfra/elog.c | 1061 -- vppinfra/vppinfra/elog.h | 460 - vppinfra/vppinfra/error.c | 292 - vppinfra/vppinfra/error.h | 201 - vppinfra/vppinfra/error_bootstrap.h | 106 - vppinfra/vppinfra/fheap.c | 473 - vppinfra/vppinfra/fheap.h | 140 - vppinfra/vppinfra/fifo.c | 137 - vppinfra/vppinfra/fifo.h | 304 - vppinfra/vppinfra/format.c | 814 - vppinfra/vppinfra/format.h | 331 - vppinfra/vppinfra/graph.c | 182 - vppinfra/vppinfra/graph.h | 127 - vppinfra/vppinfra/hash.c | 1095 -- vppinfra/vppinfra/hash.h | 699 - vppinfra/vppinfra/heap.c | 828 - vppinfra/vppinfra/heap.h | 357 - vppinfra/vppinfra/longjmp.S | 690 - vppinfra/vppinfra/longjmp.h | 124 - vppinfra/vppinfra/macros.c | 266 - vppinfra/vppinfra/macros.h | 54 - vppinfra/vppinfra/math.h | 63 - vppinfra/vppinfra/md5.c | 317 - vppinfra/vppinfra/md5.h | 57 - vppinfra/vppinfra/mem.h | 291 - vppinfra/vppinfra/mem_mheap.c | 165 - vppinfra/vppinfra/memcheck.h | 317 - vppinfra/vppinfra/memcpy_avx.h | 293 - vppinfra/vppinfra/memcpy_sse3.h | 355 - vppinfra/vppinfra/mhash.c | 408 - vppinfra/vppinfra/mhash.h | 179 - vppinfra/vppinfra/mheap.c | 1649 -- vppinfra/vppinfra/mheap.h | 94 - vppinfra/vppinfra/mheap_bootstrap.h | 374 - vppinfra/vppinfra/mod_test_hash.c | 27 - vppinfra/vppinfra/os.h | 72 - vppinfra/vppinfra/pfhash.c | 689 - vppinfra/vppinfra/pfhash.h | 276 - vppinfra/vppinfra/phash.c | 1017 -- vppinfra/vppinfra/phash.h | 194 - vppinfra/vppinfra/pipeline.h | 176 - vppinfra/vppinfra/pool.h | 405 - vppinfra/vppinfra/ptclosure.c | 125 - vppinfra/vppinfra/ptclosure.h | 40 - vppinfra/vppinfra/qhash.c | 858 - vppinfra/vppinfra/qhash.h | 169 - vppinfra/vppinfra/qsort.c | 269 - vppinfra/vppinfra/random.c | 51 - vppinfra/vppinfra/random.h | 178 - vppinfra/vppinfra/random_buffer.c | 86 - vppinfra/vppinfra/random_buffer.h | 118 - vppinfra/vppinfra/random_isaac.c | 434 - vppinfra/vppinfra/random_isaac.h | 81 - vppinfra/vppinfra/serialize.c | 1254 -- vppinfra/vppinfra/serialize.h | 443 - vppinfra/vppinfra/slist.c | 336 - vppinfra/vppinfra/slist.h | 145 - vppinfra/vppinfra/smp.c | 325 - vppinfra/vppinfra/smp.h | 81 - vppinfra/vppinfra/smp_fifo.c | 91 - vppinfra/vppinfra/smp_fifo.h | 313 - vppinfra/vppinfra/socket.c | 422 - vppinfra/vppinfra/socket.h | 160 - vppinfra/vppinfra/sparse_vec.h | 244 - vppinfra/vppinfra/std-formats.c | 330 - vppinfra/vppinfra/string.c | 94 - vppinfra/vppinfra/string.h | 83 - vppinfra/vppinfra/test_bihash_template.c | 297 - vppinfra/vppinfra/test_dlist.c | 193 - vppinfra/vppinfra/test_elf.c | 217 - vppinfra/vppinfra/test_elog.c | 262 - vppinfra/vppinfra/test_fifo.c | 144 - vppinfra/vppinfra/test_format.c | 199 - vppinfra/vppinfra/test_hash.c | 458 - vppinfra/vppinfra/test_heap.c | 198 - vppinfra/vppinfra/test_longjmp.c | 129 - vppinfra/vppinfra/test_macros.c | 64 - vppinfra/vppinfra/test_md5.c | 141 - vppinfra/vppinfra/test_mheap.c | 242 - vppinfra/vppinfra/test_pfhash.c | 322 - vppinfra/vppinfra/test_phash.c | 149 - vppinfra/vppinfra/test_pool.c | 86 - vppinfra/vppinfra/test_pool_iterate.c | 59 - vppinfra/vppinfra/test_ptclosure.c | 212 - vppinfra/vppinfra/test_qhash.c | 333 - vppinfra/vppinfra/test_random.c | 148 - vppinfra/vppinfra/test_random_isaac.c | 142 - vppinfra/vppinfra/test_serialize.c | 274 - vppinfra/vppinfra/test_slist.c | 228 - vppinfra/vppinfra/test_socket.c | 134 - vppinfra/vppinfra/test_time.c | 104 - vppinfra/vppinfra/test_timing_wheel.c | 389 - vppinfra/vppinfra/test_vec.c | 1159 -- vppinfra/vppinfra/test_vec.h | 243 - vppinfra/vppinfra/test_vhash.c | 757 - vppinfra/vppinfra/test_zvec.c | 117 - vppinfra/vppinfra/time.c | 226 - vppinfra/vppinfra/time.h | 298 - vppinfra/vppinfra/timer.c | 322 - vppinfra/vppinfra/timer.h | 46 - vppinfra/vppinfra/timing_wheel.c | 750 - vppinfra/vppinfra/timing_wheel.h | 155 - vppinfra/vppinfra/types.h | 174 - vppinfra/vppinfra/unformat.c | 1077 -- vppinfra/vppinfra/unix-formats.c | 918 - vppinfra/vppinfra/unix-kelog.c | 415 - vppinfra/vppinfra/unix-misc.c | 242 - vppinfra/vppinfra/unix.h | 64 - vppinfra/vppinfra/valgrind.h | 4030 ----- vppinfra/vppinfra/vec.c | 171 - vppinfra/vppinfra/vec.h | 973 - vppinfra/vppinfra/vec_bootstrap.h | 201 - vppinfra/vppinfra/vector.c | 54 - vppinfra/vppinfra/vector.h | 268 - vppinfra/vppinfra/vector_altivec.h | 178 - vppinfra/vppinfra/vector_funcs.h | 334 - vppinfra/vppinfra/vector_iwmmxt.h | 149 - vppinfra/vppinfra/vector_neon.h | 71 - vppinfra/vppinfra/vector_sse2.h | 711 - vppinfra/vppinfra/vhash.c | 772 - vppinfra/vppinfra/vhash.h | 850 - vppinfra/vppinfra/vm_linux_kernel.h | 78 - vppinfra/vppinfra/vm_standalone.h | 74 - vppinfra/vppinfra/vm_unix.h | 106 - vppinfra/vppinfra/xxhash.h | 86 - vppinfra/vppinfra/xy.h | 56 - vppinfra/vppinfra/zvec.c | 442 - vppinfra/vppinfra/zvec.h | 166 - 2038 files changed, 380675 insertions(+), 381455 deletions(-) delete mode 100644 build-data/packages/cavium-dpdk.mk create mode 100644 build-data/packages/src.mk delete mode 100644 build-data/packages/svm.mk delete mode 100644 build-data/packages/vlib-api-cavium-dpdk.mk delete mode 100644 build-data/packages/vlib-api.mk delete mode 100644 build-data/packages/vlib-cavium-dpdk.mk delete mode 100644 build-data/packages/vlib.mk delete mode 100644 build-data/packages/vnet-cavium-dpdk.mk delete mode 100644 build-data/packages/vpp-api-test-cavium-dpdk.mk delete mode 100644 build-data/packages/vpp-api-test.mk delete mode 100644 build-data/packages/vpp-cavium-dpdk.mk delete mode 100644 build-data/packages/vppinfra.mk delete mode 100644 build-data/suffix-rules.mk create mode 100644 build-root/packages/src.mk create mode 100644 build-root/packages/tools.mk delete mode 100644 build-root/packages/vppapigen.mk delete mode 100644 g2/Makefile.am delete mode 100644 g2/clib.c delete mode 100644 g2/configure.ac delete mode 100644 g2/cpel.c delete mode 100644 g2/cpel.h delete mode 100644 g2/events.c delete mode 100644 g2/g2.h delete mode 100644 g2/g2version.c delete mode 100644 g2/main.c delete mode 100644 g2/menu1.c delete mode 100644 g2/mkversion.c delete mode 100644 g2/pointsel.c delete mode 100644 g2/props.c delete mode 100644 g2/props.h delete mode 100644 g2/view1.c delete mode 100644 perftool/Makefile.am delete mode 100644 perftool/c2cpel.c delete mode 100644 perftool/configure.ac delete mode 100644 perftool/cpel.h delete mode 100644 perftool/cpel_util.c delete mode 100644 perftool/cpel_util.h delete mode 100644 perftool/cpelatency.c delete mode 100644 perftool/cpeldump.c delete mode 100644 perftool/cpelinreg.c delete mode 100644 perftool/cpelstate.c delete mode 100644 perftool/delsvec.c delete mode 100644 perftool/linreg.c delete mode 100644 perftool/new.cpel delete mode 100644 perftool/new.elog delete mode 100644 perftool/props.c delete mode 100644 plugins/flowperpkt-plugin/Makefile.am delete mode 100644 plugins/flowperpkt-plugin/configure.ac delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/l2_node.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt/node.c delete mode 100644 plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md delete mode 100644 plugins/ila-plugin/Makefile.am delete mode 100644 plugins/ila-plugin/configure.ac delete mode 100644 plugins/ila-plugin/ila/ila.c delete mode 100644 plugins/ila-plugin/ila/ila.h delete mode 100644 plugins/sixrd-plugin/Makefile.am delete mode 100644 plugins/sixrd-plugin/configure.ac delete mode 100644 plugins/sixrd-plugin/sixrd/ip4_sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/ip6_sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd.h delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd_dpo.c delete mode 100644 plugins/sixrd-plugin/sixrd/sixrd_dpo.h create mode 100644 src/Makefile.am create mode 100644 src/configure.ac create mode 100644 src/examples/vlib/dir.dox create mode 100644 src/examples/vlib/main_stub.c create mode 100644 src/examples/vlib/mc_test.c create mode 100644 src/examples/vlib/plex_test.c create mode 100644 src/g2.am create mode 100644 src/perftool.am create mode 100644 src/plugins/Makefile.am create mode 100644 src/plugins/flowperpkt.am create mode 100644 src/plugins/flowperpkt/flowperpkt.api create mode 100644 src/plugins/flowperpkt/flowperpkt.c create mode 100644 src/plugins/flowperpkt/flowperpkt.h create mode 100644 src/plugins/flowperpkt/flowperpkt_all_api_h.h create mode 100644 src/plugins/flowperpkt/flowperpkt_msg_enum.h create mode 100644 src/plugins/flowperpkt/flowperpkt_plugin_doc.md create mode 100644 src/plugins/flowperpkt/flowperpkt_test.c create mode 100644 src/plugins/flowperpkt/l2_node.c create mode 100644 src/plugins/flowperpkt/node.c create mode 100644 src/plugins/ila.am create mode 100644 src/plugins/ila/ila.c create mode 100644 src/plugins/ila/ila.h create mode 100644 src/plugins/sixrd.am create mode 100644 src/plugins/sixrd/ip4_sixrd.c create mode 100644 src/plugins/sixrd/ip6_sixrd.c create mode 100644 src/plugins/sixrd/sixrd.c create mode 100644 src/plugins/sixrd/sixrd.h create mode 100644 src/plugins/sixrd/sixrd_dpo.c create mode 100644 src/plugins/sixrd/sixrd_dpo.h create mode 100644 src/scripts/vnet/arp4 create mode 100644 src/scripts/vnet/arp4-mpls create mode 100644 src/scripts/vnet/arp6 create mode 100644 src/scripts/vnet/bvi create mode 100644 src/scripts/vnet/dhcp/dhcpd.conf create mode 100644 src/scripts/vnet/dhcp/left-ping-target.sh create mode 100644 src/scripts/vnet/dhcp/leftpeer.conf create mode 100644 src/scripts/vnet/icmp create mode 100644 src/scripts/vnet/icmp6 create mode 100644 src/scripts/vnet/ige create mode 100644 src/scripts/vnet/ip6 create mode 100644 src/scripts/vnet/ip6-hbh create mode 100644 src/scripts/vnet/ixge create mode 100644 src/scripts/vnet/l2efpfilter create mode 100644 src/scripts/vnet/l2efpfilter_perf create mode 100644 src/scripts/vnet/l2fib create mode 100644 src/scripts/vnet/l2fib_perf create mode 100644 src/scripts/vnet/l2fib_xc create mode 100644 src/scripts/vnet/l2flood create mode 100644 src/scripts/vnet/l2tp create mode 100755 src/scripts/vnet/leftpeer/leftpeer-classify create mode 100644 src/scripts/vnet/leftpeer/leftpeer-classify6 create mode 100644 src/scripts/vnet/leftpeer/leftpeer-classifyl2 create mode 100644 src/scripts/vnet/leftpeer/leftpeer-dhcp create mode 100644 src/scripts/vnet/leftpeer/leftpeer-ioam.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-lisp.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-mpls.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-sr.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer-vxlan.conf create mode 100644 src/scripts/vnet/leftpeer/leftpeer.script create mode 100644 src/scripts/vnet/lfib/ip4-to-mpls create mode 100644 src/scripts/vnet/lfib/mpls-pop-to-mpls create mode 100644 src/scripts/vnet/lfib/mpls-to-ip4 create mode 100644 src/scripts/vnet/lfib/mpls-to-mpls create mode 100644 src/scripts/vnet/mpls-o-ethernet/leftpeer.conf create mode 100644 src/scripts/vnet/mpls-o-ethernet/pg create mode 100644 src/scripts/vnet/mpls-o-ethernet/rightpeer.conf create mode 100644 src/scripts/vnet/mpls-o-ethernet/single.conf create mode 100644 src/scripts/vnet/mpls-o-gre/dhcpd.conf create mode 100644 src/scripts/vnet/mpls-o-gre/leftpeer.conf create mode 100644 src/scripts/vnet/mpls-o-gre/rightpeer.conf create mode 100644 src/scripts/vnet/mpls-tunnel create mode 100644 src/scripts/vnet/pcap create mode 100644 src/scripts/vnet/probe4 create mode 100644 src/scripts/vnet/probe6 create mode 100644 src/scripts/vnet/rewrite create mode 100644 src/scripts/vnet/rightpeer/rightpeer-ioam.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-lisp.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-mpls.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-sr.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer-vxlan.conf create mode 100644 src/scripts/vnet/rightpeer/rightpeer.script create mode 100644 src/scripts/vnet/rpf create mode 100644 src/scripts/vnet/rtt-test create mode 100644 src/scripts/vnet/snat create mode 100644 src/scripts/vnet/snat_static create mode 100644 src/scripts/vnet/snat_static_with_port create mode 100644 src/scripts/vnet/source_and_port_range_check create mode 100644 src/scripts/vnet/speed create mode 100755 src/scripts/vnet/sr/left-linux-ping.sh create mode 100644 src/scripts/vnet/sr/leftpeer.conf create mode 100755 src/scripts/vnet/sr/right-linux-ping.sh create mode 100644 src/scripts/vnet/sr/rightpeer.conf create mode 100755 src/scripts/vnet/sr/srlocal.sh create mode 100644 src/scripts/vnet/srp create mode 100644 src/scripts/vnet/tcp create mode 100644 src/scripts/vnet/tcp-test create mode 100644 src/scripts/vnet/tf-ucs-1 create mode 100644 src/scripts/vnet/urpf create mode 100644 src/scripts/vnet/virl/ip6sr.virl create mode 100644 src/scripts/vnet/virl/ip6sr_notes.txt create mode 100644 src/scripts/vnet/virl/mplsogre.virl create mode 100644 src/scripts/vnet/virl/simple.virl create mode 100644 src/scripts/vnet/vlan create mode 100755 src/scripts/vppctl create mode 100644 src/suffix-rules.mk create mode 100644 src/svm.am create mode 100644 src/svm/dir.dox create mode 100644 src/svm/persist.c create mode 100644 src/svm/ssvm.c create mode 100644 src/svm/ssvm.h create mode 100644 src/svm/svm.c create mode 100644 src/svm/svm.h create mode 100644 src/svm/svm_test.c create mode 100644 src/svm/svmdb.c create mode 100644 src/svm/svmdb.h create mode 100644 src/svm/svmdbtool.c create mode 100644 src/svm/svmtool.c create mode 100644 src/tests/vnet/README create mode 100644 src/tests/vnet/lisp-cp/test_cp_serdes.c create mode 100644 src/tests/vnet/lisp-cp/test_lisp_types.c create mode 100644 src/tests/vnet/lisp-gpe/test.c create mode 100644 src/tools/elftool/dir.dox create mode 100644 src/tools/elftool/elftool.c create mode 100644 src/tools/g2/clib.c create mode 100644 src/tools/g2/configure.ac create mode 100644 src/tools/g2/cpel.c create mode 100644 src/tools/g2/cpel.h create mode 100644 src/tools/g2/events.c create mode 100644 src/tools/g2/g2.h create mode 100644 src/tools/g2/g2version.c create mode 100644 src/tools/g2/main.c create mode 100644 src/tools/g2/menu1.c create mode 100644 src/tools/g2/mkversion.c create mode 100644 src/tools/g2/pointsel.c create mode 100644 src/tools/g2/props.c create mode 100644 src/tools/g2/props.h create mode 100644 src/tools/g2/view1.c create mode 100644 src/tools/perftool/c2cpel.c create mode 100644 src/tools/perftool/configure.ac create mode 100644 src/tools/perftool/cpel.h create mode 100644 src/tools/perftool/cpel_util.c create mode 100644 src/tools/perftool/cpel_util.h create mode 100644 src/tools/perftool/cpelatency.c create mode 100644 src/tools/perftool/cpeldump.c create mode 100644 src/tools/perftool/cpelinreg.c create mode 100644 src/tools/perftool/cpelstate.c create mode 100644 src/tools/perftool/delsvec.c create mode 100644 src/tools/perftool/linreg.c create mode 100644 src/tools/perftool/new.cpel create mode 100644 src/tools/perftool/new.elog create mode 100644 src/tools/perftool/props.c create mode 100644 src/tools/vppapigen/configure.ac create mode 100644 src/tools/vppapigen/gram.y create mode 100644 src/tools/vppapigen/lex.c create mode 100644 src/tools/vppapigen/lex.h create mode 100644 src/tools/vppapigen/node.c create mode 100644 src/tools/vppapigen/node.h create mode 100644 src/vat/api_format.c create mode 100644 src/vat/json_format.c create mode 100644 src/vat/json_format.h create mode 100644 src/vat/json_test.c create mode 100644 src/vat/main.c create mode 100644 src/vat/plugin.c create mode 100644 src/vat/plugin.h create mode 100644 src/vat/plugin_api.c create mode 100644 src/vat/restart.c create mode 100644 src/vat/vat.h create mode 100644 src/vlib-api.am create mode 100644 src/vlib.am create mode 100644 src/vlib/buffer.c create mode 100644 src/vlib/buffer.h create mode 100644 src/vlib/buffer_funcs.h create mode 100644 src/vlib/buffer_node.h create mode 100644 src/vlib/cli.c create mode 100644 src/vlib/cli.h create mode 100644 src/vlib/cli_funcs.h create mode 100644 src/vlib/counter.c create mode 100644 src/vlib/counter.h create mode 100644 src/vlib/defs.h create mode 100644 src/vlib/dir.dox create mode 100644 src/vlib/elog_samples.c create mode 100644 src/vlib/error.c create mode 100644 src/vlib/error.h create mode 100644 src/vlib/error_funcs.h create mode 100644 src/vlib/format.c create mode 100644 src/vlib/format_funcs.h create mode 100644 src/vlib/global_funcs.h create mode 100644 src/vlib/i2c.c create mode 100644 src/vlib/i2c.h create mode 100644 src/vlib/init.c create mode 100644 src/vlib/init.h create mode 100644 src/vlib/lex.c create mode 100644 src/vlib/lex.h create mode 100644 src/vlib/main.c create mode 100644 src/vlib/main.h create mode 100644 src/vlib/mc.c create mode 100644 src/vlib/mc.h create mode 100644 src/vlib/node.c create mode 100644 src/vlib/node.h create mode 100644 src/vlib/node_cli.c create mode 100644 src/vlib/node_format.c create mode 100644 src/vlib/node_funcs.h create mode 100644 src/vlib/parse.c create mode 100644 src/vlib/parse.h create mode 100644 src/vlib/parse_builtin.c create mode 100644 src/vlib/pci/linux_pci.c create mode 100644 src/vlib/pci/pci.c create mode 100644 src/vlib/pci/pci.h create mode 100644 src/vlib/pci/pci_config.h create mode 100644 src/vlib/physmem.h create mode 100644 src/vlib/threads.c create mode 100644 src/vlib/threads.h create mode 100644 src/vlib/threads_cli.c create mode 100644 src/vlib/trace.c create mode 100644 src/vlib/trace.h create mode 100644 src/vlib/trace_funcs.h create mode 100644 src/vlib/unix/cj.c create mode 100644 src/vlib/unix/cj.h create mode 100644 src/vlib/unix/cli.c create mode 100644 src/vlib/unix/dir.dox create mode 100644 src/vlib/unix/input.c create mode 100644 src/vlib/unix/main.c create mode 100644 src/vlib/unix/mc_socket.c create mode 100644 src/vlib/unix/mc_socket.h create mode 100644 src/vlib/unix/physmem.c create mode 100644 src/vlib/unix/physmem.h create mode 100644 src/vlib/unix/plugin.c create mode 100644 src/vlib/unix/plugin.h create mode 100644 src/vlib/unix/unix.h create mode 100644 src/vlib/unix/util.c create mode 100644 src/vlib/vlib.h create mode 100644 src/vlib/vlib_process_doc.h create mode 100644 src/vlibapi/api.h create mode 100644 src/vlibapi/api_helper_macros.h create mode 100644 src/vlibapi/api_shared.c create mode 100644 src/vlibapi/node_serialize.c create mode 100644 src/vlibmemory/api.h create mode 100644 src/vlibmemory/memclnt.api create mode 100644 src/vlibmemory/memory_client.c create mode 100644 src/vlibmemory/memory_shared.c create mode 100644 src/vlibmemory/memory_vlib.c create mode 100644 src/vlibmemory/unix_shared_memory_queue.c create mode 100644 src/vlibmemory/unix_shared_memory_queue.h create mode 100644 src/vlibmemory/vl_memory_api_h.h create mode 100644 src/vlibmemory/vl_memory_msg_enum.h create mode 100644 src/vlibsocket/api.h create mode 100644 src/vlibsocket/sock_test.c create mode 100644 src/vlibsocket/sockclnt.api create mode 100644 src/vlibsocket/sockclnt_vlib.c create mode 100644 src/vlibsocket/socksvr_vlib.c create mode 100644 src/vlibsocket/vl_socket_api_h.h create mode 100644 src/vlibsocket/vl_socket_msg_enum.h create mode 100644 src/vnet.am create mode 100644 src/vnet/adj/adj.c create mode 100644 src/vnet/adj/adj.h create mode 100644 src/vnet/adj/adj_glean.c create mode 100644 src/vnet/adj/adj_glean.h create mode 100644 src/vnet/adj/adj_internal.h create mode 100644 src/vnet/adj/adj_l2.c create mode 100644 src/vnet/adj/adj_l2.h create mode 100644 src/vnet/adj/adj_midchain.c create mode 100644 src/vnet/adj/adj_midchain.h create mode 100644 src/vnet/adj/adj_nbr.c create mode 100644 src/vnet/adj/adj_nbr.h create mode 100644 src/vnet/adj/adj_rewrite.c create mode 100644 src/vnet/adj/adj_rewrite.h create mode 100644 src/vnet/adj/adj_types.h create mode 100644 src/vnet/api_errno.h create mode 100644 src/vnet/bfd/bfd.api create mode 100644 src/vnet/bfd/bfd_api.c create mode 100644 src/vnet/bfd/bfd_api.h create mode 100644 src/vnet/bfd/bfd_debug.h create mode 100644 src/vnet/bfd/bfd_doc.md create mode 100644 src/vnet/bfd/bfd_main.c create mode 100644 src/vnet/bfd/bfd_main.h create mode 100644 src/vnet/bfd/bfd_protocol.c create mode 100644 src/vnet/bfd/bfd_protocol.h create mode 100644 src/vnet/bfd/bfd_udp.c create mode 100644 src/vnet/bfd/bfd_udp.h create mode 100644 src/vnet/bfd/dir.dox create mode 100644 src/vnet/buffer.h create mode 100644 src/vnet/cdp/cdp.pg create mode 100644 src/vnet/cdp/cdp_input.c create mode 100644 src/vnet/cdp/cdp_node.c create mode 100644 src/vnet/cdp/cdp_node.h create mode 100644 src/vnet/cdp/cdp_periodic.c create mode 100644 src/vnet/cdp/cdp_protocol.h create mode 100644 src/vnet/classify/README create mode 100644 src/vnet/classify/flow_classify.c create mode 100644 src/vnet/classify/flow_classify.h create mode 100644 src/vnet/classify/flow_classify_node.c create mode 100644 src/vnet/classify/input_acl.c create mode 100644 src/vnet/classify/input_acl.h create mode 100644 src/vnet/classify/ip_classify.c create mode 100644 src/vnet/classify/policer_classify.c create mode 100644 src/vnet/classify/policer_classify.h create mode 100644 src/vnet/classify/vnet_classify.c create mode 100644 src/vnet/classify/vnet_classify.h create mode 100644 src/vnet/config.c create mode 100644 src/vnet/config.h create mode 100644 src/vnet/cop/cop.c create mode 100644 src/vnet/cop/cop.h create mode 100644 src/vnet/cop/ip4_whitelist.c create mode 100644 src/vnet/cop/ip6_whitelist.c create mode 100644 src/vnet/cop/node1.c create mode 100644 src/vnet/devices/af_packet/af_packet.api create mode 100644 src/vnet/devices/af_packet/af_packet.c create mode 100644 src/vnet/devices/af_packet/af_packet.h create mode 100644 src/vnet/devices/af_packet/af_packet_api.c create mode 100644 src/vnet/devices/af_packet/cli.c create mode 100644 src/vnet/devices/af_packet/device.c create mode 100644 src/vnet/devices/af_packet/node.c create mode 100644 src/vnet/devices/devices.c create mode 100644 src/vnet/devices/devices.h create mode 100644 src/vnet/devices/dpdk/cli.c create mode 100644 src/vnet/devices/dpdk/device.c create mode 100644 src/vnet/devices/dpdk/dpdk.h create mode 100644 src/vnet/devices/dpdk/dpdk_priv.h create mode 100644 src/vnet/devices/dpdk/format.c create mode 100644 src/vnet/devices/dpdk/hqos.c create mode 100755 src/vnet/devices/dpdk/init.c create mode 100644 src/vnet/devices/dpdk/ipsec/cli.c create mode 100644 src/vnet/devices/dpdk/ipsec/crypto_node.c create mode 100644 src/vnet/devices/dpdk/ipsec/dir.dox create mode 100644 src/vnet/devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md create mode 100644 src/vnet/devices/dpdk/ipsec/esp.h create mode 100644 src/vnet/devices/dpdk/ipsec/esp_decrypt.c create mode 100644 src/vnet/devices/dpdk/ipsec/esp_encrypt.c create mode 100644 src/vnet/devices/dpdk/ipsec/ipsec.c create mode 100644 src/vnet/devices/dpdk/ipsec/ipsec.h create mode 100644 src/vnet/devices/dpdk/node.c create mode 100644 src/vnet/devices/dpdk/qos_doc.md create mode 100644 src/vnet/devices/netmap/cli.c create mode 100644 src/vnet/devices/netmap/device.c create mode 100644 src/vnet/devices/netmap/net_netmap.h create mode 100644 src/vnet/devices/netmap/netmap.api create mode 100644 src/vnet/devices/netmap/netmap.c create mode 100644 src/vnet/devices/netmap/netmap.h create mode 100644 src/vnet/devices/netmap/netmap_api.c create mode 100644 src/vnet/devices/netmap/node.c create mode 100644 src/vnet/devices/nic/ixge.c create mode 100644 src/vnet/devices/nic/ixge.h create mode 100644 src/vnet/devices/nic/sfp.c create mode 100644 src/vnet/devices/nic/sfp.h create mode 100644 src/vnet/devices/ssvm/node.c create mode 100644 src/vnet/devices/ssvm/ssvm_eth.c create mode 100644 src/vnet/devices/ssvm/ssvm_eth.h create mode 100644 src/vnet/devices/virtio/dir.dox create mode 100644 src/vnet/devices/virtio/vhost-user.c create mode 100644 src/vnet/devices/virtio/vhost-user.h create mode 100644 src/vnet/devices/virtio/vhost_user.api create mode 100644 src/vnet/devices/virtio/vhost_user_api.c create mode 100644 src/vnet/dhcp/client.c create mode 100644 src/vnet/dhcp/client.h create mode 100644 src/vnet/dhcp/packet.h create mode 100644 src/vnet/dhcp/proxy.h create mode 100644 src/vnet/dhcp/proxy_error.def create mode 100644 src/vnet/dhcp/proxy_node.c create mode 100644 src/vnet/dhcpv6/packet.h create mode 100644 src/vnet/dhcpv6/proxy.h create mode 100644 src/vnet/dhcpv6/proxy_error.def create mode 100644 src/vnet/dhcpv6/proxy_node.c create mode 100644 src/vnet/dpo/classify_dpo.c create mode 100644 src/vnet/dpo/classify_dpo.h create mode 100644 src/vnet/dpo/dpo.c create mode 100644 src/vnet/dpo/dpo.h create mode 100644 src/vnet/dpo/drop_dpo.c create mode 100644 src/vnet/dpo/drop_dpo.h create mode 100644 src/vnet/dpo/ip_null_dpo.c create mode 100644 src/vnet/dpo/ip_null_dpo.h create mode 100644 src/vnet/dpo/load_balance.c create mode 100644 src/vnet/dpo/load_balance.h create mode 100644 src/vnet/dpo/load_balance_map.c create mode 100644 src/vnet/dpo/load_balance_map.h create mode 100644 src/vnet/dpo/lookup_dpo.c create mode 100644 src/vnet/dpo/lookup_dpo.h create mode 100644 src/vnet/dpo/mpls_label_dpo.c create mode 100644 src/vnet/dpo/mpls_label_dpo.h create mode 100644 src/vnet/dpo/punt_dpo.c create mode 100644 src/vnet/dpo/punt_dpo.h create mode 100644 src/vnet/dpo/receive_dpo.c create mode 100644 src/vnet/dpo/receive_dpo.h create mode 100644 src/vnet/ethernet/arp.c create mode 100644 src/vnet/ethernet/arp_packet.h create mode 100644 src/vnet/ethernet/dir.dox create mode 100644 src/vnet/ethernet/error.def create mode 100644 src/vnet/ethernet/ethernet.h create mode 100644 src/vnet/ethernet/format.c create mode 100644 src/vnet/ethernet/init.c create mode 100644 src/vnet/ethernet/interface.c create mode 100644 src/vnet/ethernet/mac_swap.c create mode 100755 src/vnet/ethernet/node.c create mode 100644 src/vnet/ethernet/packet.h create mode 100644 src/vnet/ethernet/pg.c create mode 100644 src/vnet/ethernet/types.def create mode 100644 src/vnet/feature/feature.c create mode 100644 src/vnet/feature/feature.h create mode 100644 src/vnet/feature/registration.c create mode 100644 src/vnet/fib/fib.c create mode 100644 src/vnet/fib/fib.h create mode 100644 src/vnet/fib/fib_api.h create mode 100644 src/vnet/fib/fib_attached_export.c create mode 100644 src/vnet/fib/fib_attached_export.h create mode 100644 src/vnet/fib/fib_entry.c create mode 100644 src/vnet/fib/fib_entry.h create mode 100644 src/vnet/fib/fib_entry_cover.c create mode 100644 src/vnet/fib/fib_entry_cover.h create mode 100644 src/vnet/fib/fib_entry_delegate.c create mode 100644 src/vnet/fib/fib_entry_delegate.h create mode 100644 src/vnet/fib/fib_entry_src.c create mode 100644 src/vnet/fib/fib_entry_src.h create mode 100644 src/vnet/fib/fib_entry_src_adj.c create mode 100644 src/vnet/fib/fib_entry_src_api.c create mode 100644 src/vnet/fib/fib_entry_src_default.c create mode 100644 src/vnet/fib/fib_entry_src_default_route.c create mode 100644 src/vnet/fib/fib_entry_src_interface.c create mode 100644 src/vnet/fib/fib_entry_src_lisp.c create mode 100644 src/vnet/fib/fib_entry_src_mpls.c create mode 100644 src/vnet/fib/fib_entry_src_rr.c create mode 100644 src/vnet/fib/fib_entry_src_special.c create mode 100644 src/vnet/fib/fib_internal.h create mode 100644 src/vnet/fib/fib_node.c create mode 100644 src/vnet/fib/fib_node.h create mode 100644 src/vnet/fib/fib_node_list.c create mode 100644 src/vnet/fib/fib_node_list.h create mode 100644 src/vnet/fib/fib_path.c create mode 100644 src/vnet/fib/fib_path.h create mode 100644 src/vnet/fib/fib_path_ext.c create mode 100644 src/vnet/fib/fib_path_ext.h create mode 100644 src/vnet/fib/fib_path_list.c create mode 100644 src/vnet/fib/fib_path_list.h create mode 100644 src/vnet/fib/fib_table.c create mode 100644 src/vnet/fib/fib_table.h create mode 100644 src/vnet/fib/fib_test.c create mode 100644 src/vnet/fib/fib_types.c create mode 100644 src/vnet/fib/fib_types.h create mode 100644 src/vnet/fib/fib_urpf_list.c create mode 100644 src/vnet/fib/fib_urpf_list.h create mode 100644 src/vnet/fib/fib_walk.c create mode 100644 src/vnet/fib/fib_walk.h create mode 100644 src/vnet/fib/ip4_fib.c create mode 100644 src/vnet/fib/ip4_fib.h create mode 100644 src/vnet/fib/ip6_fib.c create mode 100644 src/vnet/fib/ip6_fib.h create mode 100644 src/vnet/fib/mpls_fib.c create mode 100644 src/vnet/fib/mpls_fib.h create mode 100644 src/vnet/flow/flow_report.c create mode 100644 src/vnet/flow/flow_report.h create mode 100644 src/vnet/flow/flow_report_classify.c create mode 100644 src/vnet/flow/flow_report_classify.h create mode 100644 src/vnet/flow/ipfix_info_elements.h create mode 100644 src/vnet/flow/ipfix_packet.h create mode 100644 src/vnet/global_funcs.h create mode 100644 src/vnet/gre/error.def create mode 100644 src/vnet/gre/gre.api create mode 100644 src/vnet/gre/gre.c create mode 100644 src/vnet/gre/gre.h create mode 100644 src/vnet/gre/gre_api.c create mode 100644 src/vnet/gre/interface.c create mode 100644 src/vnet/gre/node.c create mode 100644 src/vnet/gre/packet.h create mode 100644 src/vnet/gre/pg.c create mode 100644 src/vnet/handoff.c create mode 100644 src/vnet/handoff.h create mode 100644 src/vnet/hdlc/error.def create mode 100644 src/vnet/hdlc/hdlc.c create mode 100644 src/vnet/hdlc/hdlc.h create mode 100644 src/vnet/hdlc/node.c create mode 100644 src/vnet/hdlc/packet.h create mode 100644 src/vnet/hdlc/pg.c create mode 100644 src/vnet/interface.api create mode 100644 src/vnet/interface.c create mode 100644 src/vnet/interface.h create mode 100644 src/vnet/interface_api.c create mode 100644 src/vnet/interface_cli.c create mode 100644 src/vnet/interface_format.c create mode 100644 src/vnet/interface_funcs.h create mode 100644 src/vnet/interface_output.c create mode 100644 src/vnet/ip/dir.dox create mode 100644 src/vnet/ip/format.c create mode 100644 src/vnet/ip/format.h create mode 100644 src/vnet/ip/icmp4.c create mode 100644 src/vnet/ip/icmp4.h create mode 100644 src/vnet/ip/icmp46_packet.h create mode 100644 src/vnet/ip/icmp6.c create mode 100644 src/vnet/ip/icmp6.h create mode 100644 src/vnet/ip/igmp_packet.h create mode 100644 src/vnet/ip/ip.api create mode 100644 src/vnet/ip/ip.h create mode 100644 src/vnet/ip/ip4.h create mode 100644 src/vnet/ip/ip46_cli.c create mode 100644 src/vnet/ip/ip4_error.h create mode 100644 src/vnet/ip/ip4_format.c create mode 100644 src/vnet/ip/ip4_forward.c create mode 100644 src/vnet/ip/ip4_input.c create mode 100644 src/vnet/ip/ip4_mtrie.c create mode 100644 src/vnet/ip/ip4_mtrie.h create mode 100644 src/vnet/ip/ip4_packet.h create mode 100644 src/vnet/ip/ip4_pg.c create mode 100644 src/vnet/ip/ip4_source_and_port_range_check.c create mode 100644 src/vnet/ip/ip4_source_check.c create mode 100644 src/vnet/ip/ip4_test.c create mode 100644 src/vnet/ip/ip6.h create mode 100644 src/vnet/ip/ip6_error.h create mode 100644 src/vnet/ip/ip6_format.c create mode 100644 src/vnet/ip/ip6_forward.c create mode 100644 src/vnet/ip/ip6_hop_by_hop.c create mode 100644 src/vnet/ip/ip6_hop_by_hop.h create mode 100644 src/vnet/ip/ip6_hop_by_hop_packet.h create mode 100644 src/vnet/ip/ip6_input.c create mode 100644 src/vnet/ip/ip6_neighbor.c create mode 100644 src/vnet/ip/ip6_neighbor.h create mode 100644 src/vnet/ip/ip6_packet.h create mode 100644 src/vnet/ip/ip6_pg.c create mode 100644 src/vnet/ip/ip_api.c create mode 100644 src/vnet/ip/ip_checksum.c create mode 100644 src/vnet/ip/ip_frag.c create mode 100644 src/vnet/ip/ip_frag.h create mode 100644 src/vnet/ip/ip_init.c create mode 100644 src/vnet/ip/ip_input_acl.c create mode 100644 src/vnet/ip/ip_packet.h create mode 100644 src/vnet/ip/ip_source_and_port_range_check.h create mode 100644 src/vnet/ip/lookup.c create mode 100644 src/vnet/ip/lookup.h create mode 100644 src/vnet/ip/ping.c create mode 100644 src/vnet/ip/ping.h create mode 100644 src/vnet/ip/ports.def create mode 100644 src/vnet/ip/protocols.def create mode 100644 src/vnet/ip/punt.c create mode 100644 src/vnet/ip/punt.h create mode 100644 src/vnet/ip/punt_error.def create mode 100644 src/vnet/ip/tcp_packet.h create mode 100644 src/vnet/ip/udp.h create mode 100644 src/vnet/ip/udp_error.def create mode 100644 src/vnet/ip/udp_format.c create mode 100644 src/vnet/ip/udp_init.c create mode 100644 src/vnet/ip/udp_local.c create mode 100644 src/vnet/ip/udp_packet.h create mode 100644 src/vnet/ip/udp_pg.c create mode 100644 src/vnet/ipsec-gre/dir.dox create mode 100644 src/vnet/ipsec-gre/error.def create mode 100644 src/vnet/ipsec-gre/interface.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre.api create mode 100644 src/vnet/ipsec-gre/ipsec_gre.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre.h create mode 100644 src/vnet/ipsec-gre/ipsec_gre_api.c create mode 100644 src/vnet/ipsec-gre/ipsec_gre_doc.md create mode 100644 src/vnet/ipsec-gre/node.c create mode 100644 src/vnet/ipsec/esp.h create mode 100644 src/vnet/ipsec/esp_decrypt.c create mode 100644 src/vnet/ipsec/esp_encrypt.c create mode 100644 src/vnet/ipsec/ikev2.c create mode 100644 src/vnet/ipsec/ikev2.h create mode 100644 src/vnet/ipsec/ikev2_cli.c create mode 100644 src/vnet/ipsec/ikev2_crypto.c create mode 100644 src/vnet/ipsec/ikev2_format.c create mode 100644 src/vnet/ipsec/ikev2_payload.c create mode 100644 src/vnet/ipsec/ikev2_priv.h create mode 100644 src/vnet/ipsec/ipsec.api create mode 100644 src/vnet/ipsec/ipsec.c create mode 100644 src/vnet/ipsec/ipsec.h create mode 100644 src/vnet/ipsec/ipsec_api.c create mode 100644 src/vnet/ipsec/ipsec_cli.c create mode 100644 src/vnet/ipsec/ipsec_format.c create mode 100644 src/vnet/ipsec/ipsec_if.c create mode 100644 src/vnet/ipsec/ipsec_if_in.c create mode 100644 src/vnet/ipsec/ipsec_if_out.c create mode 100644 src/vnet/ipsec/ipsec_input.c create mode 100644 src/vnet/ipsec/ipsec_output.c create mode 100644 src/vnet/l2/dir.dox create mode 100644 src/vnet/l2/feat_bitmap.c create mode 100644 src/vnet/l2/feat_bitmap.h create mode 100644 src/vnet/l2/l2.api create mode 100644 src/vnet/l2/l2_api.c create mode 100644 src/vnet/l2/l2_bd.c create mode 100644 src/vnet/l2/l2_bd.h create mode 100644 src/vnet/l2/l2_bvi.c create mode 100644 src/vnet/l2/l2_bvi.h create mode 100644 src/vnet/l2/l2_classify.h create mode 100644 src/vnet/l2/l2_efp_filter.c create mode 100644 src/vnet/l2/l2_efp_filter.h create mode 100644 src/vnet/l2/l2_fib.c create mode 100644 src/vnet/l2/l2_fib.h create mode 100644 src/vnet/l2/l2_flood.c create mode 100644 src/vnet/l2/l2_flood.h create mode 100644 src/vnet/l2/l2_fwd.c create mode 100644 src/vnet/l2/l2_fwd.h create mode 100644 src/vnet/l2/l2_input.c create mode 100644 src/vnet/l2/l2_input.h create mode 100644 src/vnet/l2/l2_input_acl.c create mode 100644 src/vnet/l2/l2_input_classify.c create mode 100644 src/vnet/l2/l2_input_vtr.c create mode 100644 src/vnet/l2/l2_input_vtr.h create mode 100644 src/vnet/l2/l2_learn.c create mode 100644 src/vnet/l2/l2_learn.h create mode 100644 src/vnet/l2/l2_output.c create mode 100644 src/vnet/l2/l2_output.h create mode 100644 src/vnet/l2/l2_output_acl.c create mode 100644 src/vnet/l2/l2_output_classify.c create mode 100644 src/vnet/l2/l2_patch.c create mode 100644 src/vnet/l2/l2_rw.c create mode 100644 src/vnet/l2/l2_rw.h create mode 100644 src/vnet/l2/l2_vtr.c create mode 100644 src/vnet/l2/l2_vtr.h create mode 100644 src/vnet/l2/l2_xcrw.c create mode 100644 src/vnet/l2/l2_xcrw.h create mode 100644 src/vnet/l2tp/decap.c create mode 100644 src/vnet/l2tp/encap.c create mode 100644 src/vnet/l2tp/l2tp.api create mode 100644 src/vnet/l2tp/l2tp.c create mode 100644 src/vnet/l2tp/l2tp.h create mode 100644 src/vnet/l2tp/l2tp_api.c create mode 100644 src/vnet/l2tp/packet.h create mode 100644 src/vnet/l2tp/pg.c create mode 100644 src/vnet/l3_types.h create mode 100644 src/vnet/lawful-intercept/lawful_intercept.c create mode 100644 src/vnet/lawful-intercept/lawful_intercept.h create mode 100644 src/vnet/lawful-intercept/node.c create mode 100644 src/vnet/lisp-cp/control.c create mode 100644 src/vnet/lisp-cp/control.h create mode 100644 src/vnet/lisp-cp/gid_dictionary.c create mode 100644 src/vnet/lisp-cp/gid_dictionary.h create mode 100644 src/vnet/lisp-cp/lisp.api create mode 100644 src/vnet/lisp-cp/lisp_api.c create mode 100644 src/vnet/lisp-cp/lisp_cp_dpo.c create mode 100644 src/vnet/lisp-cp/lisp_cp_dpo.h create mode 100644 src/vnet/lisp-cp/lisp_cp_messages.h create mode 100644 src/vnet/lisp-cp/lisp_msg_serdes.c create mode 100644 src/vnet/lisp-cp/lisp_msg_serdes.h create mode 100644 src/vnet/lisp-cp/lisp_types.c create mode 100644 src/vnet/lisp-cp/lisp_types.h create mode 100644 src/vnet/lisp-cp/packets.c create mode 100644 src/vnet/lisp-cp/packets.h create mode 100644 src/vnet/lisp-gpe/decap.c create mode 100644 src/vnet/lisp-gpe/dir.dox create mode 100644 src/vnet/lisp-gpe/interface.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe.api create mode 100644 src/vnet/lisp-gpe/lisp_gpe.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_adjacency.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_adjacency.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_api.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_error.def create mode 100644 src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_packet.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_sub_interface.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_sub_interface.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tenant.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tenant.h create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tunnel.c create mode 100644 src/vnet/lisp-gpe/lisp_gpe_tunnel.h create mode 100644 src/vnet/lisp-gpe/rfc.txt create mode 100644 src/vnet/llc/llc.c create mode 100644 src/vnet/llc/llc.h create mode 100644 src/vnet/llc/node.c create mode 100644 src/vnet/llc/pg.c create mode 100644 src/vnet/lldp/dir.dox create mode 100644 src/vnet/lldp/lldp_cli.c create mode 100644 src/vnet/lldp/lldp_doc.md create mode 100644 src/vnet/lldp/lldp_input.c create mode 100644 src/vnet/lldp/lldp_node.c create mode 100644 src/vnet/lldp/lldp_node.h create mode 100644 src/vnet/lldp/lldp_output.c create mode 100644 src/vnet/lldp/lldp_protocol.h create mode 100755 src/vnet/map/examples/gen-rules.py create mode 100644 src/vnet/map/examples/health_check.c create mode 100755 src/vnet/map/examples/test_map.py create mode 100755 src/vnet/map/gen-rules.py create mode 100644 src/vnet/map/ip4_map.c create mode 100644 src/vnet/map/ip4_map_t.c create mode 100644 src/vnet/map/ip6_map.c create mode 100644 src/vnet/map/ip6_map_t.c create mode 100644 src/vnet/map/map.api create mode 100644 src/vnet/map/map.c create mode 100644 src/vnet/map/map.h create mode 100644 src/vnet/map/map_api.c create mode 100644 src/vnet/map/map_doc.md create mode 100644 src/vnet/map/map_dpo.c create mode 100644 src/vnet/map/map_dpo.h create mode 100644 src/vnet/map/test.c create mode 100644 src/vnet/mcast/mcast.c create mode 100644 src/vnet/mcast/mcast.h create mode 100644 src/vnet/mcast/mcast_test.c create mode 100644 src/vnet/misc.c create mode 100644 src/vnet/mpls/error.def create mode 100644 src/vnet/mpls/interface.c create mode 100644 src/vnet/mpls/mpls.c create mode 100644 src/vnet/mpls/mpls.h create mode 100644 src/vnet/mpls/mpls_features.c create mode 100644 src/vnet/mpls/mpls_lookup.c create mode 100644 src/vnet/mpls/mpls_output.c create mode 100644 src/vnet/mpls/mpls_tunnel.c create mode 100644 src/vnet/mpls/mpls_tunnel.h create mode 100644 src/vnet/mpls/mpls_types.h create mode 100644 src/vnet/mpls/node.c create mode 100644 src/vnet/mpls/packet.h create mode 100644 src/vnet/mpls/pg.c create mode 100644 src/vnet/osi/node.c create mode 100644 src/vnet/osi/osi.c create mode 100644 src/vnet/osi/osi.h create mode 100644 src/vnet/osi/pg.c create mode 100644 src/vnet/pg/cli.c create mode 100644 src/vnet/pg/edit.c create mode 100644 src/vnet/pg/edit.h create mode 100644 src/vnet/pg/example.script create mode 100644 src/vnet/pg/init.c create mode 100644 src/vnet/pg/input.c create mode 100644 src/vnet/pg/output.c create mode 100644 src/vnet/pg/pg.h create mode 100644 src/vnet/pg/stream.c create mode 100644 src/vnet/pipeline.h create mode 100644 src/vnet/plugin/p1.c create mode 100644 src/vnet/plugin/plugin.h create mode 100644 src/vnet/policer/node_funcs.c create mode 100644 src/vnet/policer/police.h create mode 100644 src/vnet/policer/policer.c create mode 100644 src/vnet/policer/policer.h create mode 100644 src/vnet/policer/xlate.c create mode 100644 src/vnet/policer/xlate.h create mode 100644 src/vnet/ppp/error.def create mode 100644 src/vnet/ppp/node.c create mode 100644 src/vnet/ppp/packet.h create mode 100644 src/vnet/ppp/pg.c create mode 100644 src/vnet/ppp/ppp.c create mode 100644 src/vnet/ppp/ppp.h create mode 100644 src/vnet/replication.c create mode 100644 src/vnet/replication.h create mode 100644 src/vnet/rewrite.c create mode 100644 src/vnet/rewrite.h create mode 100644 src/vnet/snap/node.c create mode 100644 src/vnet/snap/pg.c create mode 100644 src/vnet/snap/snap.c create mode 100644 src/vnet/snap/snap.h create mode 100644 src/vnet/span/node.c create mode 100644 src/vnet/span/span.api create mode 100644 src/vnet/span/span.c create mode 100644 src/vnet/span/span.h create mode 100644 src/vnet/span/span.md create mode 100644 src/vnet/span/span_api.c create mode 100644 src/vnet/sr/dir.dox create mode 100644 src/vnet/sr/examples/sr_multicastmap.script create mode 100644 src/vnet/sr/rfc_draft_05.txt create mode 100644 src/vnet/sr/sr.c create mode 100644 src/vnet/sr/sr.h create mode 100644 src/vnet/sr/sr_error.def create mode 100644 src/vnet/sr/sr_fix_dst_error.def create mode 100644 src/vnet/sr/sr_packet.h create mode 100644 src/vnet/sr/sr_replicate.c create mode 100644 src/vnet/srp/format.c create mode 100644 src/vnet/srp/interface.c create mode 100644 src/vnet/srp/node.c create mode 100644 src/vnet/srp/packet.h create mode 100644 src/vnet/srp/pg.c create mode 100644 src/vnet/srp/srp.h create mode 100644 src/vnet/unix/gdb_funcs.c create mode 100644 src/vnet/unix/pcap.c create mode 100644 src/vnet/unix/pcap.h create mode 100644 src/vnet/unix/pcap2pg.c create mode 100644 src/vnet/unix/tap.api create mode 100644 src/vnet/unix/tap_api.c create mode 100644 src/vnet/unix/tapcli.c create mode 100644 src/vnet/unix/tapcli.h create mode 100644 src/vnet/unix/tuntap.c create mode 100644 src/vnet/unix/tuntap.h create mode 100644 src/vnet/vnet.h create mode 100644 src/vnet/vnet_all_api_h.h create mode 100644 src/vnet/vnet_msg_enum.h create mode 100644 src/vnet/vxlan-gpe/decap.c create mode 100644 src/vnet/vxlan-gpe/dir.dox create mode 100644 src/vnet/vxlan-gpe/encap.c create mode 100644 src/vnet/vxlan-gpe/vxlan-gpe-rfc.txt create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.api create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.c create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe.h create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_api.c create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_error.def create mode 100644 src/vnet/vxlan-gpe/vxlan_gpe_packet.h create mode 100644 src/vnet/vxlan/decap.c create mode 100644 src/vnet/vxlan/dir.dox create mode 100644 src/vnet/vxlan/encap.c create mode 100644 src/vnet/vxlan/vxlan.api create mode 100644 src/vnet/vxlan/vxlan.c create mode 100644 src/vnet/vxlan/vxlan.h create mode 100644 src/vnet/vxlan/vxlan_api.c create mode 100644 src/vnet/vxlan/vxlan_error.def create mode 100644 src/vnet/vxlan/vxlan_packet.h create mode 100644 src/vpp-api-test.am create mode 100644 src/vpp-api/python/Makefile.am create mode 100644 src/vpp-api/python/README.rst create mode 100644 src/vpp-api/python/pneum/pneum.c create mode 100644 src/vpp-api/python/pneum/pneum.h create mode 100644 src/vpp-api/python/pneum/test_pneum.c create mode 100644 src/vpp-api/python/setup.cfg create mode 100644 src/vpp-api/python/setup.py create mode 100755 src/vpp-api/python/tests/test_cli.py create mode 100755 src/vpp-api/python/tests/test_modules.py create mode 100755 src/vpp-api/python/tests/test_papi.py create mode 100755 src/vpp-api/python/tests/test_version.py create mode 100755 src/vpp-api/python/tests/test_vpp_papi2.py create mode 100644 src/vpp-api/python/vpp_papi/__init__.py create mode 100644 src/vpp-api/python/vpp_papi/pneum_wrap.c create mode 100644 src/vpp-api/python/vpp_papi/vpp_papi.py create mode 100644 src/vpp.am create mode 100644 src/vpp/api/api.c create mode 120000 src/vpp/api/api_format.c create mode 100644 src/vpp/api/api_main.c create mode 100644 src/vpp/api/custom_dump.c create mode 100644 src/vpp/api/gmon.c create mode 100644 src/vpp/api/json_format.c create mode 100644 src/vpp/api/json_format.h create mode 100644 src/vpp/api/summary_stats_client.c create mode 100644 src/vpp/api/test_client.c create mode 100644 src/vpp/api/test_ha.c create mode 120000 src/vpp/api/vat.h create mode 100644 src/vpp/api/vpe.api create mode 100644 src/vpp/api/vpe_all_api_h.h create mode 100644 src/vpp/api/vpe_msg_enum.h create mode 100644 src/vpp/api/vpp_get_metrics.c create mode 100644 src/vpp/app/l2t.c create mode 100644 src/vpp/app/l2t_l2.c create mode 100644 src/vpp/app/sticky_hash.c create mode 100644 src/vpp/app/version.c create mode 100644 src/vpp/app/vpe_cli.c create mode 100644 src/vpp/conf/80-vpp.conf create mode 100644 src/vpp/conf/startup.conf create mode 100644 src/vpp/conf/startup.uiopcigeneric.conf create mode 100644 src/vpp/oam/oam.c create mode 100644 src/vpp/oam/oam.h create mode 100644 src/vpp/stats/stats.c create mode 100644 src/vpp/stats/stats.h create mode 100644 src/vpp/vnet/main.c create mode 100644 src/vppapigen.am create mode 100644 src/vppinfra.am create mode 100644 src/vppinfra/README create mode 100644 src/vppinfra/anneal.c create mode 100644 src/vppinfra/anneal.h create mode 100644 src/vppinfra/asm_mips.h create mode 100644 src/vppinfra/asm_x86.c create mode 100644 src/vppinfra/asm_x86.h create mode 100644 src/vppinfra/backtrace.c create mode 100644 src/vppinfra/bihash_24_8.h create mode 100644 src/vppinfra/bihash_8_8.h create mode 100644 src/vppinfra/bihash_doc.h create mode 100644 src/vppinfra/bihash_template.c create mode 100644 src/vppinfra/bihash_template.h create mode 100644 src/vppinfra/bitmap.h create mode 100644 src/vppinfra/bitops.h create mode 100644 src/vppinfra/byte_order.h create mode 100644 src/vppinfra/cache.h create mode 100644 src/vppinfra/clib.h create mode 100644 src/vppinfra/cpu.c create mode 100644 src/vppinfra/cpu.h create mode 100644 src/vppinfra/dir.dox create mode 100644 src/vppinfra/dlist.h create mode 100644 src/vppinfra/elf.c create mode 100644 src/vppinfra/elf.h create mode 100644 src/vppinfra/elf_clib.c create mode 100644 src/vppinfra/elf_clib.h create mode 100644 src/vppinfra/elog.c create mode 100644 src/vppinfra/elog.h create mode 100644 src/vppinfra/error.c create mode 100644 src/vppinfra/error.h create mode 100644 src/vppinfra/error_bootstrap.h create mode 100644 src/vppinfra/fheap.c create mode 100644 src/vppinfra/fheap.h create mode 100644 src/vppinfra/fifo.c create mode 100644 src/vppinfra/fifo.h create mode 100644 src/vppinfra/format.c create mode 100644 src/vppinfra/format.h create mode 100644 src/vppinfra/graph.c create mode 100644 src/vppinfra/graph.h create mode 100644 src/vppinfra/hash.c create mode 100644 src/vppinfra/hash.h create mode 100644 src/vppinfra/heap.c create mode 100644 src/vppinfra/heap.h create mode 100644 src/vppinfra/longjmp.S create mode 100644 src/vppinfra/longjmp.h create mode 100644 src/vppinfra/macros.c create mode 100644 src/vppinfra/macros.h create mode 100644 src/vppinfra/math.h create mode 100644 src/vppinfra/md5.c create mode 100644 src/vppinfra/md5.h create mode 100644 src/vppinfra/mem.h create mode 100644 src/vppinfra/mem_mheap.c create mode 100644 src/vppinfra/memcheck.h create mode 100644 src/vppinfra/memcpy_avx.h create mode 100644 src/vppinfra/memcpy_sse3.h create mode 100644 src/vppinfra/mhash.c create mode 100644 src/vppinfra/mhash.h create mode 100644 src/vppinfra/mheap.c create mode 100644 src/vppinfra/mheap.h create mode 100644 src/vppinfra/mheap_bootstrap.h create mode 100644 src/vppinfra/mod_test_hash.c create mode 100644 src/vppinfra/os.h create mode 100644 src/vppinfra/pfhash.c create mode 100644 src/vppinfra/pfhash.h create mode 100644 src/vppinfra/phash.c create mode 100644 src/vppinfra/phash.h create mode 100644 src/vppinfra/pipeline.h create mode 100644 src/vppinfra/pool.h create mode 100644 src/vppinfra/ptclosure.c create mode 100644 src/vppinfra/ptclosure.h create mode 100644 src/vppinfra/qhash.c create mode 100644 src/vppinfra/qhash.h create mode 100644 src/vppinfra/qsort.c create mode 100644 src/vppinfra/random.c create mode 100644 src/vppinfra/random.h create mode 100644 src/vppinfra/random_buffer.c create mode 100644 src/vppinfra/random_buffer.h create mode 100644 src/vppinfra/random_isaac.c create mode 100644 src/vppinfra/random_isaac.h create mode 100644 src/vppinfra/serialize.c create mode 100644 src/vppinfra/serialize.h create mode 100644 src/vppinfra/slist.c create mode 100644 src/vppinfra/slist.h create mode 100644 src/vppinfra/smp.c create mode 100644 src/vppinfra/smp.h create mode 100644 src/vppinfra/smp_fifo.c create mode 100644 src/vppinfra/smp_fifo.h create mode 100644 src/vppinfra/socket.c create mode 100644 src/vppinfra/socket.h create mode 100644 src/vppinfra/sparse_vec.h create mode 100644 src/vppinfra/std-formats.c create mode 100644 src/vppinfra/string.c create mode 100644 src/vppinfra/string.h create mode 100644 src/vppinfra/test_bihash_template.c create mode 100644 src/vppinfra/test_dlist.c create mode 100644 src/vppinfra/test_elf.c create mode 100644 src/vppinfra/test_elog.c create mode 100644 src/vppinfra/test_fifo.c create mode 100644 src/vppinfra/test_format.c create mode 100644 src/vppinfra/test_hash.c create mode 100644 src/vppinfra/test_heap.c create mode 100644 src/vppinfra/test_longjmp.c create mode 100644 src/vppinfra/test_macros.c create mode 100644 src/vppinfra/test_md5.c create mode 100644 src/vppinfra/test_mheap.c create mode 100644 src/vppinfra/test_pfhash.c create mode 100644 src/vppinfra/test_phash.c create mode 100644 src/vppinfra/test_pool.c create mode 100644 src/vppinfra/test_pool_iterate.c create mode 100644 src/vppinfra/test_ptclosure.c create mode 100644 src/vppinfra/test_qhash.c create mode 100644 src/vppinfra/test_random.c create mode 100644 src/vppinfra/test_random_isaac.c create mode 100644 src/vppinfra/test_serialize.c create mode 100644 src/vppinfra/test_slist.c create mode 100644 src/vppinfra/test_socket.c create mode 100644 src/vppinfra/test_time.c create mode 100644 src/vppinfra/test_timing_wheel.c create mode 100644 src/vppinfra/test_vec.c create mode 100644 src/vppinfra/test_vec.h create mode 100644 src/vppinfra/test_vhash.c create mode 100644 src/vppinfra/test_zvec.c create mode 100644 src/vppinfra/time.c create mode 100644 src/vppinfra/time.h create mode 100644 src/vppinfra/timer.c create mode 100644 src/vppinfra/timer.h create mode 100644 src/vppinfra/timing_wheel.c create mode 100644 src/vppinfra/timing_wheel.h create mode 100644 src/vppinfra/types.h create mode 100644 src/vppinfra/unformat.c create mode 100644 src/vppinfra/unix-formats.c create mode 100644 src/vppinfra/unix-kelog.c create mode 100644 src/vppinfra/unix-misc.c create mode 100644 src/vppinfra/unix.h create mode 100644 src/vppinfra/unix_error.def create mode 100644 src/vppinfra/valgrind.h create mode 100644 src/vppinfra/vec.c create mode 100644 src/vppinfra/vec.h create mode 100644 src/vppinfra/vec_bootstrap.h create mode 100644 src/vppinfra/vector.c create mode 100644 src/vppinfra/vector.h create mode 100644 src/vppinfra/vector_altivec.h create mode 100644 src/vppinfra/vector_funcs.h create mode 100644 src/vppinfra/vector_iwmmxt.h create mode 100644 src/vppinfra/vector_neon.h create mode 100644 src/vppinfra/vector_sse2.h create mode 100644 src/vppinfra/vhash.c create mode 100644 src/vppinfra/vhash.h create mode 100644 src/vppinfra/vm_linux_kernel.h create mode 100644 src/vppinfra/vm_standalone.h create mode 100644 src/vppinfra/vm_unix.h create mode 100644 src/vppinfra/xxhash.h create mode 100644 src/vppinfra/xy.h create mode 100644 src/vppinfra/zvec.c create mode 100644 src/vppinfra/zvec.h delete mode 100644 svm/Makefile.am delete mode 100644 svm/configure.ac delete mode 100644 svm/dir.dox delete mode 100644 svm/persist.c delete mode 100644 svm/ssvm.c delete mode 100644 svm/ssvm.h delete mode 100644 svm/svm.c delete mode 100644 svm/svm.h delete mode 100644 svm/svm_test.c delete mode 100644 svm/svmdb.c delete mode 100644 svm/svmdb.h delete mode 100644 svm/svmdbtool.c delete mode 100644 svm/svmtool.c delete mode 100644 vlib-api/Makefile.am delete mode 100644 vlib-api/configure.ac delete mode 120000 vlib-api/suffix-rules.mk delete mode 100644 vlib-api/vlibapi/api.h delete mode 100644 vlib-api/vlibapi/api_helper_macros.h delete mode 100644 vlib-api/vlibapi/api_shared.c delete mode 100644 vlib-api/vlibapi/node_serialize.c delete mode 100644 vlib-api/vlibmemory/api.h delete mode 100644 vlib-api/vlibmemory/memclnt.api delete mode 100644 vlib-api/vlibmemory/memory_client.c delete mode 100644 vlib-api/vlibmemory/memory_shared.c delete mode 100644 vlib-api/vlibmemory/memory_vlib.c delete mode 100644 vlib-api/vlibmemory/unix_shared_memory_queue.c delete mode 100644 vlib-api/vlibmemory/unix_shared_memory_queue.h delete mode 100644 vlib-api/vlibmemory/vl_memory_api_h.h delete mode 100644 vlib-api/vlibmemory/vl_memory_msg_enum.h delete mode 100644 vlib-api/vlibsocket/api.h delete mode 100644 vlib-api/vlibsocket/sock_test.c delete mode 100644 vlib-api/vlibsocket/sockclnt.api delete mode 100644 vlib-api/vlibsocket/sockclnt_vlib.c delete mode 100644 vlib-api/vlibsocket/socksvr_vlib.c delete mode 100644 vlib-api/vlibsocket/vl_socket_api_h.h delete mode 100644 vlib-api/vlibsocket/vl_socket_msg_enum.h delete mode 100644 vlib/.gitignore delete mode 100644 vlib/Makefile.am delete mode 100644 vlib/configure.ac delete mode 100644 vlib/dir.dox delete mode 100644 vlib/example/dir.dox delete mode 100644 vlib/example/main_stub.c delete mode 100644 vlib/example/mc_test.c delete mode 100644 vlib/example/plex_test.c delete mode 100644 vlib/vlib/buffer.c delete mode 100644 vlib/vlib/buffer.h delete mode 100644 vlib/vlib/buffer_funcs.h delete mode 100644 vlib/vlib/buffer_node.h delete mode 100644 vlib/vlib/cli.c delete mode 100644 vlib/vlib/cli.h delete mode 100644 vlib/vlib/cli_funcs.h delete mode 100644 vlib/vlib/counter.c delete mode 100644 vlib/vlib/counter.h delete mode 100644 vlib/vlib/defs.h delete mode 100644 vlib/vlib/dir.dox delete mode 100644 vlib/vlib/elog_samples.c delete mode 100644 vlib/vlib/error.c delete mode 100644 vlib/vlib/error.h delete mode 100644 vlib/vlib/error_funcs.h delete mode 100644 vlib/vlib/format.c delete mode 100644 vlib/vlib/format_funcs.h delete mode 100644 vlib/vlib/global_funcs.h delete mode 100644 vlib/vlib/i2c.c delete mode 100644 vlib/vlib/i2c.h delete mode 100644 vlib/vlib/init.c delete mode 100644 vlib/vlib/init.h delete mode 100644 vlib/vlib/lex.c delete mode 100644 vlib/vlib/lex.h delete mode 100644 vlib/vlib/main.c delete mode 100644 vlib/vlib/main.h delete mode 100644 vlib/vlib/mc.c delete mode 100644 vlib/vlib/mc.h delete mode 100644 vlib/vlib/node.c delete mode 100644 vlib/vlib/node.h delete mode 100644 vlib/vlib/node_cli.c delete mode 100644 vlib/vlib/node_format.c delete mode 100644 vlib/vlib/node_funcs.h delete mode 100644 vlib/vlib/parse.c delete mode 100644 vlib/vlib/parse.h delete mode 100644 vlib/vlib/parse_builtin.c delete mode 100644 vlib/vlib/pci/linux_pci.c delete mode 100644 vlib/vlib/pci/pci.c delete mode 100644 vlib/vlib/pci/pci.h delete mode 100644 vlib/vlib/pci/pci_config.h delete mode 100644 vlib/vlib/physmem.h delete mode 100644 vlib/vlib/threads.c delete mode 100644 vlib/vlib/threads.h delete mode 100644 vlib/vlib/threads_cli.c delete mode 100644 vlib/vlib/trace.c delete mode 100644 vlib/vlib/trace.h delete mode 100644 vlib/vlib/trace_funcs.h delete mode 100644 vlib/vlib/unix/cj.c delete mode 100644 vlib/vlib/unix/cj.h delete mode 100644 vlib/vlib/unix/cli.c delete mode 100644 vlib/vlib/unix/dir.dox delete mode 100644 vlib/vlib/unix/input.c delete mode 100644 vlib/vlib/unix/main.c delete mode 100644 vlib/vlib/unix/mc_socket.c delete mode 100644 vlib/vlib/unix/mc_socket.h delete mode 100644 vlib/vlib/unix/physmem.c delete mode 100644 vlib/vlib/unix/physmem.h delete mode 100644 vlib/vlib/unix/plugin.c delete mode 100644 vlib/vlib/unix/plugin.h delete mode 100644 vlib/vlib/unix/unix.h delete mode 100644 vlib/vlib/unix/util.c delete mode 100644 vlib/vlib/vlib.h delete mode 100644 vlib/vlib/vlib_process_doc.h delete mode 100644 vnet/.gitignore delete mode 100644 vnet/Makefile.am delete mode 100644 vnet/configure.ac delete mode 100644 vnet/etc/scripts/arp4 delete mode 100644 vnet/etc/scripts/arp4-mpls delete mode 100644 vnet/etc/scripts/arp6 delete mode 100644 vnet/etc/scripts/bvi delete mode 100644 vnet/etc/scripts/dhcp/dhcpd.conf delete mode 100644 vnet/etc/scripts/dhcp/left-ping-target.sh delete mode 100644 vnet/etc/scripts/dhcp/leftpeer.conf delete mode 100644 vnet/etc/scripts/icmp delete mode 100644 vnet/etc/scripts/icmp6 delete mode 100644 vnet/etc/scripts/ige delete mode 100644 vnet/etc/scripts/ip6 delete mode 100644 vnet/etc/scripts/ip6-hbh delete mode 100644 vnet/etc/scripts/ixge delete mode 100644 vnet/etc/scripts/l2efpfilter delete mode 100644 vnet/etc/scripts/l2efpfilter_perf delete mode 100644 vnet/etc/scripts/l2fib delete mode 100644 vnet/etc/scripts/l2fib_perf delete mode 100644 vnet/etc/scripts/l2fib_xc delete mode 100644 vnet/etc/scripts/l2flood delete mode 100644 vnet/etc/scripts/l2tp delete mode 100755 vnet/etc/scripts/leftpeer/leftpeer-classify delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-classify6 delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-classifyl2 delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-dhcp delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-ioam.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-l3vxlan.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-lisp.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-mpls.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-sr.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer-vxlan.conf delete mode 100644 vnet/etc/scripts/leftpeer/leftpeer.script delete mode 100644 vnet/etc/scripts/lfib/ip4-to-mpls delete mode 100644 vnet/etc/scripts/lfib/mpls-pop-to-mpls delete mode 100644 vnet/etc/scripts/lfib/mpls-to-ip4 delete mode 100644 vnet/etc/scripts/lfib/mpls-to-mpls delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/leftpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/pg delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/rightpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-ethernet/single.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/dhcpd.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/leftpeer.conf delete mode 100644 vnet/etc/scripts/mpls-o-gre/rightpeer.conf delete mode 100644 vnet/etc/scripts/mpls-tunnel delete mode 100644 vnet/etc/scripts/pcap delete mode 100644 vnet/etc/scripts/probe4 delete mode 100644 vnet/etc/scripts/probe6 delete mode 100644 vnet/etc/scripts/rewrite delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-ioam.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-l3vxlan.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-lisp.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-mpls-l2.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-mpls.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-sr.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer-vxlan.conf delete mode 100644 vnet/etc/scripts/rightpeer/rightpeer.script delete mode 100644 vnet/etc/scripts/rpf delete mode 100644 vnet/etc/scripts/rtt-test delete mode 100644 vnet/etc/scripts/snat delete mode 100644 vnet/etc/scripts/snat_static delete mode 100644 vnet/etc/scripts/snat_static_with_port delete mode 100644 vnet/etc/scripts/source_and_port_range_check delete mode 100644 vnet/etc/scripts/speed delete mode 100755 vnet/etc/scripts/sr/left-linux-ping.sh delete mode 100644 vnet/etc/scripts/sr/leftpeer.conf delete mode 100755 vnet/etc/scripts/sr/right-linux-ping.sh delete mode 100644 vnet/etc/scripts/sr/rightpeer.conf delete mode 100755 vnet/etc/scripts/sr/srlocal.sh delete mode 100644 vnet/etc/scripts/srp delete mode 100644 vnet/etc/scripts/tcp delete mode 100644 vnet/etc/scripts/tcp-test delete mode 100644 vnet/etc/scripts/tf-ucs-1 delete mode 100644 vnet/etc/scripts/urpf delete mode 100644 vnet/etc/scripts/virl/ip6sr.virl delete mode 100644 vnet/etc/scripts/virl/ip6sr_notes.txt delete mode 100644 vnet/etc/scripts/virl/mplsogre.virl delete mode 100644 vnet/etc/scripts/virl/simple.virl delete mode 100644 vnet/etc/scripts/vlan delete mode 120000 vnet/suffix-rules.mk delete mode 100644 vnet/test/README delete mode 100644 vnet/test/lisp-cp/test_cp_serdes.c delete mode 100644 vnet/test/lisp-cp/test_lisp_types.c delete mode 100644 vnet/test/lisp-gpe/test.c delete mode 100644 vnet/vnet/adj/adj.c delete mode 100644 vnet/vnet/adj/adj.h delete mode 100644 vnet/vnet/adj/adj_glean.c delete mode 100644 vnet/vnet/adj/adj_glean.h delete mode 100644 vnet/vnet/adj/adj_internal.h delete mode 100644 vnet/vnet/adj/adj_l2.c delete mode 100644 vnet/vnet/adj/adj_l2.h delete mode 100644 vnet/vnet/adj/adj_midchain.c delete mode 100644 vnet/vnet/adj/adj_midchain.h delete mode 100644 vnet/vnet/adj/adj_nbr.c delete mode 100644 vnet/vnet/adj/adj_nbr.h delete mode 100644 vnet/vnet/adj/adj_rewrite.c delete mode 100644 vnet/vnet/adj/adj_rewrite.h delete mode 100644 vnet/vnet/adj/adj_types.h delete mode 100644 vnet/vnet/api_errno.h delete mode 100644 vnet/vnet/bfd/bfd.api delete mode 100644 vnet/vnet/bfd/bfd_api.c delete mode 100644 vnet/vnet/bfd/bfd_api.h delete mode 100644 vnet/vnet/bfd/bfd_debug.h delete mode 100644 vnet/vnet/bfd/bfd_doc.md delete mode 100644 vnet/vnet/bfd/bfd_main.c delete mode 100644 vnet/vnet/bfd/bfd_main.h delete mode 100644 vnet/vnet/bfd/bfd_protocol.c delete mode 100644 vnet/vnet/bfd/bfd_protocol.h delete mode 100644 vnet/vnet/bfd/bfd_udp.c delete mode 100644 vnet/vnet/bfd/bfd_udp.h delete mode 100644 vnet/vnet/bfd/dir.dox delete mode 100644 vnet/vnet/buffer.h delete mode 100644 vnet/vnet/cdp/cdp.pg delete mode 100644 vnet/vnet/cdp/cdp_input.c delete mode 100644 vnet/vnet/cdp/cdp_node.c delete mode 100644 vnet/vnet/cdp/cdp_node.h delete mode 100644 vnet/vnet/cdp/cdp_periodic.c delete mode 100644 vnet/vnet/cdp/cdp_protocol.h delete mode 100644 vnet/vnet/classify/README delete mode 100644 vnet/vnet/classify/flow_classify.c delete mode 100644 vnet/vnet/classify/flow_classify.h delete mode 100644 vnet/vnet/classify/flow_classify_node.c delete mode 100644 vnet/vnet/classify/input_acl.c delete mode 100644 vnet/vnet/classify/input_acl.h delete mode 100644 vnet/vnet/classify/ip_classify.c delete mode 100644 vnet/vnet/classify/policer_classify.c delete mode 100644 vnet/vnet/classify/policer_classify.h delete mode 100644 vnet/vnet/classify/vnet_classify.c delete mode 100644 vnet/vnet/classify/vnet_classify.h delete mode 100644 vnet/vnet/config.c delete mode 100644 vnet/vnet/config.h delete mode 100644 vnet/vnet/cop/cop.c delete mode 100644 vnet/vnet/cop/cop.h delete mode 100644 vnet/vnet/cop/ip4_whitelist.c delete mode 100644 vnet/vnet/cop/ip6_whitelist.c delete mode 100644 vnet/vnet/cop/node1.c delete mode 100644 vnet/vnet/devices/af_packet/af_packet.api delete mode 100644 vnet/vnet/devices/af_packet/af_packet.c delete mode 100644 vnet/vnet/devices/af_packet/af_packet.h delete mode 100644 vnet/vnet/devices/af_packet/af_packet_api.c delete mode 100644 vnet/vnet/devices/af_packet/cli.c delete mode 100644 vnet/vnet/devices/af_packet/device.c delete mode 100644 vnet/vnet/devices/af_packet/node.c delete mode 100644 vnet/vnet/devices/devices.c delete mode 100644 vnet/vnet/devices/devices.h delete mode 100644 vnet/vnet/devices/dpdk/cli.c delete mode 100644 vnet/vnet/devices/dpdk/device.c delete mode 100644 vnet/vnet/devices/dpdk/dpdk.h delete mode 100644 vnet/vnet/devices/dpdk/dpdk_priv.h delete mode 100644 vnet/vnet/devices/dpdk/format.c delete mode 100644 vnet/vnet/devices/dpdk/hqos.c delete mode 100755 vnet/vnet/devices/dpdk/init.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/cli.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/crypto_node.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/dir.dox delete mode 100644 vnet/vnet/devices/dpdk/ipsec/dpdk_crypto_ipsec_doc.md delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp.h delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp_decrypt.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/esp_encrypt.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/ipsec.c delete mode 100644 vnet/vnet/devices/dpdk/ipsec/ipsec.h delete mode 100644 vnet/vnet/devices/dpdk/node.c delete mode 100644 vnet/vnet/devices/dpdk/qos_doc.md delete mode 100644 vnet/vnet/devices/netmap/cli.c delete mode 100644 vnet/vnet/devices/netmap/device.c delete mode 100644 vnet/vnet/devices/netmap/net_netmap.h delete mode 100644 vnet/vnet/devices/netmap/netmap.api delete mode 100644 vnet/vnet/devices/netmap/netmap.c delete mode 100644 vnet/vnet/devices/netmap/netmap.h delete mode 100644 vnet/vnet/devices/netmap/netmap_api.c delete mode 100644 vnet/vnet/devices/netmap/node.c delete mode 100644 vnet/vnet/devices/nic/ixge.c delete mode 100644 vnet/vnet/devices/nic/ixge.h delete mode 100644 vnet/vnet/devices/nic/sfp.c delete mode 100644 vnet/vnet/devices/nic/sfp.h delete mode 100644 vnet/vnet/devices/ssvm/node.c delete mode 100644 vnet/vnet/devices/ssvm/ssvm_eth.c delete mode 100644 vnet/vnet/devices/ssvm/ssvm_eth.h delete mode 100644 vnet/vnet/devices/virtio/dir.dox delete mode 100644 vnet/vnet/devices/virtio/vhost-user.c delete mode 100644 vnet/vnet/devices/virtio/vhost-user.h delete mode 100644 vnet/vnet/devices/virtio/vhost_user.api delete mode 100644 vnet/vnet/devices/virtio/vhost_user_api.c delete mode 100644 vnet/vnet/dhcp/client.c delete mode 100644 vnet/vnet/dhcp/client.h delete mode 100644 vnet/vnet/dhcp/packet.h delete mode 100644 vnet/vnet/dhcp/proxy.h delete mode 100644 vnet/vnet/dhcp/proxy_error.def delete mode 100644 vnet/vnet/dhcp/proxy_node.c delete mode 100644 vnet/vnet/dhcpv6/packet.h delete mode 100644 vnet/vnet/dhcpv6/proxy.h delete mode 100644 vnet/vnet/dhcpv6/proxy_error.def delete mode 100644 vnet/vnet/dhcpv6/proxy_node.c delete mode 100644 vnet/vnet/dpo/classify_dpo.c delete mode 100644 vnet/vnet/dpo/classify_dpo.h delete mode 100644 vnet/vnet/dpo/dpo.c delete mode 100644 vnet/vnet/dpo/dpo.h delete mode 100644 vnet/vnet/dpo/drop_dpo.c delete mode 100644 vnet/vnet/dpo/drop_dpo.h delete mode 100644 vnet/vnet/dpo/ip_null_dpo.c delete mode 100644 vnet/vnet/dpo/ip_null_dpo.h delete mode 100644 vnet/vnet/dpo/load_balance.c delete mode 100644 vnet/vnet/dpo/load_balance.h delete mode 100644 vnet/vnet/dpo/load_balance_map.c delete mode 100644 vnet/vnet/dpo/load_balance_map.h delete mode 100644 vnet/vnet/dpo/lookup_dpo.c delete mode 100644 vnet/vnet/dpo/lookup_dpo.h delete mode 100644 vnet/vnet/dpo/mpls_label_dpo.c delete mode 100644 vnet/vnet/dpo/mpls_label_dpo.h delete mode 100644 vnet/vnet/dpo/punt_dpo.c delete mode 100644 vnet/vnet/dpo/punt_dpo.h delete mode 100644 vnet/vnet/dpo/receive_dpo.c delete mode 100644 vnet/vnet/dpo/receive_dpo.h delete mode 100644 vnet/vnet/ethernet/arp.c delete mode 100644 vnet/vnet/ethernet/arp_packet.h delete mode 100644 vnet/vnet/ethernet/dir.dox delete mode 100644 vnet/vnet/ethernet/error.def delete mode 100644 vnet/vnet/ethernet/ethernet.h delete mode 100644 vnet/vnet/ethernet/format.c delete mode 100644 vnet/vnet/ethernet/init.c delete mode 100644 vnet/vnet/ethernet/interface.c delete mode 100644 vnet/vnet/ethernet/mac_swap.c delete mode 100755 vnet/vnet/ethernet/node.c delete mode 100644 vnet/vnet/ethernet/packet.h delete mode 100644 vnet/vnet/ethernet/pg.c delete mode 100644 vnet/vnet/ethernet/types.def delete mode 100644 vnet/vnet/feature/feature.c delete mode 100644 vnet/vnet/feature/feature.h delete mode 100644 vnet/vnet/feature/registration.c delete mode 100644 vnet/vnet/fib/fib.c delete mode 100644 vnet/vnet/fib/fib.h delete mode 100644 vnet/vnet/fib/fib_api.h delete mode 100644 vnet/vnet/fib/fib_attached_export.c delete mode 100644 vnet/vnet/fib/fib_attached_export.h delete mode 100644 vnet/vnet/fib/fib_entry.c delete mode 100644 vnet/vnet/fib/fib_entry.h delete mode 100644 vnet/vnet/fib/fib_entry_cover.c delete mode 100644 vnet/vnet/fib/fib_entry_cover.h delete mode 100644 vnet/vnet/fib/fib_entry_delegate.c delete mode 100644 vnet/vnet/fib/fib_entry_delegate.h delete mode 100644 vnet/vnet/fib/fib_entry_src.c delete mode 100644 vnet/vnet/fib/fib_entry_src.h delete mode 100644 vnet/vnet/fib/fib_entry_src_adj.c delete mode 100644 vnet/vnet/fib/fib_entry_src_api.c delete mode 100644 vnet/vnet/fib/fib_entry_src_default.c delete mode 100644 vnet/vnet/fib/fib_entry_src_default_route.c delete mode 100644 vnet/vnet/fib/fib_entry_src_interface.c delete mode 100644 vnet/vnet/fib/fib_entry_src_lisp.c delete mode 100644 vnet/vnet/fib/fib_entry_src_mpls.c delete mode 100644 vnet/vnet/fib/fib_entry_src_rr.c delete mode 100644 vnet/vnet/fib/fib_entry_src_special.c delete mode 100644 vnet/vnet/fib/fib_internal.h delete mode 100644 vnet/vnet/fib/fib_node.c delete mode 100644 vnet/vnet/fib/fib_node.h delete mode 100644 vnet/vnet/fib/fib_node_list.c delete mode 100644 vnet/vnet/fib/fib_node_list.h delete mode 100644 vnet/vnet/fib/fib_path.c delete mode 100644 vnet/vnet/fib/fib_path.h delete mode 100644 vnet/vnet/fib/fib_path_ext.c delete mode 100644 vnet/vnet/fib/fib_path_ext.h delete mode 100644 vnet/vnet/fib/fib_path_list.c delete mode 100644 vnet/vnet/fib/fib_path_list.h delete mode 100644 vnet/vnet/fib/fib_table.c delete mode 100644 vnet/vnet/fib/fib_table.h delete mode 100644 vnet/vnet/fib/fib_test.c delete mode 100644 vnet/vnet/fib/fib_types.c delete mode 100644 vnet/vnet/fib/fib_types.h delete mode 100644 vnet/vnet/fib/fib_urpf_list.c delete mode 100644 vnet/vnet/fib/fib_urpf_list.h delete mode 100644 vnet/vnet/fib/fib_walk.c delete mode 100644 vnet/vnet/fib/fib_walk.h delete mode 100644 vnet/vnet/fib/ip4_fib.c delete mode 100644 vnet/vnet/fib/ip4_fib.h delete mode 100644 vnet/vnet/fib/ip6_fib.c delete mode 100644 vnet/vnet/fib/ip6_fib.h delete mode 100644 vnet/vnet/fib/mpls_fib.c delete mode 100644 vnet/vnet/fib/mpls_fib.h delete mode 100644 vnet/vnet/flow/flow_report.c delete mode 100644 vnet/vnet/flow/flow_report.h delete mode 100644 vnet/vnet/flow/flow_report_classify.c delete mode 100644 vnet/vnet/flow/flow_report_classify.h delete mode 100644 vnet/vnet/flow/ipfix_info_elements.h delete mode 100644 vnet/vnet/flow/ipfix_packet.h delete mode 100644 vnet/vnet/global_funcs.h delete mode 100644 vnet/vnet/gre/error.def delete mode 100644 vnet/vnet/gre/gre.api delete mode 100644 vnet/vnet/gre/gre.c delete mode 100644 vnet/vnet/gre/gre.h delete mode 100644 vnet/vnet/gre/gre_api.c delete mode 100644 vnet/vnet/gre/interface.c delete mode 100644 vnet/vnet/gre/node.c delete mode 100644 vnet/vnet/gre/packet.h delete mode 100644 vnet/vnet/gre/pg.c delete mode 100644 vnet/vnet/handoff.c delete mode 100644 vnet/vnet/handoff.h delete mode 100644 vnet/vnet/hdlc/error.def delete mode 100644 vnet/vnet/hdlc/hdlc.c delete mode 100644 vnet/vnet/hdlc/hdlc.h delete mode 100644 vnet/vnet/hdlc/node.c delete mode 100644 vnet/vnet/hdlc/packet.h delete mode 100644 vnet/vnet/hdlc/pg.c delete mode 100644 vnet/vnet/interface.api delete mode 100644 vnet/vnet/interface.c delete mode 100644 vnet/vnet/interface.h delete mode 100644 vnet/vnet/interface_api.c delete mode 100644 vnet/vnet/interface_cli.c delete mode 100644 vnet/vnet/interface_format.c delete mode 100644 vnet/vnet/interface_funcs.h delete mode 100644 vnet/vnet/interface_output.c delete mode 100644 vnet/vnet/ip/dir.dox delete mode 100644 vnet/vnet/ip/format.c delete mode 100644 vnet/vnet/ip/format.h delete mode 100644 vnet/vnet/ip/icmp4.c delete mode 100644 vnet/vnet/ip/icmp4.h delete mode 100644 vnet/vnet/ip/icmp46_packet.h delete mode 100644 vnet/vnet/ip/icmp6.c delete mode 100644 vnet/vnet/ip/icmp6.h delete mode 100644 vnet/vnet/ip/igmp_packet.h delete mode 100644 vnet/vnet/ip/ip.api delete mode 100644 vnet/vnet/ip/ip.h delete mode 100644 vnet/vnet/ip/ip4.h delete mode 100644 vnet/vnet/ip/ip46_cli.c delete mode 100644 vnet/vnet/ip/ip4_error.h delete mode 100644 vnet/vnet/ip/ip4_format.c delete mode 100644 vnet/vnet/ip/ip4_forward.c delete mode 100644 vnet/vnet/ip/ip4_input.c delete mode 100644 vnet/vnet/ip/ip4_mtrie.c delete mode 100644 vnet/vnet/ip/ip4_mtrie.h delete mode 100644 vnet/vnet/ip/ip4_packet.h delete mode 100644 vnet/vnet/ip/ip4_pg.c delete mode 100644 vnet/vnet/ip/ip4_source_and_port_range_check.c delete mode 100644 vnet/vnet/ip/ip4_source_check.c delete mode 100644 vnet/vnet/ip/ip4_test.c delete mode 100644 vnet/vnet/ip/ip6.h delete mode 100644 vnet/vnet/ip/ip6_error.h delete mode 100644 vnet/vnet/ip/ip6_format.c delete mode 100644 vnet/vnet/ip/ip6_forward.c delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop.c delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop.h delete mode 100644 vnet/vnet/ip/ip6_hop_by_hop_packet.h delete mode 100644 vnet/vnet/ip/ip6_input.c delete mode 100644 vnet/vnet/ip/ip6_neighbor.c delete mode 100644 vnet/vnet/ip/ip6_neighbor.h delete mode 100644 vnet/vnet/ip/ip6_packet.h delete mode 100644 vnet/vnet/ip/ip6_pg.c delete mode 100644 vnet/vnet/ip/ip_api.c delete mode 100644 vnet/vnet/ip/ip_checksum.c delete mode 100644 vnet/vnet/ip/ip_frag.c delete mode 100644 vnet/vnet/ip/ip_frag.h delete mode 100644 vnet/vnet/ip/ip_init.c delete mode 100644 vnet/vnet/ip/ip_input_acl.c delete mode 100644 vnet/vnet/ip/ip_packet.h delete mode 100644 vnet/vnet/ip/ip_source_and_port_range_check.h delete mode 100644 vnet/vnet/ip/lookup.c delete mode 100644 vnet/vnet/ip/lookup.h delete mode 100644 vnet/vnet/ip/ping.c delete mode 100644 vnet/vnet/ip/ping.h delete mode 100644 vnet/vnet/ip/ports.def delete mode 100644 vnet/vnet/ip/protocols.def delete mode 100644 vnet/vnet/ip/punt.c delete mode 100644 vnet/vnet/ip/punt.h delete mode 100644 vnet/vnet/ip/punt_error.def delete mode 100644 vnet/vnet/ip/tcp_packet.h delete mode 100644 vnet/vnet/ip/udp.h delete mode 100644 vnet/vnet/ip/udp_error.def delete mode 100644 vnet/vnet/ip/udp_format.c delete mode 100644 vnet/vnet/ip/udp_init.c delete mode 100644 vnet/vnet/ip/udp_local.c delete mode 100644 vnet/vnet/ip/udp_packet.h delete mode 100644 vnet/vnet/ip/udp_pg.c delete mode 100644 vnet/vnet/ipsec-gre/dir.dox delete mode 100644 vnet/vnet/ipsec-gre/error.def delete mode 100644 vnet/vnet/ipsec-gre/interface.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.api delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre.h delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre_api.c delete mode 100644 vnet/vnet/ipsec-gre/ipsec_gre_doc.md delete mode 100644 vnet/vnet/ipsec-gre/node.c delete mode 100644 vnet/vnet/ipsec/esp.h delete mode 100644 vnet/vnet/ipsec/esp_decrypt.c delete mode 100644 vnet/vnet/ipsec/esp_encrypt.c delete mode 100644 vnet/vnet/ipsec/ikev2.c delete mode 100644 vnet/vnet/ipsec/ikev2.h delete mode 100644 vnet/vnet/ipsec/ikev2_cli.c delete mode 100644 vnet/vnet/ipsec/ikev2_crypto.c delete mode 100644 vnet/vnet/ipsec/ikev2_format.c delete mode 100644 vnet/vnet/ipsec/ikev2_payload.c delete mode 100644 vnet/vnet/ipsec/ikev2_priv.h delete mode 100644 vnet/vnet/ipsec/ipsec.api delete mode 100644 vnet/vnet/ipsec/ipsec.c delete mode 100644 vnet/vnet/ipsec/ipsec.h delete mode 100644 vnet/vnet/ipsec/ipsec_api.c delete mode 100644 vnet/vnet/ipsec/ipsec_cli.c delete mode 100644 vnet/vnet/ipsec/ipsec_format.c delete mode 100644 vnet/vnet/ipsec/ipsec_if.c delete mode 100644 vnet/vnet/ipsec/ipsec_if_in.c delete mode 100644 vnet/vnet/ipsec/ipsec_if_out.c delete mode 100644 vnet/vnet/ipsec/ipsec_input.c delete mode 100644 vnet/vnet/ipsec/ipsec_output.c delete mode 100644 vnet/vnet/l2/dir.dox delete mode 100644 vnet/vnet/l2/feat_bitmap.c delete mode 100644 vnet/vnet/l2/feat_bitmap.h delete mode 100644 vnet/vnet/l2/l2.api delete mode 100644 vnet/vnet/l2/l2_api.c delete mode 100644 vnet/vnet/l2/l2_bd.c delete mode 100644 vnet/vnet/l2/l2_bd.h delete mode 100644 vnet/vnet/l2/l2_bvi.c delete mode 100644 vnet/vnet/l2/l2_bvi.h delete mode 100644 vnet/vnet/l2/l2_classify.h delete mode 100644 vnet/vnet/l2/l2_efp_filter.c delete mode 100644 vnet/vnet/l2/l2_efp_filter.h delete mode 100644 vnet/vnet/l2/l2_fib.c delete mode 100644 vnet/vnet/l2/l2_fib.h delete mode 100644 vnet/vnet/l2/l2_flood.c delete mode 100644 vnet/vnet/l2/l2_flood.h delete mode 100644 vnet/vnet/l2/l2_fwd.c delete mode 100644 vnet/vnet/l2/l2_fwd.h delete mode 100644 vnet/vnet/l2/l2_input.c delete mode 100644 vnet/vnet/l2/l2_input.h delete mode 100644 vnet/vnet/l2/l2_input_acl.c delete mode 100644 vnet/vnet/l2/l2_input_classify.c delete mode 100644 vnet/vnet/l2/l2_input_vtr.c delete mode 100644 vnet/vnet/l2/l2_input_vtr.h delete mode 100644 vnet/vnet/l2/l2_learn.c delete mode 100644 vnet/vnet/l2/l2_learn.h delete mode 100644 vnet/vnet/l2/l2_output.c delete mode 100644 vnet/vnet/l2/l2_output.h delete mode 100644 vnet/vnet/l2/l2_output_acl.c delete mode 100644 vnet/vnet/l2/l2_output_classify.c delete mode 100644 vnet/vnet/l2/l2_patch.c delete mode 100644 vnet/vnet/l2/l2_rw.c delete mode 100644 vnet/vnet/l2/l2_rw.h delete mode 100644 vnet/vnet/l2/l2_vtr.c delete mode 100644 vnet/vnet/l2/l2_vtr.h delete mode 100644 vnet/vnet/l2/l2_xcrw.c delete mode 100644 vnet/vnet/l2/l2_xcrw.h delete mode 100644 vnet/vnet/l2tp/decap.c delete mode 100644 vnet/vnet/l2tp/encap.c delete mode 100644 vnet/vnet/l2tp/l2tp.api delete mode 100644 vnet/vnet/l2tp/l2tp.c delete mode 100644 vnet/vnet/l2tp/l2tp.h delete mode 100644 vnet/vnet/l2tp/l2tp_api.c delete mode 100644 vnet/vnet/l2tp/packet.h delete mode 100644 vnet/vnet/l2tp/pg.c delete mode 100644 vnet/vnet/l3_types.h delete mode 100644 vnet/vnet/lawful-intercept/lawful_intercept.c delete mode 100644 vnet/vnet/lawful-intercept/lawful_intercept.h delete mode 100644 vnet/vnet/lawful-intercept/node.c delete mode 100644 vnet/vnet/lisp-cp/control.c delete mode 100644 vnet/vnet/lisp-cp/control.h delete mode 100644 vnet/vnet/lisp-cp/gid_dictionary.c delete mode 100644 vnet/vnet/lisp-cp/gid_dictionary.h delete mode 100644 vnet/vnet/lisp-cp/lisp.api delete mode 100644 vnet/vnet/lisp-cp/lisp_api.c delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_dpo.c delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_dpo.h delete mode 100644 vnet/vnet/lisp-cp/lisp_cp_messages.h delete mode 100644 vnet/vnet/lisp-cp/lisp_msg_serdes.c delete mode 100644 vnet/vnet/lisp-cp/lisp_msg_serdes.h delete mode 100644 vnet/vnet/lisp-cp/lisp_types.c delete mode 100644 vnet/vnet/lisp-cp/lisp_types.h delete mode 100644 vnet/vnet/lisp-cp/packets.c delete mode 100644 vnet/vnet/lisp-cp/packets.h delete mode 100644 vnet/vnet/lisp-gpe/decap.c delete mode 100644 vnet/vnet/lisp-gpe/dir.dox delete mode 100644 vnet/vnet/lisp-gpe/interface.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.api delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_adjacency.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_adjacency.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_api.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_error.def delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_packet.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_sub_interface.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tenant.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tenant.h delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tunnel.c delete mode 100644 vnet/vnet/lisp-gpe/lisp_gpe_tunnel.h delete mode 100644 vnet/vnet/lisp-gpe/rfc.txt delete mode 100644 vnet/vnet/llc/llc.c delete mode 100644 vnet/vnet/llc/llc.h delete mode 100644 vnet/vnet/llc/node.c delete mode 100644 vnet/vnet/llc/pg.c delete mode 100644 vnet/vnet/lldp/dir.dox delete mode 100644 vnet/vnet/lldp/lldp_cli.c delete mode 100644 vnet/vnet/lldp/lldp_doc.md delete mode 100644 vnet/vnet/lldp/lldp_input.c delete mode 100644 vnet/vnet/lldp/lldp_node.c delete mode 100644 vnet/vnet/lldp/lldp_node.h delete mode 100644 vnet/vnet/lldp/lldp_output.c delete mode 100644 vnet/vnet/lldp/lldp_protocol.h delete mode 100755 vnet/vnet/map/examples/gen-rules.py delete mode 100644 vnet/vnet/map/examples/health_check.c delete mode 100755 vnet/vnet/map/examples/test_map.py delete mode 100755 vnet/vnet/map/gen-rules.py delete mode 100644 vnet/vnet/map/ip4_map.c delete mode 100644 vnet/vnet/map/ip4_map_t.c delete mode 100644 vnet/vnet/map/ip6_map.c delete mode 100644 vnet/vnet/map/ip6_map_t.c delete mode 100644 vnet/vnet/map/map.api delete mode 100644 vnet/vnet/map/map.c delete mode 100644 vnet/vnet/map/map.h delete mode 100644 vnet/vnet/map/map_api.c delete mode 100644 vnet/vnet/map/map_doc.md delete mode 100644 vnet/vnet/map/map_dpo.c delete mode 100644 vnet/vnet/map/map_dpo.h delete mode 100644 vnet/vnet/map/test.c delete mode 100644 vnet/vnet/mcast/mcast.c delete mode 100644 vnet/vnet/mcast/mcast.h delete mode 100644 vnet/vnet/mcast/mcast_test.c delete mode 100644 vnet/vnet/misc.c delete mode 100644 vnet/vnet/mpls/error.def delete mode 100644 vnet/vnet/mpls/interface.c delete mode 100644 vnet/vnet/mpls/mpls.c delete mode 100644 vnet/vnet/mpls/mpls.h delete mode 100644 vnet/vnet/mpls/mpls_features.c delete mode 100644 vnet/vnet/mpls/mpls_lookup.c delete mode 100644 vnet/vnet/mpls/mpls_output.c delete mode 100644 vnet/vnet/mpls/mpls_tunnel.c delete mode 100644 vnet/vnet/mpls/mpls_tunnel.h delete mode 100644 vnet/vnet/mpls/mpls_types.h delete mode 100644 vnet/vnet/mpls/node.c delete mode 100644 vnet/vnet/mpls/packet.h delete mode 100644 vnet/vnet/mpls/pg.c delete mode 100644 vnet/vnet/osi/node.c delete mode 100644 vnet/vnet/osi/osi.c delete mode 100644 vnet/vnet/osi/osi.h delete mode 100644 vnet/vnet/osi/pg.c delete mode 100644 vnet/vnet/pg/cli.c delete mode 100644 vnet/vnet/pg/edit.c delete mode 100644 vnet/vnet/pg/edit.h delete mode 100644 vnet/vnet/pg/example.script delete mode 100644 vnet/vnet/pg/init.c delete mode 100644 vnet/vnet/pg/input.c delete mode 100644 vnet/vnet/pg/output.c delete mode 100644 vnet/vnet/pg/pg.h delete mode 100644 vnet/vnet/pg/stream.c delete mode 100644 vnet/vnet/pipeline.h delete mode 100644 vnet/vnet/plugin/p1.c delete mode 100644 vnet/vnet/plugin/plugin.h delete mode 100644 vnet/vnet/policer/node_funcs.c delete mode 100644 vnet/vnet/policer/police.h delete mode 100644 vnet/vnet/policer/policer.c delete mode 100644 vnet/vnet/policer/policer.h delete mode 100644 vnet/vnet/policer/xlate.c delete mode 100644 vnet/vnet/policer/xlate.h delete mode 100644 vnet/vnet/ppp/error.def delete mode 100644 vnet/vnet/ppp/node.c delete mode 100644 vnet/vnet/ppp/packet.h delete mode 100644 vnet/vnet/ppp/pg.c delete mode 100644 vnet/vnet/ppp/ppp.c delete mode 100644 vnet/vnet/ppp/ppp.h delete mode 100644 vnet/vnet/replication.c delete mode 100644 vnet/vnet/replication.h delete mode 100644 vnet/vnet/rewrite.c delete mode 100644 vnet/vnet/rewrite.h delete mode 100644 vnet/vnet/snap/node.c delete mode 100644 vnet/vnet/snap/pg.c delete mode 100644 vnet/vnet/snap/snap.c delete mode 100644 vnet/vnet/snap/snap.h delete mode 100644 vnet/vnet/span/node.c delete mode 100644 vnet/vnet/span/span.api delete mode 100644 vnet/vnet/span/span.c delete mode 100644 vnet/vnet/span/span.h delete mode 100644 vnet/vnet/span/span.md delete mode 100644 vnet/vnet/span/span_api.c delete mode 100644 vnet/vnet/sr/dir.dox delete mode 100644 vnet/vnet/sr/examples/sr_multicastmap.script delete mode 100644 vnet/vnet/sr/rfc_draft_05.txt delete mode 100644 vnet/vnet/sr/sr.c delete mode 100644 vnet/vnet/sr/sr.h delete mode 100644 vnet/vnet/sr/sr_error.def delete mode 100644 vnet/vnet/sr/sr_fix_dst_error.def delete mode 100644 vnet/vnet/sr/sr_packet.h delete mode 100644 vnet/vnet/sr/sr_replicate.c delete mode 100644 vnet/vnet/srp/format.c delete mode 100644 vnet/vnet/srp/interface.c delete mode 100644 vnet/vnet/srp/node.c delete mode 100644 vnet/vnet/srp/packet.h delete mode 100644 vnet/vnet/srp/pg.c delete mode 100644 vnet/vnet/srp/srp.h delete mode 100644 vnet/vnet/unix/gdb_funcs.c delete mode 100644 vnet/vnet/unix/pcap.c delete mode 100644 vnet/vnet/unix/pcap.h delete mode 100644 vnet/vnet/unix/pcap2pg.c delete mode 100644 vnet/vnet/unix/tap.api delete mode 100644 vnet/vnet/unix/tap_api.c delete mode 100644 vnet/vnet/unix/tapcli.c delete mode 100644 vnet/vnet/unix/tapcli.h delete mode 100644 vnet/vnet/unix/tuntap.c delete mode 100644 vnet/vnet/unix/tuntap.h delete mode 100644 vnet/vnet/vnet.h delete mode 100644 vnet/vnet/vnet_all_api_h.h delete mode 100644 vnet/vnet/vnet_msg_enum.h delete mode 100644 vnet/vnet/vxlan-gpe/decap.c delete mode 100644 vnet/vnet/vxlan-gpe/dir.dox delete mode 100644 vnet/vnet/vxlan-gpe/encap.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan-gpe-rfc.txt delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.api delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe.h delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_api.c delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_error.def delete mode 100644 vnet/vnet/vxlan-gpe/vxlan_gpe_packet.h delete mode 100644 vnet/vnet/vxlan/decap.c delete mode 100644 vnet/vnet/vxlan/dir.dox delete mode 100644 vnet/vnet/vxlan/encap.c delete mode 100644 vnet/vnet/vxlan/vxlan.api delete mode 100644 vnet/vnet/vxlan/vxlan.c delete mode 100644 vnet/vnet/vxlan/vxlan.h delete mode 100644 vnet/vnet/vxlan/vxlan_api.c delete mode 100644 vnet/vnet/vxlan/vxlan_error.def delete mode 100644 vnet/vnet/vxlan/vxlan_packet.h delete mode 100644 vpp-api-test/Makefile.am delete mode 100644 vpp-api-test/configure.ac delete mode 100755 vpp-api-test/scripts/vppctl delete mode 100644 vpp-api-test/vat/api_format.c delete mode 100644 vpp-api-test/vat/json_format.c delete mode 100644 vpp-api-test/vat/json_format.h delete mode 100644 vpp-api-test/vat/json_test.c delete mode 100644 vpp-api-test/vat/main.c delete mode 100644 vpp-api-test/vat/plugin.c delete mode 100644 vpp-api-test/vat/plugin.h delete mode 100644 vpp-api-test/vat/plugin_api.c delete mode 100644 vpp-api-test/vat/restart.c delete mode 100644 vpp-api-test/vat/vat.h delete mode 100644 vpp-api/python/Makefile.am delete mode 100644 vpp-api/python/README.rst delete mode 100644 vpp-api/python/pneum/pneum.c delete mode 100644 vpp-api/python/pneum/pneum.h delete mode 100644 vpp-api/python/pneum/test_pneum.c delete mode 100644 vpp-api/python/setup.cfg delete mode 100644 vpp-api/python/setup.py delete mode 100755 vpp-api/python/tests/test_cli.py delete mode 100755 vpp-api/python/tests/test_modules.py delete mode 100755 vpp-api/python/tests/test_papi.py delete mode 100755 vpp-api/python/tests/test_version.py delete mode 100755 vpp-api/python/tests/test_vpp_papi2.py delete mode 100644 vpp-api/python/vpp_papi/__init__.py delete mode 100644 vpp-api/python/vpp_papi/pneum_wrap.c delete mode 100644 vpp-api/python/vpp_papi/vpp_papi.py delete mode 100644 vpp/Makefile.am delete mode 100644 vpp/app/l2t.c delete mode 100644 vpp/app/l2t_l2.c delete mode 100644 vpp/app/sticky_hash.c delete mode 100644 vpp/app/version.c delete mode 100644 vpp/app/vpe_cli.c delete mode 100644 vpp/conf/80-vpp.conf delete mode 100644 vpp/conf/startup.conf delete mode 100644 vpp/conf/startup.uiopcigeneric.conf delete mode 100644 vpp/configure.ac delete mode 100644 vpp/oam/oam.c delete mode 100644 vpp/oam/oam.h delete mode 100644 vpp/stats/stats.c delete mode 100644 vpp/stats/stats.h delete mode 120000 vpp/suffix-rules.mk delete mode 100644 vpp/vnet/main.c delete mode 100644 vpp/vpp-api/api.c delete mode 120000 vpp/vpp-api/api_format.c delete mode 100644 vpp/vpp-api/api_main.c delete mode 100644 vpp/vpp-api/custom_dump.c delete mode 100644 vpp/vpp-api/gmon.c delete mode 100644 vpp/vpp-api/json_format.c delete mode 100644 vpp/vpp-api/json_format.h delete mode 100644 vpp/vpp-api/summary_stats_client.c delete mode 100644 vpp/vpp-api/test_client.c delete mode 100644 vpp/vpp-api/test_ha.c delete mode 120000 vpp/vpp-api/vat.h delete mode 100644 vpp/vpp-api/vpe.api delete mode 100644 vpp/vpp-api/vpe_all_api_h.h delete mode 100644 vpp/vpp-api/vpe_msg_enum.h delete mode 100644 vpp/vpp-api/vpp_get_metrics.c delete mode 100644 vppapigen/Makefile.am delete mode 100644 vppapigen/configure.ac delete mode 100644 vppapigen/gram.y delete mode 100644 vppapigen/lex.c delete mode 100644 vppapigen/lex.h delete mode 100644 vppapigen/node.c delete mode 100644 vppapigen/node.h delete mode 100644 vppinfra/.gitignore delete mode 100644 vppinfra/INSTALL delete mode 100644 vppinfra/Make.defs delete mode 100644 vppinfra/Makefile.am delete mode 100644 vppinfra/README delete mode 100644 vppinfra/configure.ac delete mode 100644 vppinfra/dir.dox delete mode 100755 vppinfra/mkinstalldirs delete mode 100644 vppinfra/tools/dir.dox delete mode 100644 vppinfra/tools/elftool.c delete mode 100644 vppinfra/unix_error.def delete mode 100644 vppinfra/vppinfra/anneal.c delete mode 100644 vppinfra/vppinfra/anneal.h delete mode 100644 vppinfra/vppinfra/asm_mips.h delete mode 100644 vppinfra/vppinfra/asm_x86.c delete mode 100644 vppinfra/vppinfra/asm_x86.h delete mode 100644 vppinfra/vppinfra/backtrace.c delete mode 100644 vppinfra/vppinfra/bihash_24_8.h delete mode 100644 vppinfra/vppinfra/bihash_8_8.h delete mode 100644 vppinfra/vppinfra/bihash_doc.h delete mode 100644 vppinfra/vppinfra/bihash_template.c delete mode 100644 vppinfra/vppinfra/bihash_template.h delete mode 100644 vppinfra/vppinfra/bitmap.h delete mode 100644 vppinfra/vppinfra/bitops.h delete mode 100644 vppinfra/vppinfra/byte_order.h delete mode 100644 vppinfra/vppinfra/cache.h delete mode 100644 vppinfra/vppinfra/clib.h delete mode 100644 vppinfra/vppinfra/cpu.c delete mode 100644 vppinfra/vppinfra/cpu.h delete mode 100644 vppinfra/vppinfra/dir.dox delete mode 100644 vppinfra/vppinfra/dlist.h delete mode 100644 vppinfra/vppinfra/elf.c delete mode 100644 vppinfra/vppinfra/elf.h delete mode 100644 vppinfra/vppinfra/elf_clib.c delete mode 100644 vppinfra/vppinfra/elf_clib.h delete mode 100644 vppinfra/vppinfra/elog.c delete mode 100644 vppinfra/vppinfra/elog.h delete mode 100644 vppinfra/vppinfra/error.c delete mode 100644 vppinfra/vppinfra/error.h delete mode 100644 vppinfra/vppinfra/error_bootstrap.h delete mode 100644 vppinfra/vppinfra/fheap.c delete mode 100644 vppinfra/vppinfra/fheap.h delete mode 100644 vppinfra/vppinfra/fifo.c delete mode 100644 vppinfra/vppinfra/fifo.h delete mode 100644 vppinfra/vppinfra/format.c delete mode 100644 vppinfra/vppinfra/format.h delete mode 100644 vppinfra/vppinfra/graph.c delete mode 100644 vppinfra/vppinfra/graph.h delete mode 100644 vppinfra/vppinfra/hash.c delete mode 100644 vppinfra/vppinfra/hash.h delete mode 100644 vppinfra/vppinfra/heap.c delete mode 100644 vppinfra/vppinfra/heap.h delete mode 100644 vppinfra/vppinfra/longjmp.S delete mode 100644 vppinfra/vppinfra/longjmp.h delete mode 100644 vppinfra/vppinfra/macros.c delete mode 100644 vppinfra/vppinfra/macros.h delete mode 100644 vppinfra/vppinfra/math.h delete mode 100644 vppinfra/vppinfra/md5.c delete mode 100644 vppinfra/vppinfra/md5.h delete mode 100644 vppinfra/vppinfra/mem.h delete mode 100644 vppinfra/vppinfra/mem_mheap.c delete mode 100644 vppinfra/vppinfra/memcheck.h delete mode 100644 vppinfra/vppinfra/memcpy_avx.h delete mode 100644 vppinfra/vppinfra/memcpy_sse3.h delete mode 100644 vppinfra/vppinfra/mhash.c delete mode 100644 vppinfra/vppinfra/mhash.h delete mode 100644 vppinfra/vppinfra/mheap.c delete mode 100644 vppinfra/vppinfra/mheap.h delete mode 100644 vppinfra/vppinfra/mheap_bootstrap.h delete mode 100644 vppinfra/vppinfra/mod_test_hash.c delete mode 100644 vppinfra/vppinfra/os.h delete mode 100644 vppinfra/vppinfra/pfhash.c delete mode 100644 vppinfra/vppinfra/pfhash.h delete mode 100644 vppinfra/vppinfra/phash.c delete mode 100644 vppinfra/vppinfra/phash.h delete mode 100644 vppinfra/vppinfra/pipeline.h delete mode 100644 vppinfra/vppinfra/pool.h delete mode 100644 vppinfra/vppinfra/ptclosure.c delete mode 100644 vppinfra/vppinfra/ptclosure.h delete mode 100644 vppinfra/vppinfra/qhash.c delete mode 100644 vppinfra/vppinfra/qhash.h delete mode 100644 vppinfra/vppinfra/qsort.c delete mode 100644 vppinfra/vppinfra/random.c delete mode 100644 vppinfra/vppinfra/random.h delete mode 100644 vppinfra/vppinfra/random_buffer.c delete mode 100644 vppinfra/vppinfra/random_buffer.h delete mode 100644 vppinfra/vppinfra/random_isaac.c delete mode 100644 vppinfra/vppinfra/random_isaac.h delete mode 100644 vppinfra/vppinfra/serialize.c delete mode 100644 vppinfra/vppinfra/serialize.h delete mode 100644 vppinfra/vppinfra/slist.c delete mode 100644 vppinfra/vppinfra/slist.h delete mode 100644 vppinfra/vppinfra/smp.c delete mode 100644 vppinfra/vppinfra/smp.h delete mode 100644 vppinfra/vppinfra/smp_fifo.c delete mode 100644 vppinfra/vppinfra/smp_fifo.h delete mode 100644 vppinfra/vppinfra/socket.c delete mode 100644 vppinfra/vppinfra/socket.h delete mode 100644 vppinfra/vppinfra/sparse_vec.h delete mode 100644 vppinfra/vppinfra/std-formats.c delete mode 100644 vppinfra/vppinfra/string.c delete mode 100644 vppinfra/vppinfra/string.h delete mode 100644 vppinfra/vppinfra/test_bihash_template.c delete mode 100644 vppinfra/vppinfra/test_dlist.c delete mode 100644 vppinfra/vppinfra/test_elf.c delete mode 100644 vppinfra/vppinfra/test_elog.c delete mode 100644 vppinfra/vppinfra/test_fifo.c delete mode 100644 vppinfra/vppinfra/test_format.c delete mode 100644 vppinfra/vppinfra/test_hash.c delete mode 100644 vppinfra/vppinfra/test_heap.c delete mode 100644 vppinfra/vppinfra/test_longjmp.c delete mode 100644 vppinfra/vppinfra/test_macros.c delete mode 100644 vppinfra/vppinfra/test_md5.c delete mode 100644 vppinfra/vppinfra/test_mheap.c delete mode 100644 vppinfra/vppinfra/test_pfhash.c delete mode 100644 vppinfra/vppinfra/test_phash.c delete mode 100644 vppinfra/vppinfra/test_pool.c delete mode 100644 vppinfra/vppinfra/test_pool_iterate.c delete mode 100644 vppinfra/vppinfra/test_ptclosure.c delete mode 100644 vppinfra/vppinfra/test_qhash.c delete mode 100644 vppinfra/vppinfra/test_random.c delete mode 100644 vppinfra/vppinfra/test_random_isaac.c delete mode 100644 vppinfra/vppinfra/test_serialize.c delete mode 100644 vppinfra/vppinfra/test_slist.c delete mode 100644 vppinfra/vppinfra/test_socket.c delete mode 100644 vppinfra/vppinfra/test_time.c delete mode 100644 vppinfra/vppinfra/test_timing_wheel.c delete mode 100644 vppinfra/vppinfra/test_vec.c delete mode 100644 vppinfra/vppinfra/test_vec.h delete mode 100644 vppinfra/vppinfra/test_vhash.c delete mode 100644 vppinfra/vppinfra/test_zvec.c delete mode 100644 vppinfra/vppinfra/time.c delete mode 100644 vppinfra/vppinfra/time.h delete mode 100644 vppinfra/vppinfra/timer.c delete mode 100644 vppinfra/vppinfra/timer.h delete mode 100644 vppinfra/vppinfra/timing_wheel.c delete mode 100644 vppinfra/vppinfra/timing_wheel.h delete mode 100644 vppinfra/vppinfra/types.h delete mode 100644 vppinfra/vppinfra/unformat.c delete mode 100644 vppinfra/vppinfra/unix-formats.c delete mode 100644 vppinfra/vppinfra/unix-kelog.c delete mode 100644 vppinfra/vppinfra/unix-misc.c delete mode 100644 vppinfra/vppinfra/unix.h delete mode 100644 vppinfra/vppinfra/valgrind.h delete mode 100644 vppinfra/vppinfra/vec.c delete mode 100644 vppinfra/vppinfra/vec.h delete mode 100644 vppinfra/vppinfra/vec_bootstrap.h delete mode 100644 vppinfra/vppinfra/vector.c delete mode 100644 vppinfra/vppinfra/vector.h delete mode 100644 vppinfra/vppinfra/vector_altivec.h delete mode 100644 vppinfra/vppinfra/vector_funcs.h delete mode 100644 vppinfra/vppinfra/vector_iwmmxt.h delete mode 100644 vppinfra/vppinfra/vector_neon.h delete mode 100644 vppinfra/vppinfra/vector_sse2.h delete mode 100644 vppinfra/vppinfra/vhash.c delete mode 100644 vppinfra/vppinfra/vhash.h delete mode 100644 vppinfra/vppinfra/vm_linux_kernel.h delete mode 100644 vppinfra/vppinfra/vm_standalone.h delete mode 100644 vppinfra/vppinfra/vm_unix.h delete mode 100644 vppinfra/vppinfra/xxhash.h delete mode 100644 vppinfra/vppinfra/xy.h delete mode 100644 vppinfra/vppinfra/zvec.c delete mode 100644 vppinfra/vppinfra/zvec.h diff --git a/Makefile b/Makefile index 292b0d286c0..1b75779a92c 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ endif DEB_DEPENDS = curl build-essential autoconf automake bison libssl-dev ccache DEB_DEPENDS += debhelper dkms git libtool libganglia1-dev libapr1-dev dh-systemd -DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope +DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config DEB_DEPENDS += python-dev python-virtualenv python-pip lcov chrpath autoconf ifeq ($(OS_VERSION_ID),14.04) DEB_DEPENDS += openjdk-8-jdk-headless @@ -147,7 +147,7 @@ else @ln -s /usr/bin/ccache $(BR)/tools/ccache-bin/gcc @ln -s /usr/bin/ccache $(BR)/tools/ccache-bin/g++ endif - @make -C $(BR) V=$(V) is_build_tool=yes vppapigen-install + @make -C $(BR) V=$(V) is_build_tool=yes tools-install @touch $@ bootstrap: $(BR)/.bootstrap.ok diff --git a/build-data/packages/cavium-dpdk.mk b/build-data/packages/cavium-dpdk.mk deleted file mode 100644 index ce8ee228429..00000000000 --- a/build-data/packages/cavium-dpdk.mk +++ /dev/null @@ -1,55 +0,0 @@ -# Temporary until Cavium upstreams their work - -cavium-dpdk_configure = \ - src_dir=$(call find_source_fn,$(PACKAGE_SOURCE)) ; \ - dst_dir=$(PACKAGE_BUILD_DIR) ; \ - tar -C $${src_dir} -cf - . | tar -C $${dst_dir} -xf - ; \ - cd $${dst_dir} ; \ - : colossal hemorrhoid to configure headroom ; \ - if [ x$($(PACKAGE)_configure_args_$(PLATFORM)) = "x" ] ; then \ - HR=256 ; \ - else \ - dpdk_configure_args=$($(PACKAGE)_configure_args_$(PLATFORM)) ; \ - if [ $$dpdk_configure_args = "--with-headroom=256" ] ; then \ - HR=256 ; \ - elif [ $$dpdk_configure_args = "--with-headroom=384" ] ; then \ - HR=384 ; \ - else \ - HR=256 ; \ - fi ; \ - fi ; \ - env HR=$$HR \ - spp -o \ - $(PACKAGE_BUILD_DIR)/config/common_linuxapp \ - $(PACKAGE_BUILD_DIR)/config/common_linuxapp.spp \ - ; \ - env $(CONFIGURE_ENV) \ - make config T=arm64-thunderx-linuxapp-gcc RTE_ARCH=arm64 \ - CC=aarch64-thunderx-linux-gnu-gcc V=0 \ - RTE_SDK=$(PACKAGE_BUILD_DIR) \ - RTE_TARGET=arm-default-linuxapp-gcc - -# Note: add e.g. "-O0" to EXTRA_CFLAGS if desired: EXTRA_CFLAGS='-g -O0' - -cavium-dpdk_make_args = install T=arm64-thunderx-linuxapp-gcc RTE_ARCH=arm64 \ - CC=aarch64-thunderx-linux-gnu-gcc V=0 \ - RTE_SDK=$(PACKAGE_BUILD_DIR) \ - RTE_TARGET=arm-default-linuxapp-gcc - -cavium-dpdk_install = \ - src_dir=$(PACKAGE_BUILD_DIR) ; \ - dst_dir=$(PACKAGE_INSTALL_DIR) ; \ - tar -h -C $${src_dir}/arm64-thunderx-linuxapp-gcc -cf - . \ - | tar -C $${dst_dir} -xf - - -# dpdk libraries end up in .../lib not .../lib64. Fix it. -cavium-dpdk_post_install = \ - if [ "$(arch_lib_dir)" != "lib" ] ; then \ - mkdir -p $(PACKAGE_INSTALL_DIR)/$(arch_lib_dir) ; \ - cd $(PACKAGE_INSTALL_DIR)/lib ; \ - tar cf - . | ( cd $(PACKAGE_INSTALL_DIR)/$(arch_lib_dir); tar xf - ) ; \ - fi - -# nothing to install, all static libraries -cavium-dpdk_image_include = echo - diff --git a/build-data/packages/g2.mk b/build-data/packages/g2.mk index 258eff1daa4..9b760e63d1f 100644 --- a/build-data/packages/g2.mk +++ b/build-data/packages/g2.mk @@ -1,5 +1,3 @@ -g2_configure_depend = vppinfra-install +g2_source = src -g2_CPPFLAGS = $(call installed_includes_fn, vppinfra) - -g2_LDFLAGS = $(call installed_libs_fn, vppinfra) +g2_configure_args = --disable-vlib --disable-svm --enable-g2 diff --git a/build-data/packages/gmod.mk b/build-data/packages/gmod.mk index a6ba42d093b..6fa7e0f160f 100644 --- a/build-data/packages/gmod.mk +++ b/build-data/packages/gmod.mk @@ -1,9 +1,9 @@ -gmod_configure_depend = vppinfra-install svm-install +gmod_configure_depend = vpp-install gmod_configure_args = --libdir=$(PACKAGE_INSTALL_DIR)/$(arch_lib_dir)/ganglia -gmod_CPPFLAGS = $(call installed_includes_fn, vppinfra svm) +gmod_CPPFLAGS = $(call installed_includes_fn, vpp) gmod_CPPFLAGS += -I/usr/include/apr-1.0 -I/usr/include/apr-1 -I/usr/include -gmod_LDFLAGS = $(call installed_libs_fn, vppinfra svm) +gmod_LDFLAGS = $(call installed_libs_fn, vpp) gmod_image_include = echo $(arch_lib_dir)/ganglia/libgmodvpp.so etc diff --git a/build-data/packages/perftool.mk b/build-data/packages/perftool.mk index 300f902b08f..e582c316db1 100644 --- a/build-data/packages/perftool.mk +++ b/build-data/packages/perftool.mk @@ -1,5 +1,4 @@ -perftool_configure_depend = vppinfra-install +perftool_source = src -perftool_CPPFLAGS = $(call installed_includes_fn, vppinfra) +perftool_configure_args = --disable-vlib --disable-svm --enable-perftool -perftool_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-data/packages/plugins.mk b/build-data/packages/plugins.mk index 44a8e2bd141..b4d67a28abd 100644 --- a/build-data/packages/plugins.mk +++ b/build-data/packages/plugins.mk @@ -1,24 +1,13 @@ plugins_configure_depend = \ - vppinfra-install \ - vlib-api-install \ - vpp-api-test-install \ - vnet-install \ - vlib-install \ - vpp-api-install + vpp-api-install \ + vpp-install -plugins_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - vlib \ - vnet \ - svm \ - vpp-api-test \ - vlib-api \ - vpp-api) +plugins_CPPFLAGS = $(call installed_includes_fn, \ + vpp \ + vpp-api) -plugins_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - vlib \ - vlib-api) +plugins_LDFLAGS = $(call installed_libs_fn, \ + vpp) ifeq ($($(PLATFORM)_enable_tests),yes) plugins_configure_args += --enable-tests diff --git a/build-data/packages/src.mk b/build-data/packages/src.mk new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-data/packages/svm.mk b/build-data/packages/svm.mk deleted file mode 100644 index 3971fe82335..00000000000 --- a/build-data/packages/svm.mk +++ /dev/null @@ -1,5 +0,0 @@ -svm_top_srcdir = $(call find_source_fn,svm) -svm_configure_depend = vppinfra-install - -svm_CPPFLAGS = $(call installed_includes_fn, vppinfra) -svm_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-data/packages/vlib-api-cavium-dpdk.mk b/build-data/packages/vlib-api-cavium-dpdk.mk deleted file mode 100644 index 7a4fe2cd718..00000000000 --- a/build-data/packages/vlib-api-cavium-dpdk.mk +++ /dev/null @@ -1,6 +0,0 @@ -vlib-api-cavium-dpdk_source = vlib-api - -vlib-api-cavium-dpdk_configure_depend = vppinfra-install svm-install vlib-cavium-dpdk-install - -vlib-api-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, vppinfra svm vlib-cavium-dpdk) -vlib-api-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, vppinfra svm vlib-cavium-dpdk) diff --git a/build-data/packages/vlib-api.mk b/build-data/packages/vlib-api.mk deleted file mode 100644 index 29b0d17dba2..00000000000 --- a/build-data/packages/vlib-api.mk +++ /dev/null @@ -1,4 +0,0 @@ -vlib-api_configure_depend = vppinfra-install svm-install vlib-install - -vlib-api_CPPFLAGS = $(call installed_includes_fn, vppinfra svm vlib) -vlib-api_LDFLAGS = $(call installed_libs_fn, vppinfra svm vlib) diff --git a/build-data/packages/vlib-cavium-dpdk.mk b/build-data/packages/vlib-cavium-dpdk.mk deleted file mode 100644 index 0f2f132d05c..00000000000 --- a/build-data/packages/vlib-cavium-dpdk.mk +++ /dev/null @@ -1,7 +0,0 @@ -vlib-cavium-dpdk_source = vlib -vlib-cavium-dpdk_configure_depend = vppinfra-install cavium-dpdk-install - -vlib-cavium-dpdk_configure_args += --with-dpdk - -vlib-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, vppinfra cavium-dpdk) -vlib-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, vppinfra cavium-dpdk) diff --git a/build-data/packages/vlib.mk b/build-data/packages/vlib.mk deleted file mode 100644 index 2172708d07e..00000000000 --- a/build-data/packages/vlib.mk +++ /dev/null @@ -1,16 +0,0 @@ -vlib_configure_depend = vppinfra-install - -vlib_CPPFLAGS = $(call installed_includes_fn, vppinfra) -vlib_LDFLAGS = $(call installed_libs_fn, vppinfra) - -ifneq ($($(PLATFORM)_uses_dpdk),no) -vlib_configure_args += --with-dpdk -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -vlib_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -vlib_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -vlib_configure_depend += dpdk-install -vlib_CPPFLAGS += $(call installed_includes_fn, dpdk) -vlib_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -endif diff --git a/build-data/packages/vnet-cavium-dpdk.mk b/build-data/packages/vnet-cavium-dpdk.mk deleted file mode 100644 index 4c35b04dce8..00000000000 --- a/build-data/packages/vnet-cavium-dpdk.mk +++ /dev/null @@ -1,29 +0,0 @@ -vnet-cavium-dpdk_source = vnet - -vnet-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install - - -vnet-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk) - -vnet-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk) - -# Platform dependent configure flags -vnet-cavium-dpdk_configure_args += $(vnet-cavium-dpdk_configure_args_$(PLATFORM)) - diff --git a/build-data/packages/vpp-api-test-cavium-dpdk.mk b/build-data/packages/vpp-api-test-cavium-dpdk.mk deleted file mode 100644 index e352317ff8d..00000000000 --- a/build-data/packages/vpp-api-test-cavium-dpdk.mk +++ /dev/null @@ -1,32 +0,0 @@ -vpp-api-test-cavium-dpdk_source = vpp-api-test - -vpp-api-test-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install \ - vnet-cavium-dpdk-install \ - vpp-cavium-dpdk-install - -# -vpp-api-test-cavium-dpdk_configure_args = --with-dpdk - -vpp-api-test-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk \ - vpp-cavium-dpdk) - -vpp-api-test-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk \ - vpp-cavium-dpdk) - diff --git a/build-data/packages/vpp-api-test.mk b/build-data/packages/vpp-api-test.mk deleted file mode 100644 index c9eae367a12..00000000000 --- a/build-data/packages/vpp-api-test.mk +++ /dev/null @@ -1,39 +0,0 @@ -vpp-api-test_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ - vpp-install - -vpp-api-test_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ - vpp) - -vpp-api-test_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ - vpp) - -ifneq ($($(PLATFORM)_uses_dpdk),no) -vpp-api-test_configure_args = --with-dpdk -ifeq ($($(PLATFORM)_uses_external_dpdk),yes) -vpp-api-test_CPPFLAGS += -I$($(PLATFORM)_dpdk_inc_dir) -vpp-api-test_LDFLAGS += -L$($(PLATFORM)_dpdk_lib_dir) -else -vpp-api-test_configure_depend += dpdk-install -vpp-api-test_CPPFLAGS += $(call installed_includes_fn, dpdk) -vpp-api-test_LDFLAGS += $(call installed_libs_fn, dpdk) -endif -endif -ifeq ($($(PLATFORM)_uses_dpdk_cryptodev),yes) -vpp-api-test_configure_args += --with-dpdk-crypto -endif - diff --git a/build-data/packages/vpp-api.mk b/build-data/packages/vpp-api.mk index 4937023aceb..d9e8d72e182 100644 --- a/build-data/packages/vpp-api.mk +++ b/build-data/packages/vpp-api.mk @@ -1,23 +1,9 @@ vpp-api_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ vpp-install vpp-api_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet \ vpp) -vpp-api_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api) +vpp-api_LDFLAGS = vpp-api_CPPFLAGS += -I/usr/lib/jvm/java-8-openjdk-amd64/include diff --git a/build-data/packages/vpp-cavium-dpdk.mk b/build-data/packages/vpp-cavium-dpdk.mk deleted file mode 100644 index 704e3a95535..00000000000 --- a/build-data/packages/vpp-cavium-dpdk.mk +++ /dev/null @@ -1,30 +0,0 @@ -vpp-cavium-dpdk_source = vpp - -vpp-cavium-dpdk_configure_depend = \ - vppinfra-install \ - cavium-dpdk-install \ - svm-install \ - vlib-api-cavium-dpdk-install \ - vlib-cavium-dpdk-install \ - vnet-cavium-dpdk-install - -# Platform dependent configure flags -vpp-cavium-dpdk_configure_args += $(vpp-cavium-dpdk_configure_args_$(PLATFORM)) - -vpp-cavium-dpdk_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk) - -vpp-cavium-dpdk_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - cavium-dpdk \ - openssl \ - svm \ - vlib-cavium-dpdk \ - vlib-api-cavium-dpdk \ - vnet-cavium-dpdk) diff --git a/build-data/packages/vpp.mk b/build-data/packages/vpp.mk index a3d60528a01..fe68cd823a3 100644 --- a/build-data/packages/vpp.mk +++ b/build-data/packages/vpp.mk @@ -1,11 +1,5 @@ -vpp_configure_depend = \ - vppinfra-install \ - svm-install \ - vlib-api-install \ - vlib-install \ - vnet-install \ +vpp_source = src -# ifeq ($($(PLATFORM)_dpdk_shared_lib),yes) vpp_configure_args = --enable-dpdk-shared else @@ -16,25 +10,8 @@ endif vpp_configure_args += $(vpp_configure_args_$(PLATFORM)) -vpp_CPPFLAGS = $(call installed_includes_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet) - -vpp_LDFLAGS = $(call installed_libs_fn, \ - vppinfra \ - svm \ - vlib \ - vlib-api \ - vnet) - -# include & link with openssl only if needed -ifneq ($($(PLATFORM)_uses_openssl),no) -vpp_CPPFLAGS += $(call installed_includes_fn, openssl) -vpp_LDFLAGS += $(call installed_libs_fn, openssl) -endif +vpp_CPPFLAGS = +vpp_LDFLAGS = ifneq ($($(PLATFORM)_uses_dpdk),no) ifeq ($($(PLATFORM)_uses_external_dpdk),yes) diff --git a/build-data/packages/vppinfra.mk b/build-data/packages/vppinfra.mk deleted file mode 100644 index 6ca6eb24b92..00000000000 --- a/build-data/packages/vppinfra.mk +++ /dev/null @@ -1,5 +0,0 @@ - -ifeq ($($(PLATFORM)_enable_tests),yes) -vppinfra_configure_args += --enable-tests -endif - diff --git a/build-data/platforms.mk b/build-data/platforms.mk index a568c7a06a3..88dd3ed813b 100644 --- a/build-data/platforms.mk +++ b/build-data/platforms.mk @@ -60,15 +60,15 @@ install-deb: $(patsubst %,%-find-source,$(ROOT_PACKAGES)) deb/debian/vpp-dpdk-dev.install ; \ \ : bin package needs startup config ; \ - echo ../../vpp/conf/startup.conf /etc/vpp \ + echo ../../src/vpp/conf/startup.conf /etc/vpp \ >> deb/debian/vpp.install ; \ \ : and sysctl config ; \ - echo ../../vpp/conf/80-vpp.conf /etc/sysctl.d \ + echo ../../src/vpp/conf/80-vpp.conf /etc/sysctl.d \ >> deb/debian/vpp.install ; \ \ : dev package needs a couple of additions ; \ - echo ../build-tool-native/vppapigen/vppapigen /usr/bin \ + echo ../build-tool-native/tools/vppapigen /usr/bin \ >> deb/debian/vpp-dev.install ; \ echo ../../vpp-api/java/jvpp/gen/jvpp_gen.py /usr/bin \ >> deb/debian/vpp-dev.install ; \ diff --git a/build-data/platforms/vpp.mk b/build-data/platforms/vpp.mk index 97ddc57db71..513a4db40bc 100644 --- a/build-data/platforms/vpp.mk +++ b/build-data/platforms/vpp.mk @@ -29,11 +29,9 @@ vpp_uses_dpdk = yes # Uncoment to enable building unit tests # vpp_enable_tests = yes -vpp_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \ - vpp-api gmod plugins +vpp_root_packages = vpp vpp-api gmod plugins vpp_configure_args_vpp = --with-dpdk -vnet_configure_args_vpp = --with-dpdk # Set these parameters carefully. The vlib_buffer_t is 128 bytes, i.e. vlib_configure_args_vpp = --with-pre-data=128 diff --git a/build-data/platforms/vpp_lite.mk b/build-data/platforms/vpp_lite.mk index ef2ec4442f9..55805d1002a 100644 --- a/build-data/platforms/vpp_lite.mk +++ b/build-data/platforms/vpp_lite.mk @@ -27,8 +27,7 @@ vpp_lite_uses_dpdk = no # Uncoment to enable building unit tests #vpp_lite_enable_tests = yes -vpp_lite_root_packages = vpp vlib vlib-api vnet svm vpp-api-test \ - vpp-api gmod +vpp_lite_root_packages = vpp vpp-api gmod vlib_configure_args_vpp_lite = --with-pre-data=128 diff --git a/build-data/suffix-rules.mk b/build-data/suffix-rules.mk deleted file mode 100644 index e3eeb9220bf..00000000000 --- a/build-data/suffix-rules.mk +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Shared suffix rules -# Please do not set "SUFFIXES = .api.h .api" here - -%.api.h: %.api - @echo " APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ diff --git a/build-root/bootstrap.sh b/build-root/bootstrap.sh index f83734fd4af..2949c1806c2 100755 --- a/build-root/bootstrap.sh +++ b/build-root/bootstrap.sh @@ -45,7 +45,7 @@ cd $wsroot cd $build_root echo Compile native tools -for tool in vppapigen +for tool in tools do make V=0 is_build_tool=yes $tool-install done diff --git a/build-root/packages/src.mk b/build-root/packages/src.mk new file mode 100644 index 00000000000..db48ed58f03 --- /dev/null +++ b/build-root/packages/src.mk @@ -0,0 +1,4 @@ +# nothing + + + diff --git a/build-root/packages/tools.mk b/build-root/packages/tools.mk new file mode 100644 index 00000000000..506e024b727 --- /dev/null +++ b/build-root/packages/tools.mk @@ -0,0 +1,3 @@ +tools_source = src +tools_configure_args = --disable-vlib + diff --git a/build-root/packages/vppapigen.mk b/build-root/packages/vppapigen.mk deleted file mode 100644 index 0d284631979..00000000000 --- a/build-root/packages/vppapigen.mk +++ /dev/null @@ -1,5 +0,0 @@ -vppapigen_configure_depend = vppinfra-install - -vppapigen_CPPFLAGS = $(call installed_includes_fn, vppinfra) - -vppapigen_LDFLAGS = $(call installed_libs_fn, vppinfra) diff --git a/build-root/rpm/vpp.spec b/build-root/rpm/vpp.spec index 194d205fe7e..654424c083f 100644 --- a/build-root/rpm/vpp.spec +++ b/build-root/rpm/vpp.spec @@ -97,12 +97,10 @@ groupadd -f -r vpp mkdir -p -m755 %{buildroot}%{_bindir} mkdir -p -m755 %{buildroot}%{_unitdir} install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/*/bin/* %{buildroot}%{_bindir} -install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/vppapigen/vppapigen %{buildroot}%{_bindir} +install -p -m 755 %{_mu_build_dir}/%{_vpp_build_dir}/tools/vppapigen %{buildroot}%{_bindir} -# core api +# api mkdir -p -m755 %{buildroot}/usr/share/vpp/api -install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/vpp-api/vpe.api.json %{buildroot}/usr/share/vpp/api -install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vlib-api/vlibmemory/memclnt.api.json %{buildroot}/usr/share/vpp/api # # configs @@ -110,8 +108,8 @@ install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vlib-api/vlibmemory/memcl mkdir -p -m755 %{buildroot}/etc/vpp mkdir -p -m755 %{buildroot}/etc/sysctl.d install -p -m 644 %{_mu_build_dir}/rpm/vpp.service %{buildroot}%{_unitdir} -install -p -m 644 %{_mu_build_dir}/../vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf -install -p -m 644 %{_mu_build_dir}/../vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d +install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/startup.uiopcigeneric.conf %{buildroot}/etc/vpp/startup.conf +install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}/etc/sysctl.d # # libraries # @@ -128,7 +126,7 @@ do ( cd %{buildroot}%{_libdir} && ln -fs $file $(echo $file | sed -e 's/\(\.so\)\.[0-9]\+.*/\1/') ) done -for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vnet -type f -name '*.api.json' -print ) +for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/vpp/api -type f -name '*.api.json' -print ) do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done @@ -178,12 +176,24 @@ do %{buildroot}/usr/lib/vpp_plugins/$file done +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_plugins && find -type f -print) +do + install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_plugins/$file \ + %{buildroot}/usr/lib/vpp_plugins/$file +done + for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins && find -type f -print) do install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/plugins/lib64/vpp_api_test_plugins/$file \ %{buildroot}/usr/lib/vpp_api_test_plugins/$file done +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_api_test_plugins && find -type f -print) +do + install -p -m 644 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/lib64/vpp_api_test_plugins/$file \ + %{buildroot}/usr/lib/vpp_api_test_plugins/$file +done + for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/plugins -type f -name '*.api.json' -print ) do install -p -m 644 $file %{buildroot}/usr/share/vpp/api diff --git a/build-root/scripts/find-plugins-contents b/build-root/scripts/find-plugins-contents index a5a52acf337..4108f7905ea 100755 --- a/build-root/scripts/find-plugins-contents +++ b/build-root/scripts/find-plugins-contents @@ -2,14 +2,14 @@ rm -f $2 -for i in ${1}/plugins/lib64/vpp_plugins/*.so; do +for i in ${1}/{plugins,vpp}/lib64/vpp_plugins/*.so; do echo ../${i} /usr/lib/vpp_plugins >> ${2} done -for i in ${1}/plugins/lib64/vpp_api_test_plugins/*.so; do +for i in ${1}/{plugins,vpp}/lib64/vpp_api_test_plugins/*.so; do echo ../${i} /usr/lib/vpp_api_test_plugins >> ${2} done -for i in $(find ${1}/plugins -name *.api.json -type f -print); do +for i in $(find ${1}/plugins ${1}/vpp/share/vpp/api/plugins/ -name *.api.json -type f -print); do echo ../${i} /usr/share/vpp/api/ >> ${2} done diff --git a/build-root/scripts/find-python-api-contents b/build-root/scripts/find-python-api-contents index 9b390e75849..24e8532c670 100755 --- a/build-root/scripts/find-python-api-contents +++ b/build-root/scripts/find-python-api-contents @@ -2,7 +2,7 @@ rm -f $2 -for i in $(find ${1}/vpp-api/lib/python2.7/site-packages/ -type f -print); do +for i in $(find ${1}/{vpp,vpp-api}/lib/python2.7/site-packages/ -type f -print); do echo ../${i} /usr/lib/python2.7/site-packages/vpp_papi >> ${2} done diff --git a/g2/Makefile.am b/g2/Makefile.am deleted file mode 100644 index 8457c272fcd..00000000000 --- a/g2/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign - -bin_PROGRAMS = g2 - -AM_CFLAGS = -Wall - -g2_SOURCES = \ - clib.c \ - cpel.c \ - cpel.h \ - events.c \ - g2.h \ - main.c \ - menu1.c \ - pointsel.c \ - props.c \ - props.h \ - g2version.c \ - view1.c - -g2_LDADD = $(g2_LIBS) -lvppinfra -lpthread -lm diff --git a/g2/clib.c b/g2/clib.c deleted file mode 100644 index d0cd6195a5f..00000000000 --- a/g2/clib.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2009-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include "g2.h" - -int widest_track_format; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -elog_main_t elog_main; - -void *get_clib_event (unsigned int datum) -{ - elog_event_t *ep = vec_elt_at_index (elog_main.events, datum); - return (void *)ep; -} - -/* - * read_clib_file - */ -int read_clib_file(char *clib_file) -{ - static FILE *ofp; - clib_error_t *error = 0; - int i; - elog_main_t *em = &elog_main; - double starttime, delta; - - vec_free(em->events); - vec_free(em->event_types); - if (the_trackdef_hash) - hash_free(the_trackdef_hash); - - the_trackdef_hash = hash_create (0, sizeof (uword)); - - error = elog_read_file (&elog_main, clib_file); - - if (error) { - fformat(stderr, "%U", format_clib_error, error); - return (1); - } - - if (ofp == NULL) { - ofp = fdopen(2, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(2)?\n"); - exit(1); - } - } - - em = &elog_main; - - for (i = 0; i < vec_len (em->tracks); i++) { - u32 track_code; - bound_track_t * btp; - elog_track_t * t; - uword * p; - int track_strlen; - - t = &em->tracks[i]; - track_code = i; - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = t->name; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - track_strlen = strlen((char *)btp->track_str); - if (track_strlen > widest_track_format) - widest_track_format = track_strlen; - } - - initialize_events(); - - for (i = 0; i < vec_len (em->event_types); i++) { - elog_event_type_t *ep; - u8 *tmp; - - ep = vec_elt_at_index(em->event_types, i); - tmp = (u8 *) vec_dup(ep->format); - vec_add1(tmp,0); - add_event_from_clib_file (ep->type_index_plus_one, (char *) tmp, i); - vec_free(tmp); - } - - finalize_events(); - - em->events = elog_get_events (em); - - cpel_event_init(vec_len(em->events)); - - starttime = em->events[0].time; - - for (i = 0; i < vec_len (em->events); i++) { - elog_event_t *ep; - - ep = vec_elt_at_index(em->events, i); - - delta = ep->time - starttime; - - add_clib_event (delta, ep->track, ep->type + 1, i); - } - - cpel_event_finalize(); - - set_pid_ax_width(8*widest_track_format); - - return(0); -} diff --git a/g2/configure.ac b/g2/configure.ac deleted file mode 100644 index c8af7747b89..00000000000 --- a/g2/configure.ac +++ /dev/null @@ -1,12 +0,0 @@ -AC_INIT(g2, 3.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, - AC_MSG_ERROR([Please install the vpp-lib package])) -AC_CHECK_HEADER([vppinfra/clib.h],, - AC_MSG_ERROR([Please install the vpp-dev package])) - -PKG_CHECK_MODULES(g2, gtk+-2.0) - -AC_OUTPUT([Makefile]) diff --git a/g2/cpel.c b/g2/cpel.c deleted file mode 100644 index 8bcc91e674e..00000000000 --- a/g2/cpel.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include "g2.h" - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; -} bound_event_t; - -bound_event_t *bound_events; - -int widest_track_format=8; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ -u8 *event_strtab; /* event string-table */ - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - initialize_events(); - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - add_event_from_cpel_file(event_code, (char *) bp->event_str, - (char *)bp->datum_str); - - ep++; - } - - finalize_events(); - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int track_strlen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - track_strlen = strlen((char *)btp->track_str); - if (track_strlen > widest_track_format) - widest_track_format = track_strlen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - u32 event_code, track_code, datum; - u64 starttime = ~0ULL; - int nevents; - int i; - event_entry_t *ep; - u64 now; - u64 delta; - u32 time0, time1; - double d; - uword *p; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9; - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - event_strtab = (u8 *)p[0]; - - cpel_event_init(nevents); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_ns; - - now = d; - - if (starttime == ~0ULL) - starttime = now; - - delta = now - starttime; - - /* Delta = time since first event, in usec */ - event_code = ntohl(ep->event_code); - track_code = ntohl(ep->track); - datum = ntohl(ep->event_datum); - - add_cpel_event(delta, track_code, event_code, datum); - - ep++; - } - cpel_event_finalize(); - return(0); -} - -char *strtab_ref(unsigned long datum) -{ - return ((char *)(event_strtab + datum)); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - } - - return(0); -} - - -int cpel_process(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - - return(0); -} - -/* - * read_cpel_file - */ -int read_cpel_file(char *cpel_file) -{ - int verbose = 0; - int rv; - static u8 *cpel; - static unsigned long size; - static FILE *ofp; - - if (cpel) { - unmapfile((char *)cpel, size); - hash_free(the_strtab_hash); - the_strtab_hash = 0; - hash_free(the_evtdef_hash); - the_evtdef_hash = 0; - hash_free(the_trackdef_hash); - the_trackdef_hash = 0; - } - - cpel = (u8 *)mapfile((char *)cpel_file, &size); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (ofp == NULL) { - ofp = fdopen(2, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(2)?\n"); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - - rv = cpel_process(cpel, verbose, ofp); - - set_pid_ax_width(8*widest_track_format); - - return(rv); -} - -static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"}; -static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"}; - -/* - * get_track_label - */ -char *get_track_label(unsigned long track) -{ - uword *p; - bound_track_t *tp; - - p = hash_get(the_trackdef_hash, track); - if (p) { - tp = &bound_tracks[p[0]]; - } else { - if (track > 65535) - tp = &generic_hex_track; - else - tp = &generic_decimal_track; - } - return((char *)tp->track_str); -} diff --git a/g2/cpel.h b/g2/cpel.h deleted file mode 100644 index 73e4aea5755..00000000000 --- a/g2/cpel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _CPEL_H_ -#define _CPEL_H_ 1 - -typedef struct cpel_file_header_ { - unsigned char endian_version; - unsigned char pad; - unsigned short nsections; - unsigned file_date; -} cpel_file_header_t; - -#define CPEL_FILE_LITTLE_ENDIAN 0x80 -#define CPEL_FILE_VERSION 0x01 -#define CPEL_FILE_VERSION_MASK 0x7F - -typedef struct cpel_section_header_ { - unsigned int section_type; - unsigned int data_length; /* does NOT include type and itself */ -} cpel_section_header_t; - -#define CPEL_SECTION_STRTAB 1 -/* string at offset 0 is the name of the table */ - -#define CPEL_SECTION_SYMTAB 2 -#define CPEL_SECTION_EVTDEF 3 - -typedef struct event_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_event_definitions; -} event_definition_section_header_t; - -typedef struct event_definition_ { - unsigned int event; - unsigned int event_format; - unsigned int datum_format; -} event_definition_t; - -#define CPEL_SECTION_TRACKDEF 4 - -typedef struct track_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_track_definitions; -} track_definition_section_header_t; - -typedef struct track_definition_ { - unsigned int track; - unsigned int track_format; -} track_definition_t; - -#define CPEL_SECTION_EVENT 5 - -typedef struct event_section_header_ { - char string_table_name[64]; - unsigned int number_of_events; - unsigned int clock_ticks_per_second; -} event_section_header_t; - -typedef struct event_entry_ { - unsigned int time[2]; - unsigned int track; - unsigned int event_code; - unsigned int event_datum; -} event_entry_t; - -#define CPEL_NUM_SECTION_TYPES 5 - -#endif /* _CPEL_H_ */ - diff --git a/g2/events.c b/g2/events.c deleted file mode 100644 index d4333bb05d1..00000000000 --- a/g2/events.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "g2.h" -#include -#include -#include -#include - -/* - * globals - */ -boolean g_little_endian; -event_t *g_events; -ulong g_nevents; -pid_sort_t *g_pids; -pid_sort_t *g_original_pids; -int g_npids; -pid_data_t *g_pid_data_list; - -/* - * locals - */ -pid_data_t **s_pidhash; - -/* - * config parameters - */ - -double ticks_per_ns=1000.0; -boolean ticks_per_ns_set; - -/**************************************************************************** -* event_init -****************************************************************************/ - -void event_init(void) -{ - ulong endian; - char *ep; - char *askstr; - int tmp; - - ep = (char *)&endian; - endian = 0x12345678; - if (*ep != 0x12) - g_little_endian = TRUE; - else - g_little_endian = FALSE; - - askstr = getprop("dont_ask_ticks_per_ns_initially"); - - if (askstr && (*askstr == 't' || *askstr == 'T')) { - tmp = atol(getprop_default("ticks_per_ns", 0)); - if (tmp > 0) { - ticks_per_ns = tmp; - ticks_per_ns_set = TRUE; - } - } -} - -/**************************************************************************** -* find_or_add_pid -****************************************************************************/ - -pid_data_t *find_or_add_pid (ulong pid) -{ - pid_data_t *pp; - ulong bucket; - - bucket = pid % PIDHASH_NBUCKETS; - - pp = s_pidhash[bucket]; - - if (pp == 0) { - pp = g_malloc0(sizeof(pid_data_t)); - pp->pid_value = pid; - s_pidhash[bucket] = pp; - g_npids++; - return(pp); - } - while (pp) { - if (pp->pid_value == pid) - return(pp); - pp = pp->next; - } - - pp = g_malloc0(sizeof(pid_data_t)); - pp->pid_value = pid; - pp->next = s_pidhash[bucket]; - s_pidhash[bucket] = pp; - g_npids++; - return(pp); -} - -/**************************************************************************** -* pid_cmp -****************************************************************************/ - -int pid_cmp(const void *a1, const void *a2) -{ - pid_sort_t *p1 = (pid_sort_t *)a1; - pid_sort_t *p2 = (pid_sort_t *)a2; - - if (p1->pid_value < p2->pid_value) - return(-1); - else if (p1->pid_value == p2->pid_value) - return(0); - else - return(1); -} - -/**************************************************************************** -* make_sorted_pid_vector -****************************************************************************/ - -static void make_sorted_pid_vector(void) -{ - pid_data_t *pp; - pid_data_t **p_previous; - pid_sort_t *psp; - int i; - - psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids); - - for (i = 0; i < PIDHASH_NBUCKETS; i++) { - pp = s_pidhash[i]; - while(pp) { - psp->pid = pp; - psp->pid_value = pp->pid_value; - psp++; - pp = pp->next; - } - } - - qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); - - /* put the sort order into the pid objects */ - psp = g_pids; - - /* - * This is rather gross. - * - * We happen to know that whenever this function is called, the hash table - * structure itself is immediately torn down. So the "next" pointers in the - * pid_data_t elements are about to become useless. - * - * So we re-use them, to link all the pid_data_t elements together into a - * single unified linked list, with g_pid_data_list pointing to the head. - * This means we can walk all the pid_data_t objects if we really want to. - * Reading snapshots from disk is one example. - * - * Alternatively we could just leave the hash table in place; this is - * far nicer, but as it happens, trading O(n) lookups for O(1) lookups - * isn't actually a problem for the restricted post-tear-down usage. So for - * now we take the memory savings and swap our hash table for a list. - */ - p_previous = &g_pid_data_list; - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - *p_previous = pp; - p_previous = &pp->next; - psp++; - } - *p_previous = NULL; - - /* - * Squirrel away original (sorted) vector, so we can - * toggle between "chase" mode, snapshots, and the original - * display method on short notice - */ - g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids); - memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); -} - -/**************************************************************************** -* read_events -****************************************************************************/ - -void read_events(char *filename) -{ - ulong *ulp; - ulong size; - event_t *ep; - raw_event_t *rep; - ulonglong start_time=0ULL; - ulonglong low_time; - boolean once=TRUE; - int i; - char tmpbuf [128]; - - ulp = (ulong *)mapfile(filename, &size); - - if (ulp == NULL) { - sprintf(tmpbuf, "Couldn't open %s\n", filename); - infobox("Read Event Log Failure", tmpbuf); - return; - } - - g_nevents = ntohl(*ulp); - - if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { - sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename); - infobox("Bad Input File", tmpbuf); - g_nevents = 0; - unmapfile((char *)ulp, size); - return; - } - - rep = (raw_event_t *)(ulp+1); - - if (g_events) - g_free(g_events); - - g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); - ep = g_events; - - while (g_npids > 0) { - g_free((g_pids + g_npids-1)->pid); - g_npids--; - } - if (g_pids) { - g_free(g_pids); - g_free(g_original_pids); - g_pids = 0; - g_original_pids = 0; - } - - s_pidhash = (pid_data_t **)g_malloc0( - PIDHASH_NBUCKETS*sizeof(pid_data_t *)); - - /* $$$ add a SEGV handler... */ - for (i = 0; i < g_nevents; i++) { - if (once) { - once = FALSE; - start_time = ((ulonglong)ntohl(rep->time[0])); - start_time <<= 32; - low_time = ntohl(rep->time[1]); - low_time &= 0xFFFFFFFF; - start_time |= low_time; - ep->time = 0LL; - } else { - ep->time = ((ulonglong)ntohl(rep->time[0])); - ep->time <<= 32; - low_time = ntohl(rep->time[1]); - low_time &= 0xFFFFFFFF; - ep->time |= low_time; - ep->time -= start_time; - ep->time /= ticks_per_ns; - } - ep->code = ntohl(rep->code); - ep->pid = find_or_add_pid(ntohl(rep->pid)); - ep->datum = ntohl(rep->datum); - ep->flags = 0; - ep++; - rep++; - } - - unmapfile((char *)ulp, size); - - make_sorted_pid_vector(); - g_free(s_pidhash); - s_pidhash = 0; - - /* Give the view-1 world a chance to reset a few things... */ - view1_read_events_callback(); -} - -static event_t *add_ep; - -/**************************************************************************** -* cpel_event_init -****************************************************************************/ -void cpel_event_init (ulong nevents) -{ - g_nevents = nevents; - if (g_events) - g_free(g_events); - add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); - while (g_npids > 0) { - g_free((g_pids + g_npids-1)->pid); - g_npids--; - } - if (g_pids) { - g_free(g_pids); - g_free(g_original_pids); - g_pids = 0; - g_original_pids = 0; - } - s_pidhash = (pid_data_t **)g_malloc0( - PIDHASH_NBUCKETS*sizeof(pid_data_t *)); -} - -/**************************************************************************** -* add_cpel_event -****************************************************************************/ - -void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) -{ - event_t *ep; - - ep = add_ep++; - ep->time = delta; - ep->pid = find_or_add_pid(track); - ep->code = event; - ep->datum = datum; - ep->flags = 0; -} - -/**************************************************************************** -* add_clib_event -****************************************************************************/ - -void add_clib_event(double delta, unsigned short track, - unsigned short event, unsigned int index) -{ - event_t *ep; - - ep = add_ep++; - ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */ - ep->pid = find_or_add_pid(track); - ep->code = event; - ep->datum = index; - ep->flags = EVENT_FLAG_CLIB; -} - -/**************************************************************************** -* cpel_event_finalize -****************************************************************************/ - -void cpel_event_finalize(void) -{ - make_sorted_pid_vector(); - g_free(s_pidhash); - s_pidhash = 0; - - /* Give the view-1 world a chance to reset a few things... */ - view1_read_events_callback(); -} - -/**************************************************************************** -* mapfile -****************************************************************************/ - -char *mapfile (char *file, ulong *sizep) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - return (NULL); - - if (fstat (maphfile, &statb) < 0) { - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) { - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) { - g_error ("%s mapping problem, I quit...\n", file); - } - - close (maphfile); - - if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { - return (rv); - } - - if (sizep) { - *sizep = mapfsize; - } - return (rv); -} - -/**************************************************************************** -* unmapfile -****************************************************************************/ - -boolean unmapfile (char *addr, ulong size) -{ - if (munmap (addr, size) < 0) { - g_warning("Unmap error, addr 0x%lx size 0x%x\n", - (unsigned long) addr, (unsigned int)size); - return(FALSE); - } - return(TRUE); -} - -/**************************************************************************** -* find_event_index -* Binary search for first event whose time is >= t -****************************************************************************/ - -int find_event_index (ulonglong t) -{ - int index, bottom, top; - event_t *ep; - - bottom = g_nevents-1; - top = 0; - - while (1) { - index = (bottom + top) / 2; - - ep = (g_events + index); - - if (ep->time == t) - return(index); - - if (top >= bottom) { - while (index > 0 && ep->time > t) { - ep--; - index--; - } - while (index < g_nevents && ep->time < t) { - ep++; - index++; - } - return(index); - } - - if (ep->time < t) - top = index + 1; - else - bottom = index - 1; - } -} - -/**************************************************************************** -* events_about -****************************************************************************/ - -void events_about (char *tmpbuf) -{ - sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", - (int)g_nevents, ticks_per_ns); -} diff --git a/g2/g2.h b/g2/g2.h deleted file mode 100644 index 1ab42191ca9..00000000000 --- a/g2/g2.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * typedefs and so forth - */ -#include -#include -#include -#include "props.h" - -typedef char boolean; -typedef unsigned long long ulonglong; - -/* - * main.c - */ - -GtkWidget *g_mainwindow; -GtkWidget *g_mainvbox; -GtkWidget *g_mainhbox; - -/* - * pointsel.c - */ -void point_selector_init(void); -boolean read_event_definitions (char *filename); -char *sxerox(char *); -void pointsel_about(char *); -void pointsel_next_snapshot(void); -void initialize_events(void); -void finalize_events(void); - -#define NEVENTS 100000 - -typedef struct event_def_ { - ulong event; - char *name; - char *format; - boolean selected; - boolean is_clib; - char pad[2]; -} event_def_t; - -event_def_t *find_event_definition (ulong code); - -event_def_t g_eventdefs[NEVENTS]; - -/* - * config params - */ -int c_maxpointsel; /* max # points shown in selector dlg */ -gint c_view1_draw_width; -gint c_view1_draw_height; - -/* - * menu1.c - */ - -void menu1_init(void); -void modal_dialog (char *label_text, char *retry_text, char *default_value, - boolean (*cb)(char *)); -void infobox(char *label_text, char *text); -/* - * view1.c - */ -GdkFont *g_font; -GdkColor fg_black, bg_white; -void view1_init(void); -void view1_display(void); -void view1_read_events_callback(void); -void view1_display_when_idle(void); -void view1_print_callback(GtkToggleButton *item, gpointer data); -void view1_about(char *); -void set_pid_ax_width(int width); -void set_window_title(const char *filename); - -enum view1_tbox_fn { - TBOX_DRAW_BOXED = 1, /* note: order counts */ - TBOX_DRAW_EVENT, - TBOX_DRAW_PLAIN, - TBOX_PRINT_BOXED, - TBOX_PRINT_EVENT, - TBOX_PRINT_PLAIN, /* end restriction */ - TBOX_GETRECT_BOXED, - TBOX_GETRECT_EVENT, - TBOX_GETRECT_PLAIN, -}; - -enum view1_line_fn { - LINE_DRAW_BLACK = 1, - LINE_DRAW_WHITE, - LINE_PRINT, -}; - -GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function); -void line (int x1, int y1, int x2, int y2, enum view1_line_fn function); -gint view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event); - -/* - * events.c - */ - -void events_about (char *); - -typedef struct raw_event { - unsigned long time[2]; - unsigned long pid; - unsigned long code; - unsigned long datum; -} raw_event_t; - -void event_init(void); -char *mapfile (char *file, ulong *sizep); -boolean unmapfile (char *addr, ulong size); -void read_events (char *); -int find_event_index (ulonglong t); -int read_cpel_file(char *file); -int read_clib_file(char *file); -void cpel_event_init(ulong); -void add_event_from_cpel_file(ulong, char * , char *); -void add_event_from_clib_file(unsigned int event, char *name, - unsigned int vec_index); -void add_cpel_event(ulonglong delta, ulong, ulong, ulong); -void add_clib_event(double delta, unsigned short track, - unsigned short event, unsigned int index); -void cpel_event_finalize(void); -void *get_clib_event (unsigned int datum); - -typedef struct pid_data { - struct pid_data *next; - ulong pid_value; /* The actual pid value */ - ulong pid_index; /* Index in pid sort order */ -} pid_data_t; - -#define EVENT_FLAG_SELECT 0x00000001 /* This event is selected */ -#define EVENT_FLAG_SEARCHRSLT 0x00000002 /* This event is the search rslt */ -#define EVENT_FLAG_CLIB 0x00000004 /* clib event */ - -typedef struct pid_sort { - struct pid_data *pid; - ulong pid_value; - /* - * This is a bit of a hack, since this is used only by the view: - */ - unsigned color_index; -} pid_sort_t; - -typedef struct event { - ulonglong time; - ulong code; - pid_data_t *pid; - ulong datum; - ulong flags; -} event_t; - - -boolean g_little_endian; -event_t *g_events; -ulong g_nevents; -pid_sort_t *g_pids; -pid_sort_t *g_original_pids; -int g_npids; -pid_data_t *g_pid_data_list; - -#define PIDHASH_NBUCKETS 20021 /* Should be prime */ - -boolean ticks_per_ns_set; -double ticks_per_ns; - -/* - * version.c - */ -const char *version_string; -const char *minor_v_string; - -/* - * cpel.c - */ -char *get_track_label(unsigned long); -int widest_track_format; -char *strtab_ref(unsigned long); diff --git a/g2/g2version.c b/g2/g2version.c deleted file mode 100644 index 4b6f9313fee..00000000000 --- a/g2/g2version.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const char *version_string = "G2 (x86_64 GNU/Linux) major version 3.0"; -const char *minor_v_string = - "Built Wed Feb 3 10:58:12 EST 2016"; diff --git a/g2/main.c b/g2/main.c deleted file mode 100644 index a782e17f2ef..00000000000 --- a/g2/main.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "g2.h" -#include "props.h" -#include -#include -#include -#include -#include - -/* - * globals - */ - -GtkWidget *g_mainwindow; /* The main window */ - -/* Graphical object heirarchy - * - * [main window] - * [main vbox] - * [main (e.g. file) menubar] - * [view hbox] - * [view bottom menu] - */ - -GtkWidget *g_mainvbox; -GtkWidget *g_mainhbox; - -gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) -{ - /* Allow window to be destroyed */ - return(FALSE); -} - -void destroy(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -int main (int argc, char **argv) -{ - char tmpbuf [128]; - struct passwd *pw; - char *event_file = 0; - char *cpel_file = 0; - char *clib_file =0; - char *title = "none"; - int curarg=1; - char *homedir; - - gtk_init(&argc, &argv); - - homedir = getenv ("HOME"); - tmpbuf[0] = 0; - - if (homedir) { - sprintf(tmpbuf, "%s/.g2", homedir); - } else { - pw = getpwuid(geteuid()); - if (pw) { - sprintf(tmpbuf, "%s/.g2", pw->pw_dir); - } - } - if (tmpbuf[0]) - readprops(tmpbuf); - - g_mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT(g_mainwindow), "delete_event", - GTK_SIGNAL_FUNC (delete_event), NULL); - - gtk_signal_connect (GTK_OBJECT(g_mainwindow), "destroy", - GTK_SIGNAL_FUNC (destroy), NULL); - - gtk_container_set_border_width(GTK_CONTAINER(g_mainwindow), 5); - - g_mainvbox = gtk_vbox_new(FALSE, 0); - g_mainhbox = gtk_hbox_new(FALSE, 0); - - /* - * init routines - */ - - menu1_init(); - point_selector_init(); - view1_init(); - event_init(); - - /* - * Now that we're ready to rock 'n roll, see if we've been asked to - * press a few buttons... - */ - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--cpel-input", 4)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - break; - } - g_error("Missing filename after --cpel-input"); - } - if (!strncmp(argv[curarg], "--clib-input", 4)) { - curarg++; - if (curarg < argc) { - clib_file = argv[curarg]; - curarg++; - break; - } - g_error("Missing filename after --cpel-input"); - } - - if (!strncmp(argv[curarg], "--pointdefs", 3)) { - curarg++; - if (curarg < argc) { - read_event_definitions(argv[curarg]); - curarg++; - continue; - } - g_error ("Missing filename after --pointdefs\n"); - } - if (!strncmp(argv[curarg], "--event-log", 3)) { - curarg++; - if (curarg < argc) { - event_file = argv[curarg]; - curarg++; - continue; - } - g_error ("Missing filename after --event-log\n"); - } - - if (!strncmp(argv[curarg], "--ticks-per-us", 3)) { - curarg++; - if (curarg < argc) { - ticks_per_ns = 0.0; - ticks_per_ns = atof(argv[curarg]); - if (ticks_per_ns == 0.0) { - g_error("ticks-per-ns (%s) didn't convert properly\n", - argv[curarg]); - } - ticks_per_ns_set = TRUE; - curarg++; - continue; - } - g_error ("Missing filename after --event-log\n"); - } - - fprintf(stderr, - "g2 [--pointdefs ] [--event-log ]\n"); - fprintf(stderr, " [--ticks-per-us ]\n"); - fprintf(stderr, - " [--cpel-input ] [--clib-input \n"); - fprintf(stderr, - "%s\n%s\n", version_string, minor_v_string); - exit(0); - } - - if (clib_file) { - read_clib_file (clib_file); - title = clib_file; - } else if (cpel_file) { - read_cpel_file(cpel_file); - title = cpel_file; - } else if (event_file) { - read_events(event_file); - title = event_file; - } - - set_window_title(title); - - gtk_signal_connect (GTK_OBJECT (g_mainwindow), "key_press_event", - (GtkSignalFunc) view1_handle_key_press_event, NULL); - gtk_container_add(GTK_CONTAINER(g_mainvbox), g_mainhbox); - gtk_widget_show(g_mainhbox); - gtk_container_add(GTK_CONTAINER(g_mainwindow), g_mainvbox); - gtk_widget_show(g_mainvbox); - gtk_widget_show(g_mainwindow); - - gtk_main(); - return(0); -} diff --git a/g2/menu1.c b/g2/menu1.c deleted file mode 100644 index fce81fa66b2..00000000000 --- a/g2/menu1.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#define GTK_ENABLE_BROKEN // DGMS -#include -#include -#include "g2.h" -#include - -/* - * locals - */ -static GtkWidget *s_mainmenubar; -static GtkWidget *s_filemenu; -static GtkWidget *s_readdefs; -static GtkWidget *s_readevents; -static GtkWidget *s_readeventsclock; -static GtkWidget *s_readcpel; -static GtkWidget *s_readclib; -static GtkWidget *s_print; -static GtkWidget *s_quit; - -static GtkWidget *s_mainfilemenu; -static GtkWidget *s_help_general; -static GtkWidget *s_help_about; -static GtkWidget *s_mainhelpmenu; -static GtkWidget *s_helpmenu; - -static GtkWidget *s_filesel; -static GtkWidget *s_eventsel; - -typedef struct md_ { - GtkWidget *entry; - GtkWidget *label; - GtkWidget *dialog; - boolean (*callback)(char *); - char *retry_text; -} md_t; - -char *general_help = "\n" -"G2 is a performance event visualization tool.\n" -"\n" -"To view CPEL-format event data:\n" -"g2 --cpel \n" -"or use the File Menu->Read CPEL file option.\n" -"\n" -"To view vppinfra-format (.../open-repo/vppinfra/vppinfra/elog.h) event data:\n" -"g2 --clib \n" -"or use the File Menu->Read clib file option.\n" -"\n" -"To toggle event detail boxes, left-mouse-click on an event.\n" -"\n" -"To zoom to an area, depress the left mouse button. Move the\n" -"mouse. Release the mouse.\n" -"\n" -"To use the time ruler, depress the right mouse button. Move the\n" -"mouse. Release when done.\n" -"\n" -"To push a track to the bottom, \n" -"\n" -"To pull a track to the top, \n" -"\n" -"To selectively color/uncolor a track, \n" -"\n" -"To make the mouse scrollwheel faster, press \n" -"\n" -"Hotkeys, supposedly Quake-like:\n" -" w - zoom-in\n" -" s - zoom-out\n" -" a - pan-left\n" -" d - pan-right\n" -" r - pan-up\n" -" f - pan-down\n" -" t - less traces\n" -" g - more traces\n" -"\n" -" e - toggle summary-mode\n" -" c - toggle color-mode\n" -"\n" -" x - take snapshot\n" -" z - go to next snapshot\n" -" p - put snapshots to snapshots.g2 \n" -" l - load snapshots from snapshots.g2\n" -"\n" -"q - quit\n" -"Send comments / bug reports to the \"fd.io\" mailing list.\n"; - -/**************************************************************************** -* debug_dialog_callback -****************************************************************************/ - -boolean debug_dialog_callback (char *s) -{ - g_print("Dialog result: %s", s); - return (TRUE); -} - -/**************************************************************************** -* get_dialog_value -****************************************************************************/ - -static void get_dialog_value (GtkWidget *dialog, gpointer user_data) -{ - md_t *md = (md_t *)user_data; - char * cb_arg; - - cb_arg = (char *) gtk_entry_get_text(GTK_ENTRY(md->entry)); - - if ((*md->callback)(cb_arg)) { - gtk_grab_remove(md->dialog); - gtk_widget_destroy(md->dialog); - } else { - gtk_label_set_text (GTK_LABEL(md->label), md->retry_text); - } -} - -/**************************************************************************** -* modal_dialog -****************************************************************************/ - -void modal_dialog (char *label_text, char *retry_text, char *default_value, - boolean (*cb)(char *)) -{ - GtkWidget *dialog, *label, *ok_button, *entry; - static md_t dlg; - md_t *md = &dlg; - - dialog = gtk_dialog_new(); - label = gtk_label_new(label_text); - - entry = gtk_entry_new(); - if (default_value) - gtk_entry_set_text(GTK_ENTRY(entry), default_value); - - ok_button = gtk_button_new_with_label("OK"); - - md->entry = entry; - md->label = label; - md->retry_text = retry_text; - md->dialog = dialog; - if (cb) - md->callback = cb; - else - md->callback = debug_dialog_callback; - - gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", - GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); - - gtk_signal_connect (GTK_OBJECT (entry), "activate", - GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - entry); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - ok_button); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show_all(dialog); - gtk_widget_grab_focus(entry); - gtk_grab_add(dialog); -} - -/**************************************************************************** -* get_eventdef_name -****************************************************************************/ - -static void get_eventdef_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_event_definitions(filename); - set_window_title(filename); -} - -/**************************************************************************** -* read_eventdef_callback -****************************************************************************/ - -static void read_eventdef_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read Event Definitions From..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "../h/elog.h"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_eventdef_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* get_events_name -****************************************************************************/ - -static void get_events_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_eventsel)); - read_events(filename); - view1_display_when_idle(); -} - - -/**************************************************************************** -* get_ticks_per_ns -****************************************************************************/ - -static boolean get_ticks_per_ns (char *value) -{ - double rv; - - rv = atof (value); - - if (rv == 0.0 || rv > 100000) - return(FALSE); - - ticks_per_ns = rv; - ticks_per_ns_set = TRUE; - - gtk_widget_show(s_eventsel); - return(TRUE); -} - -/**************************************************************************** -* read_events_callback -****************************************************************************/ - -static void read_events_callback(GtkToggleButton *item, gpointer data) -{ - char tmpbuf [32]; - - s_eventsel = gtk_file_selection_new("Read Events From..."); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_events_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_eventsel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_eventsel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_eventsel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_eventsel)); - - if (ticks_per_ns_set) - gtk_widget_show (s_eventsel); - else { - sprintf(tmpbuf, "%.3f", ticks_per_ns); - modal_dialog ("Please enter clock ticks per nanosecond", - "Invalid: Please enter clock ticks per nanosecond", - tmpbuf, get_ticks_per_ns); - } -} - -/**************************************************************************** -* read_eventclock_callback -****************************************************************************/ - -static void read_eventsclock_callback(GtkToggleButton *item, gpointer data) -{ - ticks_per_ns_set = FALSE; - read_events_callback(item, data); -} - -/**************************************************************************** -* infobox_size_request -****************************************************************************/ - -void infobox_size_request (GtkWidget *widget, GtkRequisition *req, - gpointer user_data) -{ - char *text = (char *)user_data; - char *cp; - int widest_line_in_chars; - int w; - int nlines; - - /* - * You'd think that the string extent function would work here. - * You'd be wrong. - */ - nlines = w = widest_line_in_chars = 0; - for (cp = text; *cp; cp++) { - if (*cp == '\n') { - if (w > widest_line_in_chars) { - widest_line_in_chars = w; - } - w = 0; - nlines++; - } - w++; - } - - nlines++; - - req->width = (widest_line_in_chars * 8) + 20; - req->height = (nlines * 13) + 10; -} - -/**************************************************************************** -* infobox -****************************************************************************/ - -void infobox(char *label_text, char *text) -{ - GtkWidget *dialog, *label, *ok_button, *entry; - GtkWidget *box; - - dialog = gtk_dialog_new(); - label = gtk_label_new(label_text); - - entry = gtk_text_new(NULL, NULL); - - gtk_signal_connect (GTK_OBJECT (entry), "size-request", - GTK_SIGNAL_FUNC(infobox_size_request), - (gpointer) text); - - gtk_text_insert(GTK_TEXT(entry), g_font, &fg_black, &bg_white, - text, -1); - - gtk_text_set_editable(GTK_TEXT(entry), FALSE); - - ok_button = gtk_button_new_with_label("OK"); - - gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - (gpointer) GTK_OBJECT(dialog)); - - box = gtk_vbox_new(FALSE, 5); - - - gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box), ok_button, FALSE, FALSE, 0); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), - box); - - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); - gtk_widget_show_all(dialog); -} - -/**************************************************************************** -* help_general_callback -****************************************************************************/ - -static void help_general_callback(GtkToggleButton *item, gpointer data) -{ - infobox("General Help", general_help); -} - -/**************************************************************************** -* help_about_callback -****************************************************************************/ - -static void help_about_callback(GtkToggleButton *item, gpointer data) -{ - char tmpbuf [1024]; - sprintf (tmpbuf, "G2 -- Graphical Event Viewer\n\n"); - view1_about(tmpbuf); - pointsel_about(tmpbuf); - events_about(tmpbuf); - sprintf (tmpbuf+strlen(tmpbuf), "\n%s\n", version_string); - sprintf (tmpbuf+strlen(tmpbuf), "%s\n", minor_v_string); - infobox("About", tmpbuf); -} - - -/**************************************************************************** -* get_cpel_name -****************************************************************************/ - -static void get_cpel_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *)gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_cpel_file(filename); - set_window_title(filename); -} - -/**************************************************************************** -* get_clib_name -****************************************************************************/ - -static void get_clib_name (GtkFileSelection *sel, gpointer user_data) -{ - char *filename = (char *) gtk_file_selection_get_filename ( - GTK_FILE_SELECTION(s_filesel)); - read_clib_file(filename); - set_window_title(filename); -} - -/**************************************************************************** -* read_cpel_callback -****************************************************************************/ - -static void read_cpel_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read CPEL data from..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "cpel.out"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_cpel_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* read_clib_callback -****************************************************************************/ - -static void read_clib_callback(GtkToggleButton *item, gpointer data) -{ - - s_filesel = gtk_file_selection_new("Read clib data From..."); - - gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), - "clib.out"); - - gtk_signal_connect (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC(get_clib_name), NULL); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->ok_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - - gtk_signal_connect_object (GTK_OBJECT ( - GTK_FILE_SELECTION(s_filesel)->cancel_button), - "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - (gpointer) s_filesel); - gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); - gtk_widget_show (s_filesel); -} - -/**************************************************************************** -* menu1_init -****************************************************************************/ - -void menu1_init(void) -{ - - s_filemenu = gtk_menu_new(); - - s_readcpel = gtk_menu_item_new_with_label - ("Read CPEL file"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readcpel); - gtk_signal_connect(GTK_OBJECT(s_readcpel), "activate", - GTK_SIGNAL_FUNC(read_cpel_callback), 0); - - s_readclib = gtk_menu_item_new_with_label - ("Read CLIB file"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readclib); - gtk_signal_connect(GTK_OBJECT(s_readclib), "activate", - GTK_SIGNAL_FUNC(read_clib_callback), 0); - - s_readdefs = gtk_menu_item_new_with_label ("Read Event Definitions"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readdefs); - gtk_signal_connect(GTK_OBJECT(s_readdefs), "activate", - GTK_SIGNAL_FUNC(read_eventdef_callback), 0); - - s_readevents = gtk_menu_item_new_with_label ("Read Event Log"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readevents); - gtk_signal_connect(GTK_OBJECT(s_readevents), "activate", - GTK_SIGNAL_FUNC(read_events_callback), 0); - - s_readeventsclock = gtk_menu_item_new_with_label - ("Read Event Log with Different Clock Rate"); - gtk_menu_append(GTK_MENU(s_filemenu), s_readeventsclock); - gtk_signal_connect(GTK_OBJECT(s_readeventsclock), "activate", - GTK_SIGNAL_FUNC(read_eventsclock_callback), 0); - - s_print = gtk_menu_item_new_with_label ("Print"); - gtk_menu_append(GTK_MENU(s_filemenu), s_print); - gtk_signal_connect(GTK_OBJECT(s_print), "activate", - GTK_SIGNAL_FUNC(view1_print_callback), 0); - - s_quit = gtk_menu_item_new_with_label ("Exit"); - gtk_menu_append(GTK_MENU(s_filemenu), s_quit); - gtk_signal_connect(GTK_OBJECT(s_quit), "activate", - GTK_SIGNAL_FUNC(gtk_main_quit), 0); - - s_mainfilemenu = gtk_menu_item_new_with_label("File"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainfilemenu), s_filemenu); - - s_helpmenu = gtk_menu_new(); - - s_help_general = gtk_menu_item_new_with_label ("General"); - gtk_menu_append(GTK_MENU(s_helpmenu), s_help_general); - gtk_signal_connect(GTK_OBJECT(s_help_general), "activate", - GTK_SIGNAL_FUNC(help_general_callback), 0); - - s_help_about = gtk_menu_item_new_with_label ("About"); - gtk_menu_append(GTK_MENU(s_helpmenu), s_help_about); - gtk_signal_connect(GTK_OBJECT(s_help_about), "activate", - GTK_SIGNAL_FUNC(help_about_callback), 0); - - s_mainhelpmenu = gtk_menu_item_new_with_label("Help"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainhelpmenu), s_helpmenu); - - s_mainmenubar = gtk_menu_bar_new(); - gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainfilemenu); - gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainhelpmenu); - gtk_widget_show_all(s_mainmenubar); - - gtk_box_pack_start(GTK_BOX(g_mainvbox), s_mainmenubar, FALSE, FALSE, 0); -} diff --git a/g2/mkversion.c b/g2/mkversion.c deleted file mode 100644 index 3523fbe6c6d..00000000000 --- a/g2/mkversion.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -int main (int argc, char **argv) -{ - time_t now; - FILE *ofp; - char *dateval; - char *username; - char *userstr; - char *datestr; - int i; - char propname[32]; - char *propvalue; - char timestr[64]; - char *cp; - - if (argc < 4) { - printf ("usage: mkversion ostype version outputfile\n"); - exit (1); - } - - ofp = fopen (argv[3], "w"); - if (ofp == NULL) { - printf ("Couldn't create %s\n", argv[3]); - exit (1); - } - - now = time (0); - - fprintf (ofp, "/*\n"); - fprintf (ofp, " * G2 Version Stamp, %s", - ctime (&now)); - fprintf (ofp, " * Automatically generated, hand edits are pointless.\n"); - fprintf (ofp, " */\n\n"); - - fprintf (ofp, - "const char *version_string = \"G2 (%s) major version %s\";\n", - argv[1], argv[2]); - - username = (char *) cuserid (0); - - strcpy(timestr, ctime(&now)); - - cp = timestr; - - while (*cp) { - cp++; - } - if (*--cp == '\n') - *cp = 0; - - fprintf (ofp, - "const char *minor_v_string = \"Built by %s at %s\";\n", - username, timestr); - - exit (0); -} - - diff --git a/g2/pointsel.c b/g2/pointsel.c deleted file mode 100644 index 018dc2139e6..00000000000 --- a/g2/pointsel.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include "g2.h" - -/* - * globals - */ -event_def_t g_eventdefs[NEVENTS]; - -/* - * locals - */ -static GtkWidget *s_pointselbox; -static FILE *s_hfp; -static FILE *s_elog_hfp; -static int s_basenum; -static GtkWidget *s_event_buttons[NEVENTS]; -static int s_min_shown_pointsel; -static int s_max_shown_pointsel; -static GtkWidget *s_allbutton; -static GtkWidget *s_nonebutton; -static GtkWidget *s_pointselbuttons; -static GtkWidget *s_ps_vscroll; -static GtkObject *s_ps_vsadj; -static int g_neventdefs; - -enum button_click { - ALL_BUTTON=1, - NONE_BUTTON, -}; - -/* - * config params - */ -int c_maxpointsel; - -/**************************************************************************** -* recompute_vscrollbar -****************************************************************************/ - -static void recompute_ps_vscrollbar (void) -{ - GtkAdjustment *adj; - ulong limit; - - adj = GTK_ADJUSTMENT(s_ps_vsadj); - -#ifdef NOTDEF - /* This seems like the right calculation, but seems not to work */ - if (g_neventdefs > c_maxpointsel) - limit = g_neventdefs - c_maxpointsel; - else - limit = g_neventdefs; -#else - limit = g_neventdefs-1; -#endif - - adj->lower = (gfloat)0.00; - adj->upper = (gfloat)limit; - adj->value = (gfloat)0.00; - adj->step_increment = (gfloat)1.00; - adj->page_increment = (gfloat)(c_maxpointsel / 3); - adj->page_size = (gfloat)c_maxpointsel; - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); - gtk_widget_show(s_ps_vscroll); -} - -/**************************************************************************** -* point_select_callback -****************************************************************************/ - -static void point_select_callback(GtkToggleButton *item, gpointer data) -{ - int i = (int) (unsigned long long) data; - - g_eventdefs[i].selected = gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(s_event_buttons[i])); - view1_display_when_idle(); -} - -/**************************************************************************** -* up_button -****************************************************************************/ - -static void up_button(void) -{ - int i; - int increment = c_maxpointsel/4; - - if (s_min_shown_pointsel == 0) - return; - - s_min_shown_pointsel -= increment; - - if (s_min_shown_pointsel < 0) - s_min_shown_pointsel = 0; - - s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } - -} - -#ifdef NOTDEF -/**************************************************************************** -* down_button -****************************************************************************/ - -static void down_button(void) -{ - int i; - int increment = c_maxpointsel/4; - - if (s_max_shown_pointsel == g_neventdefs) - return; - - s_max_shown_pointsel += increment; - - if (s_max_shown_pointsel >= g_neventdefs) - s_max_shown_pointsel = (g_neventdefs-1); - - s_min_shown_pointsel = s_max_shown_pointsel - c_maxpointsel; - - if (s_min_shown_pointsel < 0) - s_min_shown_pointsel = 0; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } - -} -#endif - -/**************************************************************************** -* button_click_callback -****************************************************************************/ - -static void button_click_callback(GtkButton *item, gpointer data) -{ - int i; - enum button_click click = (enum button_click)data; - - switch (click) { - case ALL_BUTTON: - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), TRUE); - g_eventdefs[i].selected = TRUE; - } - break; - - case NONE_BUTTON: - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), FALSE); - g_eventdefs[i].selected = FALSE; - } - break; - } -} - -/**************************************************************************** -* scroll_callback -****************************************************************************/ - -static void scroll_callback (GtkAdjustment *adj, GtkWidget *notused) -{ - int i; - - s_min_shown_pointsel = (int)adj->value; - s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; - - for (i = 0; i < g_neventdefs; i++) { - if (i >= s_min_shown_pointsel && - i <= s_max_shown_pointsel) - gtk_widget_show(s_event_buttons[i]); - else - gtk_widget_hide(s_event_buttons[i]); - } -} - -/**************************************************************************** -* point_selector_init -****************************************************************************/ - -void point_selector_init(void) -{ - - c_maxpointsel = atol(getprop_default("event_selector_lines", "20")); - - s_pointselbox = gtk_vbox_new(FALSE,5); - - s_pointselbuttons = gtk_hbox_new(FALSE,5); - - s_allbutton = gtk_button_new_with_label("ALL"); - gtk_widget_show(s_allbutton); - s_nonebutton = gtk_button_new_with_label("NONE"); - gtk_widget_show(s_nonebutton); - - gtk_signal_connect (GTK_OBJECT(s_allbutton), "clicked", - GTK_SIGNAL_FUNC(button_click_callback), - (gpointer) ALL_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_nonebutton), "clicked", - GTK_SIGNAL_FUNC(button_click_callback), - (gpointer) NONE_BUTTON); - - gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_allbutton, FALSE, - FALSE, 0); - gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_nonebutton, FALSE, - FALSE, 0); - - gtk_widget_show(s_pointselbuttons); - gtk_widget_ref(s_pointselbuttons); - - gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, - FALSE, 0); - - gtk_box_pack_end (GTK_BOX(g_mainhbox), s_pointselbox, - FALSE, FALSE, 0); - - s_ps_vsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_ps_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_ps_vsadj)); - gtk_signal_connect (GTK_OBJECT (s_ps_vsadj), "value-changed", - GTK_SIGNAL_FUNC (scroll_callback), - (gpointer)s_ps_vscroll); - gtk_box_pack_end(GTK_BOX(g_mainhbox), s_ps_vscroll, FALSE, FALSE, 0); -} - -/**************************************************************************** -* sxerox -****************************************************************************/ - -char *sxerox (char *s) -{ - char *rv; - - /* Note: g_malloc does or dies... */ - rv = (char *)g_malloc(strlen(s)+1); - strcpy (rv, s); - return (rv); -} - -/**************************************************************************** -* reset_point_selector -****************************************************************************/ - -static void reset_point_selector(void) -{ - int i; - - gtk_widget_hide(s_pointselbox); - gtk_widget_hide(s_pointselbuttons); - gtk_widget_hide(s_ps_vscroll); - gtk_container_remove(GTK_CONTAINER(s_pointselbox), - s_pointselbuttons); - - for (i = 0; i < g_neventdefs; i++) { - if (s_event_buttons[i]) { - gtk_container_remove(GTK_CONTAINER(s_pointselbox), - s_event_buttons[i]); - s_event_buttons[i] = 0; - } - } -} - -/**************************************************************************** -* create_point_selector -****************************************************************************/ - -static void create_point_selector(void) -{ - int i; - char tmpbuf [1024]; - event_def_t *ep; - GtkWidget *wp; - - for (i = 0; i < g_neventdefs; i++) { - ep = &g_eventdefs[i]; - sprintf(tmpbuf, "[%lu] %s", ep->event, - ep->name ? ep->name : "(none)"); - /* Hack to reduce width of point selectors */ - if (strlen(tmpbuf) > 50) { - tmpbuf[50] = 0; - } - - wp = gtk_check_button_new_with_label (tmpbuf); - s_event_buttons[i] = wp; - gtk_signal_connect (GTK_OBJECT(wp), "toggled", - GTK_SIGNAL_FUNC(point_select_callback), - (gpointer) (unsigned long long) i); - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(wp), TRUE); - gtk_box_pack_start(GTK_BOX(s_pointselbox), wp, FALSE, FALSE, 0); - } - - /* set up scroll parameters by faking an up-button */ - s_min_shown_pointsel = 1; - up_button(); - - gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, - FALSE, 0); - gtk_widget_show(s_pointselbuttons); - gtk_widget_show(s_pointselbox); - gtk_widget_show(s_ps_vscroll); -} - -/**************************************************************************** -* remove_all_events -****************************************************************************/ - -static void remove_all_events(void) -{ - event_def_t *ep; - int i; - - for (i = 0; i < g_neventdefs; i++) { - ep = &g_eventdefs[i]; - if (!ep->is_clib) { - if (ep->name) - g_free(ep->name); - if(ep->format) - g_free(ep->format); - } - } - g_neventdefs = 0; -} - -/**************************************************************************** -* add_event -****************************************************************************/ - -static void add_event(ulong event, char *name, char *format) -{ - int i; - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - /* Simple dup check, probably not needed very often */ - for (i = 0; i < g_neventdefs; i++) { - if (g_eventdefs[i].event == event) { - g_warning("Duplicate def event %lu: first definition retained\n", - event); - return; - } - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - ep->name = sxerox(name); - ep->format = sxerox(format); - ep->selected = TRUE; -} - -/**************************************************************************** -* add_event_from_cpel_file -****************************************************************************/ - -void add_event_from_cpel_file(ulong event, char *event_format, - char *datum_format) -{ - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - /* - * Duplicate the strings for backward compatibility. Otherwise, - * the g_free above will barf because the name/format strings are - * actually in mmap'ed memory - */ - ep->name = sxerox(event_format); - ep->format = sxerox(datum_format); - ep->selected = TRUE; -} - -/**************************************************************************** -* add_event_from_clib_file -****************************************************************************/ - -void add_event_from_clib_file(unsigned int event, char *name, - unsigned int vec_index) -{ - event_def_t *ep; - - if (g_neventdefs >= NEVENTS) { - g_error("Too many event definitions, increase NEVENTS!"); - /*NOTREACHED*/ - } - - ep = &g_eventdefs[g_neventdefs++]; - - ep->event = event; - - ep->name = sxerox(name); - ep->format = (void *)(unsigned long long) vec_index; - ep->selected = TRUE; - ep->is_clib = TRUE; -} - -/**************************************************************************** -* read_header_file - eats header file lines of the form -* -* #define EVENT_FOO 123 / * name: %d * / -* -****************************************************************************/ - -static void read_header_file (void) -{ - char tmpbuf [1024]; - char *name, *format; - char *cp; - unsigned long event; - int ev_num_flag; - - while (fgets (tmpbuf, sizeof (tmpbuf), s_hfp)) - { - cp = tmpbuf; - ev_num_flag = 0; - - if (strncmp (cp, "#define", 7)) - continue; - - /* skip #define */ - while (*cp && !(isspace ((int)*cp))) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after #define */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip symbolic name */ - while (*cp && !(isspace ((int)*cp))) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after symbolic name */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - event = 0; - - if (!strncmp(cp, "EV_NUM", 6)) { - cp += 6; - ev_num_flag = 1; - - while (*cp && *cp != '(') - cp++; - - if (*cp == 0) - continue; - - cp++; - - while (*cp && isspace ((int)*cp)) - cp++; - - } - - /* eat event code. */ - while (*cp && isdigit ((int)*cp)) - { - event = event * 10 + (*cp - '0'); - cp++; - } - - if (*cp == 0) - continue; - - if (ev_num_flag) { - while (*cp && *cp != ')') - cp++; - if (*cp == 0) - continue; - cp++; - event += s_basenum; - } - - /* skip ws after event code */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp != '/') - continue; - - cp++; - - if (*cp != '*') - continue; - - cp++; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - name = cp; - - /* accumulate name */ - while (*cp && *cp != ':' && *cp != '*') - cp++; - - if (*cp == 0) - continue; - - *cp++ = 0; - - /* skip ws after name: */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0 || *cp == '/') - { - format = " "; - goto write_it; - } - - format = cp; - - /* accumulate format string */ - while (*cp && !isspace ((int)*cp)) - cp++; - - *cp = 0; - - write_it: - - add_event (event, name, format); - } -} - -/**************************************************************************** -* read_header_files - eats header file lines of the form -* -* #define FILE1_BASE 100 / * pointdefs: ../vpn/vpn_points.h * / -* -****************************************************************************/ - -static boolean read_header_files (void) -{ - char *cp, *name; - char tmpbuf [1024]; - int basenum; - boolean rv=FALSE; - - while (fgets (tmpbuf, sizeof (tmpbuf), s_elog_hfp)) - { - cp = tmpbuf; - - if (strncmp (cp, "#define", 7)) - continue; - - cp += 7; - - /* skip ws after #define */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip EV_COMPxxx_START */ - while (*cp && !isspace((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - /* skip ws after EV_COMPxxx_START */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - basenum = atol (cp); - - /* skip #define */ - while (*cp && (*cp != '/')) - cp++; - - if (*cp == 0) - continue; - - cp++; - if (*cp != '*') - continue; - - cp++; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - if (*cp == 0) - continue; - - if (strncmp (cp, "pointdefs:", 10)) - continue; - - cp += 10; - - /* skip ws after comment start */ - while (*cp && isspace ((int)*cp)) - cp++; - - name = cp; - - while (*cp && !isspace ((int)*cp)) - cp++; - - *cp = 0; - - s_hfp = fopen (name, "rt"); - - if (s_hfp == NULL) { - g_warning ("Couldn't open header file %s\n", name); - continue; - } - rv = TRUE; - - s_basenum = basenum; - - read_header_file(); - - fclose (s_hfp); - } - return(rv); -} - -/**************************************************************************** -* event_def_cmp -****************************************************************************/ - -int event_def_cmp(const void *a1, const void *a2) -{ - event_def_t *e1 = (event_def_t *)a1; - event_def_t *e2 = (event_def_t *)a2; - - if (e1->event < e2->event) - return(-1); - else if (e1->event == e2->event) - return(0); - else - return(1); -} - -/**************************************************************************** -* sort_event_definitions -****************************************************************************/ - -void sort_event_definitions(void) -{ - qsort(&g_eventdefs[0], g_neventdefs, sizeof(event_def_t), event_def_cmp); -} - -static boolean remove_needed=TRUE; - -void finalize_events(void) -{ - sort_event_definitions(); - create_point_selector(); - recompute_ps_vscrollbar(); - view1_display_when_idle(); - remove_needed = TRUE; -} - -void initialize_events(void) -{ - if (remove_needed) { - reset_point_selector(); - remove_all_events(); - remove_needed = FALSE; - } -} - -/**************************************************************************** -* read_event_definitions -****************************************************************************/ - -boolean read_event_definitions (char *filename) -{ - char tmpbuf [128]; - - initialize_events(); - - s_elog_hfp = fopen (filename, "rt"); - if (s_elog_hfp == NULL) { - sprintf (tmpbuf, "Couldn't open %s\n", filename); - infobox ("Open Failed", tmpbuf); - return(FALSE); - } - /* Presume "elog.h". Note fallthrough... */ - if (read_header_files()) { - sort_event_definitions(); - create_point_selector(); - recompute_ps_vscrollbar(); - fclose(s_elog_hfp); - view1_display_when_idle(); - remove_needed = TRUE; - return(TRUE); - } - fclose(s_elog_hfp); - - s_hfp = fopen (filename, "rt"); - if (s_hfp == NULL) { - sprintf (tmpbuf, "Couldn't open %s\n", filename); - infobox ("Read Event Definition Failure", tmpbuf); - return(FALSE); - } - - read_header_file(); - - /* Happens if the user feeds us the wrong file, for example */ - if (g_neventdefs == 0) { - sprintf (tmpbuf, "No event definitions found in %s\n", filename); - infobox ("No Event Definitions?", tmpbuf); - return(FALSE); - } - finalize_events(); - return(TRUE); -} - -static event_def_t dummy_event; -static char dummy_string[32]; - -/**************************************************************************** -* find_event_definition -* Binary search for first event whose time is >= t -****************************************************************************/ - -event_def_t *find_event_definition (ulong code) -{ - int index, bottom, top; - event_def_t *edp; - - if (g_neventdefs == 0) - goto use_dummy; - - bottom = g_neventdefs-1; - top = 0; - - while (1) { - index = (bottom + top) / 2; - - edp = (g_eventdefs + index); - - if (edp->event == code) - return(edp); - - if (top >= bottom) { - use_dummy: - edp = &dummy_event; - edp->selected = TRUE; - edp->event = code; - edp->format = "0x%x"; - sprintf (dummy_string, "E%lu", code); - edp->name = &dummy_string[0]; - return(edp); - } - - if (edp->event < code) - top = index + 1; - else - bottom = index - 1; - } -} - -/**************************************************************************** -* pointsel_next_snapshot -* Set dialog buttons from snapshot -****************************************************************************/ - -void pointsel_next_snapshot(void) -{ - int i; - - for (i = 0; i < g_neventdefs; i++) { - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON(s_event_buttons[i]), - g_eventdefs[i].selected); - } -} - -/**************************************************************************** -* pointsel_about -****************************************************************************/ - -void pointsel_about (char *tmpbuf) -{ - sprintf (tmpbuf+strlen(tmpbuf), "%d event definitions\n", - g_neventdefs); -} diff --git a/g2/props.c b/g2/props.c deleted file mode 100644 index a23dc0504d2..00000000000 --- a/g2/props.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include - -static char *sxerox (char *s); -void exit(int); - -#define NBUCKETS 97 - -typedef struct prop_ { - struct prop_ *next; - char *name; - char *value; -} prop_t; - -static prop_t *buckets [NBUCKETS]; -static int hash_shifts[4] = {24, 16, 8, 0}; - -/* - * getprop - */ - -char *getprop (char *name) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t *bp; - int i=0; - - for (cp = (unsigned char *) name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bp = buckets [hash%NBUCKETS]; - - while (bp && strcmp (bp->name, name)) { - bp = bp->next; - } - - if (bp == NULL) - return (0); - else - return (bp->value); -} - -/* - * getprop_default - */ - -char *getprop_default (char *name, char *def) -{ - char *rv; - rv = getprop (name); - if (rv) - return (rv); - else - return (def); -} - -/* - * addprop - */ - -void addprop (char *name, char *value) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t **bpp; - prop_t *bp; - int i=0; - - bp = (prop_t *)g_malloc (sizeof (prop_t)); - - bp->next = 0; - bp->name = sxerox (name); - bp->value = sxerox (value); - - for (cp = (unsigned char *)name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bpp = &buckets [hash%NBUCKETS]; - - if (*bpp == NULL) - *bpp = bp; - else { - bp->next = *bpp; - *bpp = bp; - } -} - -/* - * sxerox - */ - -static char *sxerox (char *s) -{ - char *rv = (char *) g_malloc (strlen (s) + 1); - strcpy (rv, s); - return rv; -} - -/* - * readprops - */ - -#define START 0 -#define READNAME 1 -#define READVALUE 2 -#define C_COMMENT 3 -#define CPP_COMMENT 4 - -int readprops (char *filename) -{ - FILE *ifp; - unsigned char c; - int state=START; - int linenum=1; - char namebuf [128]; - char valbuf [512]; - int i; - - ifp = fopen (filename, "r"); - - if (ifp == NULL) - return (-1); - - while (1) { - - readchar: - c = getc (ifp); - - again: - switch (state) { - case START: - if (feof (ifp)) { - fclose (ifp); - return (0); - } - - if (c == ' ' || c == '\t') - goto readchar; - - if (c == '\n') { - linenum++; - goto readchar; - } - if (isalpha (c) || (c == '_')) { - state = READNAME; - goto again; - } - if (c == '/') { - c = getc (ifp); - if (c == '/') { - state = CPP_COMMENT; - goto readchar; - } else if (c == '*') { - state = C_COMMENT; - goto readchar; - } else { - fprintf (stderr, "unknown token '/' line %d\n", - linenum); - exit (1); - } - } - fprintf (stderr, "unknown token '%c' line %d\n", - c, linenum); - exit (1); - break; - - case CPP_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) - return (0); - if (c == '\n') { - linenum++; - state = START; - goto readchar; - } - } - break; - - case C_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "unterminated comment, line %d\n", - linenum); - exit (1); - } - if (c == '*') { - staragain: - c = getc (ifp); - if (c == '/') { - state = START; - goto readchar; - } - if (c == '*') - goto staragain; - } - } - break; - - case READNAME: - i = 0; - namebuf[i++] = c; - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a name, line %d\n", - linenum); - exit (1); - } - if ((!isalnum (c)) && (c != '_')) { - namebuf [i] = 0; - state = READVALUE; - goto again; - } - namebuf [i++] = c; - } - break; - - case READVALUE: - i = 0; - while ((c == ' ') || (c == '\t') || (c == '=')) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a value, line %d\n", - linenum); - exit (1); - } - } - goto firsttime; - while (1) { - c = getc (ifp); - - firsttime: - if (c == '\\') { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF after '\\', line %d\n", - linenum); - exit (1); - } - valbuf[i++] = c; - continue; - } - if (c == '\n') { - linenum++; - while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') - i--; - valbuf[i] = 0; - addprop (namebuf, valbuf); - state = START; - goto readchar; - } - valbuf[i++] = c; - } - - } - } -} diff --git a/g2/props.h b/g2/props.h deleted file mode 100644 index 6289941dd4d..00000000000 --- a/g2/props.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 1997-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -extern char *getprop (char *name); -extern char *getprop_default (char *name, char *def); -extern void addprop (char *name, char *value); -extern int readprops (char *filename); -extern int writeprops (char *filename); diff --git a/g2/view1.c b/g2/view1.c deleted file mode 100644 index ec394cc3d53..00000000000 --- a/g2/view1.c +++ /dev/null @@ -1,3077 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include "g2.h" -#include -#include -#include -#include - -/* - * The main event display view. - * - * Important variables: - * - * "da" -- the drawing area, aka the screen representation of the - * event view. - * - * "pm" -- the backing pixmap for the drawing area. Note that - * all graphics operations target this backing - * store, then call gtk_widget_draw to copy a rectangle from - * the backing store onto the screen. - * - * "s_v1" -- pointer to the current v1_geometry_t object. - * - * Box heirarchy: - * s_view1_vbox - * s_view1_hbox - * da s_view1_vmenubox - * s_view1_topbutton("Top") - * s_view1_vscroll (vertical scrollbar) - * s_view1_bottombutton("Bottom") - * s_view1_hmenubox - * s_view1_startbutton("Start"); - * s_view1_hscroll(horizontal scrollbar) - * s_view1_endbutton("End") - * s_view1_zoominbutton("Zoomin") - * s_view1_searchbutton("Search") - * s_view1_searchagainbutton("Search Again") - * s_view1_zoomoutbutton("Zoomout") - * s_view1_label - */ - -/* - * Globals - */ - -GdkFont *g_font; /* a fixed-width font to use */ -GdkColor fg_black = {0, 0, 0, 0}; -GdkColor bg_white = {0, 65535, 65535, 65535}; -static boolean summary_mode = TRUE; /* start out in summary mode */ -static boolean color_mode = FALSE; /* start out in color mode */ - -/* - * Locals - */ - -/* - * user_data values passed to view1_button_click_callback, - * which is used by the various action buttons noted above - */ -enum view1_button_click { - TOP_BUTTON=1, - BOTTOM_BUTTON, - START_BUTTON, - ZOOMIN_BUTTON, - SEARCH_BUTTON, - SEARCH_AGAIN_BUTTON, - ZOOMOUT_BUTTON, - END_BUTTON, - MORE_TRACES_BUTTON, - LESS_TRACES_BUTTON, - SNAP_BUTTON, - NEXT_BUTTON, - DEL_BUTTON, - CHASE_EVENT_BUTTON, - CHASE_DATUM_BUTTON, - CHASE_TRACK_BUTTON, - UNCHASE_BUTTON, - FORWARD_BUTTON, - BACKWARD_BUTTON, - SUMMARY_BUTTON, - NOSUMMARY_BUTTON, -}; - -enum chase_mode { - CHASE_EVENT=1, - CHASE_DATUM, - CHASE_TRACK, -}; - -enum sc_dir { - SRCH_CHASE_FORWARD = 0, - SRCH_CHASE_BACKWARD = 1, -}; - -static GtkWidget *s_view1_hbox; /* see box heirarchy chart */ -static GtkWidget *s_view1_vbox; /* see box heirarchy chart */ -static GtkWidget *da; /* main drawing area */ -static GdkPixmap *pm; /* and its backing pixmap */ -static GdkCursor *norm_cursor; /* the "normal" cursor */ - -/* - * view geometry parameters - * - * Remember: - * Y increases down the page. - * Strip origin is at the top - * Payday is Friday - * Don't put your fingers in your mouth. - * - * Most of these values are in pixels - */ - -typedef struct v1_geometry { - int pid_ax_width; /* Width of the PID axis */ - int time_ax_height; /* Height of the time axis */ - int time_ax_spacing; /* TimeAxis: Space between tick-marks */ - int strip_height; /* Height of a regular PID trace */ - int pop_offset; /* Vertical offset of the detail box */ - int pid_ax_offset; /* Vertical offset of the PID axis */ - int event_offset; /* Vertical offset of the event boxes */ - int total_height; /* total height of da, see configure_event */ - int total_width; /* ditto, for width */ - - /* Derived values */ - int first_pid_index; /* Index of first displayed PID */ - int npids; /* Max number of displayed pids */ - ulonglong minvistime; /* in usec */ - ulonglong maxvistime; /* in usec */ -} v1_geometry_t; - - -/* The active geometry object */ -static v1_geometry_t s_v1record; -static v1_geometry_t *s_v1 = &s_v1record; - -/* The color array */ -static GdkColor *s_color; - -/* Snapshot ring */ -typedef struct snapshot { - struct snapshot *next; - /* Screen geometry */ - v1_geometry_t geometry; - boolean show_event[NEVENTS]; - pid_sort_t *pidvec; - /* - * Note: not worth recomputing the vertical scrollbar, just save - * its value here - */ - gfloat vscroll_value; - boolean summary_mode; - boolean color_mode; -} snapshot_t; - -static snapshot_t *s_snapshots; -static snapshot_t *s_cursnap; -static event_t *s_last_selected_event; - -/* - * various widgets, see the box heirarchy chart above - * The toolkit keeps track of these things, we could lose many of - * these pointers. - */ -static GtkWidget *s_view1_vmenubox; -static GtkWidget *s_view1_topbutton; -static GtkWidget *s_view1_bottombutton; -static GtkWidget *s_view1_more_traces_button; -static GtkWidget *s_view1_less_traces_button; - -static GtkWidget *s_view1_hmenubox; -static GtkWidget *s_view1_hmenubox2; -static GtkWidget *s_view1_startbutton; -static GtkWidget *s_view1_zoominbutton; -static GtkWidget *s_view1_searchbutton; -static GtkWidget *s_view1_srchagainbutton; -static GtkWidget *s_view1_zoomoutbutton; -static GtkWidget *s_view1_endbutton; - -static GtkWidget *s_view1_snapbutton; -static GtkWidget *s_view1_nextbutton; -static GtkWidget *s_view1_delbutton; - -static GtkWidget *s_view1_chase_event_button; -static GtkWidget *s_view1_chase_datum_button; -static GtkWidget *s_view1_chase_track_button; -static GtkWidget *s_view1_unchasebutton; - -static GtkWidget *s_view1_forward_button; -static GtkWidget *s_view1_backward_button; - -static GtkWidget *s_view1_summary_button; -static GtkWidget *s_view1_nosummary_button; - -static GtkWidget *s_view1_hscroll; -static GtkObject *s_view1_hsadj; - -static GtkWidget *s_view1_vscroll; -static GtkObject *s_view1_vsadj; - -static GtkWidget *s_view1_label; - -/* - * Search context - */ -static ulong s_srchcode; /* search event code */ -static int s_srchindex; /* last hit was at this event index */ -static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */ -static boolean s_srchfail_up; /* The status line "Search Failed" is up */ -static int srch_chase_dir; /* search/chase dir, 0=>forward */ - - -/* - * Print context - */ -static int s_print_offset; /* Magic offset added to line, tbox fn codes */ -static FILE *s_printfp; - -/* - * Forward reference prototypes - */ -static void display_pid_axis(v1_geometry_t *vp); -static void display_event_data(v1_geometry_t *vp); -static void display_time_axis(v1_geometry_t *vp); -static void view1_button_click_callback(GtkButton *item, gpointer data); - -/* - * config params - */ - -gint c_view1_draw_width; -gint c_view1_draw_height; - -/* - * Zoom-In / Time Ruler cursor - */ - -#define zi_width 32 -#define zi_height 32 -#define zi_x_hot 22 -#define zi_y_hot 14 -static unsigned char zi_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, - 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static unsigned char zi_bkgd[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, - 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, - 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -static GdkCursor *zi_cursor; -static GdkPixmap *zi_source, *zi_mask; - -/* - * Frequently-used small computations, best - * done correctly once and instantiated. - */ - -/**************************************************************************** -* dtime_per_pixel -****************************************************************************/ - -static inline double dtime_per_pixel(v1_geometry_t *vp) -{ - return ((double)(vp->maxvistime - vp->minvistime)) / - ((double)(vp->total_width - vp->pid_ax_width)); -} - -/**************************************************************************** -* message_line -* Changes the status line. Pass "" to clear the status line. -****************************************************************************/ - -void message_line (char *s) -{ - gtk_label_set_text (GTK_LABEL(s_view1_label), s); -} - -/**************************************************************************** -* set_window_title -* Changes the window title to include the specified filename. -****************************************************************************/ - -void set_window_title (const char *filename) -{ - char title[128]; - snprintf(title, sizeof(title), "g2 (%s)", filename); - gtk_window_set_title(GTK_WINDOW(g_mainwindow), title); -} - -/**************************************************************************** -* recompute_hscrollbar -* Adjust the horizontal scrollbar's adjustment object. -* -* GtkAdjustments are really cool, but have to be set up exactly -* right or the various client objects screw up completely. -* -* Note: this function is *not* called when the user clicks the scrollbar. -****************************************************************************/ - -static void recompute_hscrollbar (void) -{ - ulonglong current_width; - ulonglong event_incdec; - GtkAdjustment *adj; - event_t *ep; - - if (g_nevents == 0) - return; - - ep = (g_events + (g_nevents-1)); - current_width = s_v1->maxvistime - s_v1->minvistime; - event_incdec = (current_width) / 6; - - adj = GTK_ADJUSTMENT(s_view1_hsadj); - - /* - * Structure member decoder ring - * ----------------------------- - * lower the minimum possible value - * value the current value - * upper the maximum possible value - * step_increment end button click increment - * page_increment click in trough increment - * page_size size of currently visible area - */ - - adj->lower = (gfloat)0.00; - adj->value = (gfloat)s_v1->minvistime; - - /* Minor click: move about 1/6 of a page */ - adj->step_increment = (gfloat)event_incdec; - - /* Major click: move about 1/3 of a page. */ - adj->page_increment = (gfloat)(2*event_incdec); - - /* allow the user to go a bit past the end */ - adj->upper = adj->page_increment/3 + (gfloat)(ep->time); - adj->page_size = (gfloat)(current_width); - - /* - * Tell all clients (e.g. the visible scrollbar) to - * make themselves look right - */ - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); -} - -/**************************************************************************** -* recompute_vscrollbar -* Ditto, for the vertical scrollbar -****************************************************************************/ - -static void recompute_vscrollbar (void) -{ - GtkAdjustment *adj; - - adj = GTK_ADJUSTMENT(s_view1_vsadj); - - adj->lower = (gfloat)0.00; - adj->upper = (gfloat)g_npids; - adj->value = (gfloat)0.00; - adj->step_increment = 1.00; - adj->page_increment = (gfloat)(s_v1->npids / 3); - adj->page_size = (gfloat)s_v1->npids; - gtk_adjustment_changed(adj); - gtk_adjustment_value_changed(adj); -} - -/**************************************************************************** -* format_popbox_string -****************************************************************************/ - -elog_main_t elog_main; - -void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp) -{ - char *fp; - -#ifdef NOTDEF - sprintf(tmpbuf,"%d:", ep->code); -#endif - if (ep->flags & EVENT_FLAG_CLIB) { - elog_event_t *eep; - u8 *s; - - eep = get_clib_event (ep->datum); - - s = format (0, "%U", format_elog_event, &elog_main, eep); - memcpy (tmpbuf, s, vec_len(s)); - tmpbuf[vec_len(s)] = 0; - vec_free(s); - return; - } - - snprintf(tmpbuf, len, "%s", edp->name); - fp = edp->format; - /* Make sure there's a real format string. If so, add it */ - while (fp && *fp) { - if (*fp != ' ') { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": "); - /* %s only supported for cpel files */ - if (fp[1] == 's') { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), - edp->format, strtab_ref(ep->datum)); - } else { - snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), - edp->format, ep->datum); - } - return; - } - fp++; - } -} - -/**************************************************************************** - * add_snapshot - ****************************************************************************/ - -static void add_snapshot(void) -{ - int i; - snapshot_t *new = g_malloc(sizeof(snapshot_t)); - - memcpy(&new->geometry, s_v1, sizeof(new->geometry)); - for (i = 0; i < NEVENTS; i++) { - new->show_event[i] = g_eventdefs[i].selected; - } - new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids); - new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value; - new->summary_mode = summary_mode; - new->color_mode = color_mode; - - if (s_snapshots) { - new->next = s_snapshots; - s_snapshots = new; - } else { - new->next = 0; - s_snapshots = new; - } - s_cursnap = new; -} - -/**************************************************************************** - * next_snapshot - ****************************************************************************/ - -static void next_snapshot(void) -{ - snapshot_t *next; - int i; - pid_sort_t *psp; - pid_data_t *pp; - - if (!s_snapshots) { - infobox("No snapshots", "\nNo snapshots in the ring...\n"); - return; - } - - next = s_cursnap->next; - if (next == 0) - next = s_snapshots; - - s_cursnap = next; - - memcpy(s_v1, &next->geometry, sizeof(next->geometry)); - for (i = 0; i < NEVENTS; i++) { - g_eventdefs[i].selected = next->show_event[i]; - } - memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids); - color_mode = next->color_mode; - /* - * Update summary mode via a button push so that the button state is - * updated accordingly. (Should ideally clean up the view/controller - * separation properly one day.) - */ - if (summary_mode != next->summary_mode) { - view1_button_click_callback - (NULL, (gpointer)(unsigned long long) - (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); - } - - /* Fix the pid structure index mappings */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - recompute_hscrollbar(); - pointsel_next_snapshot(); - view1_display_when_idle(); -} - - -/**************************************************************************** - * del_snapshot - ****************************************************************************/ - -static void del_snapshot(void) -{ - snapshot_t *prev; - snapshot_t *this; - - if (!s_snapshots) { - infobox("No snapshots", "\nNo snapshots to delete...\n"); - return; - } - - prev = NULL; - this = s_snapshots; - - while (this && this != s_cursnap) { - prev = this; - this = this->next; - } - - if (this != s_cursnap) { - infobox("BUG", "\nSnapshot AWOL!\n"); - return; - } - - s_cursnap = this->next; - - /* middle of the list? */ - if (prev) { - prev->next = this->next; - g_free(this->pidvec); - g_free(this); - } else { /* start of the list */ - s_snapshots = this->next; - g_free(this->pidvec); - g_free(this); - } - - /* Note: both will be NULL after last delete */ - if (s_cursnap == NULL) - s_cursnap = s_snapshots; -} - -/**************************************************************************** - * write_snapshot - * - * VERY primitive right now - not endian or version independent, and only - * writes to "snapshots.g2" in the current directory - ****************************************************************************/ -static void write_snapshot(void) -{ - FILE *file = NULL; - snapshot_t *snap; - char *error = NULL; - int records = 0; - - if (s_snapshots == NULL) { - error = "No snapshots defined"; - errno = 0; - } - - if (!error) { - file = fopen("snapshots.g2", "w"); - if (file == NULL) { - error = "Unable to open snapshots.g2"; - } - } - - /* - * Simply serialize the arch-dependent binary data, without a care in the - * world. Don't come running to me if you try to read it and crash. - */ - for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) { - if (fwrite(&snap->geometry, - sizeof(snap->geometry), 1, file) != 1 || - fwrite(&snap->show_event, - sizeof(snap->show_event), 1, file) != 1 || - fwrite(snap->pidvec, - sizeof(pid_sort_t) * g_npids, 1, file) != 1 || - fwrite(&snap->vscroll_value, - sizeof(snap->vscroll_value), 1, file) != 1 || - fwrite(&snap->summary_mode, - sizeof(snap->summary_mode), 1, file) != 1 || - fwrite(&snap->color_mode, - sizeof(snap->color_mode), 1, file) != 1) { - error = "Error writing data"; - } - records++; - } - - if (!error) { - if (fclose(file)) { - error = "Unable to close file"; - } - } - - if (error) { - infobox(error, strerror(errno)); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2", - records); - message_line(buf); - } -} - -/**************************************************************************** - * read_snapshot - * - * VERY primitive right now - not endian or version independent, and only reads - * from "snapshots.g2" in the current directory - ****************************************************************************/ -static void read_snapshot(void) -{ - FILE *file; - snapshot_t *snap, *next_snap; - snapshot_t *new_snaps = NULL; - char *error = NULL; - int len, i, records = 0; - pid_data_t *pp; - - file = fopen("snapshots.g2", "r"); - if (file == NULL) { - error = "Unable to open snapshots.g2"; - } - - /* - * Read in the snapshots and link them together. We insert them backwards, - * but that's tolerable. If the data is in anyway not what we expect, we'll - * probably crash. Sorry. - */ - while (!error && !feof(file)) { - snap = g_malloc(sizeof(*snap)); - snap->pidvec = NULL; /* so we can free this if there's an error */ - - len = fread(&snap->geometry, sizeof(snap->geometry), 1, file); - if (len == 0) { - /* EOF */ - g_free(snap); - break; - } else { - /* insert into list straight away */ - snap->next = new_snaps; - new_snaps = snap; - } - if (len != 1) { - error = "Problem reading first item from file"; - break; - } - if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) { - error = "Problem reading second item from file"; - break; - } - len = sizeof(pid_sort_t) * g_npids; - snap->pidvec = g_malloc(len); - if (fread(snap->pidvec, len, 1, file) != 1) { - error = "Problem reading third item from file"; - break; - } - if (fread(&snap->vscroll_value, - sizeof(snap->vscroll_value), 1, file) != 1 || - fread(&snap->summary_mode, - sizeof(snap->summary_mode), 1, file) != 1 || - fread(&snap->color_mode, - sizeof(snap->color_mode), 1, file) != 1) { - error = "Problem reading final items from file"; - break; - } - - /* - * Fix up the pointers from the sorted pid vector back into our pid - * data objects, by walking the linked list of pid_data_t objects for - * every one looking for a match. This is O(n^2) grossness, but in real - * life there aren't that many pids, and it seems zippy enough. - */ - for (i = 0; i < g_npids; i++) { - for (pp = g_pid_data_list; pp != NULL; pp = pp->next) { - if (pp->pid_value == snap->pidvec[i].pid_value) { - break; - } - } - if (pp != NULL) { - snap->pidvec[i].pid = pp; - } else { - error = "Snapshot file referenced unknown pids"; - break; - } - } - - records++; - } - - if (!error) { - if (fclose(file)) { - error = "Unable to close file"; - } - } - - if (error) { - /* - * Problem - clear up any detritus - */ - infobox(error, strerror(errno)); - for (snap = new_snaps; snap != NULL; snap = next_snap) { - next_snap = snap->next; - g_free(snap); - g_free(snap->pidvec); - } - } else { - /* - * Success! trash the old snapshots and replace with the new - */ - for (snap = s_snapshots; snap != NULL; snap = next_snap) { - next_snap = snap->next; - g_free(snap->pidvec); - g_free(snap); - } - - s_cursnap = s_snapshots = new_snaps; - } - - if (error) { - infobox(error, strerror(errno)); - } else { - char buf[64]; - snprintf(buf, sizeof(buf), - "Read %d snapshots from snapshots.g2", records); - message_line(buf); - } -} - -/**************************************************************************** -* set_color -* -* Set the color for the specified pid_index, or COLOR_DEFAULT to return it -* to the usual black. -****************************************************************************/ -#define COLOR_DEFAULT (-1) -static void set_color(int pid_index) -{ - if (pid_index == COLOR_DEFAULT || !color_mode) { - gdk_gc_set_foreground(da->style->black_gc, &fg_black); - } else { - gdk_gc_set_foreground(da->style->black_gc, - &s_color[g_pids[pid_index].color_index]); - } -} - -/**************************************************************************** -* toggle_event_select -****************************************************************************/ - -static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp) -{ - int pid_index, start_index; - int x, y; - GdkRectangle *rp; - GdkRectangle hit_rect; - GdkRectangle dummy; - event_t *ep; - event_def_t *edp; - char tmpbuf [1024]; - double time_per_pixel; - - if (g_nevents == 0) - return; - - time_per_pixel = dtime_per_pixel(vp); - - start_index = find_event_index (vp->minvistime); - - /* Too far right? */ - if (start_index >= g_nevents) - return; - - /* - * To see if the mouse hit a visible event, use a variant - * of the event display loop. - */ - - hit_rect.x = (int)event->x; - hit_rect.y = (int)event->y; - hit_rect.width = 1; - hit_rect.height = 1; - - ep = (g_events + start_index); - - while ((ep->time < vp->maxvistime) && - (ep < (g_events + g_nevents))) { - pid_index = ep->pid->pid_index; - - /* First filter: pid out of range */ - if ((pid_index < vp->first_pid_index) || - (pid_index >= vp->first_pid_index + vp->npids)) { - ep++; - continue; - } - - /* Second filter: event hidden */ - edp = find_event_definition (ep->code); - if (!edp->selected) { - ep++; - continue; - } - - /* - * At this point, we know that the point is at least on the - * screen. See if the mouse hit within the bounding box - */ - - /* - * $$$$ maybe keep looping until off the edge, - * maintain a "best hit", then declare that one the winner? - */ - - pid_index -= vp->first_pid_index; - - y = pid_index*vp->strip_height + vp->event_offset; - - x = vp->pid_ax_width + - (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); - - /* Perhaps we're trying to toggle the detail box? */ - if (ep->flags & EVENT_FLAG_SELECT) { - /* Figure out the dimensions of the detail box */ - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); - rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED); - if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { - ep->flags &= ~EVENT_FLAG_SELECT; - view1_display_when_idle(); - break; - } - } - - sprintf(tmpbuf, "%ld", ep->code); - - /* Figure out the dimensions of the regular box */ - rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT); - - if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { - /* we hit the rectangle. */ - if (ep->flags & EVENT_FLAG_SELECT) { - ep->flags &= ~EVENT_FLAG_SELECT; - view1_display_when_idle(); - break; - } else { - set_color(ep->pid->pid_index); - - /* It wasn't selected, so put up the detail box */ - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); - tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED); - line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK); - ep->flags |= EVENT_FLAG_SELECT; - ep->flags &= ~EVENT_FLAG_SEARCHRSLT; - s_last_selected_event = ep; - } - break; - } - ep++; - } -} - -/**************************************************************************** -* move_current_track -****************************************************************************/ - -typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type; - -static void move_current_track(GdkEventButton *event, - v1_geometry_t *vp, - move_type type) -{ - int i; - int pid_index; - int y, delta_y; - pid_sort_t *new_pidvec; - pid_sort_t *psp; - pid_sort_t *pold, *pnew; - pid_data_t *pp; - - if (g_nevents == 0) - return; - - /* Scan pid/track axis locations, looking for a match */ - for (i = 0; i < vp->npids; i++) { - y = i*vp->strip_height + vp->pid_ax_offset; - delta_y = y - event->y; - if (delta_y < 0) - delta_y = -delta_y; - if (delta_y < 10) { - goto found; - } - - } - infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again"); - return; - - found: - pid_index = i + vp->first_pid_index; - - new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - pold = g_pids; - pnew = new_pidvec; - - if (type == MOVE_TOP) { - /* move to top */ - *pnew++ = g_pids[pid_index]; - for (i = 0; i < pid_index; i++) - *pnew++ = *pold++; - pold++; - i++; - for (; i < g_npids; i++) - *pnew++ = *pold++; - } else { - /* move to bottom */ - for (i = 0; i < pid_index; i++) - *pnew++ = *pold++; - pold++; - i++; - for (; i < g_npids; i++) - *pnew++ = *pold++; - *pnew = g_pids[pid_index]; - } - - g_free(g_pids); - g_pids = new_pidvec; - - /* - * Revert the pid_index mapping to an identity map, - */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - view1_display_when_idle(); -} - -/**************************************************************************** -* zoom_event -* Process a zoom gesture. The use of doubles is required to avoid -* truncating the various variable values, which in turn would lead to -* some pretty random-looking zoom responses. -****************************************************************************/ - -void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp) -{ - double xrange; - double time_per_pixel; - double width_in_pixels; - double center_on_time, width_in_time; - double center_on_pixel; - - /* - * Clip the zoom area to the event display area. - * Otherwise, center_on_time - width_in_time is in hyperspace - * to the left of zero - */ - - if (e1->x < vp->pid_ax_width) - e1->x = vp->pid_ax_width; - - if (e2->x < vp->pid_ax_width) - e2->x = vp->pid_ax_width; - - if (e2->x == e1->x) - goto loser_zoom_repaint; - - xrange = (double) (e2->x - e1->x); - if (xrange < 0.00) - xrange = -xrange; - - /* Actually, width in pixels of half the zoom area */ - width_in_pixels = xrange / 2.00; - time_per_pixel = dtime_per_pixel(vp); - width_in_time = width_in_pixels * time_per_pixel; - - /* Center the screen on the center of the zoom area */ - center_on_pixel = (double)((e2->x + e1->x) / 2.00) - - (double)vp->pid_ax_width; - center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime; - - /* - * Transform back to 64-bit integer microseconds, reset the - * scrollbar, schedule a repaint. - */ - vp->minvistime = (ulonglong)(center_on_time - width_in_time); - vp->maxvistime = (ulonglong)(center_on_time + width_in_time); - -loser_zoom_repaint: - recompute_hscrollbar(); - - view1_display_when_idle(); -} - -/**************************************************************************** -* scroll_y -* -* Scroll up or down by the specified delta -* -****************************************************************************/ -static void scroll_y(int delta) -{ - int new_index = s_v1->first_pid_index + delta; - if (new_index + s_v1->npids > g_npids) - new_index = g_npids - s_v1->npids; - if (new_index < 0) - new_index = 0; - - if (new_index != s_v1->first_pid_index) { - s_v1->first_pid_index = new_index; - GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - view1_display_when_idle(); - } -} - -/**************************************************************************** -* view1_handle_key_press_event -* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h -* -* This routine implements hotkeys for the Quake generation: -* -* W - zoom in -* S - zoom out -* A - pan left -* D - pan right -* R - pan up -* F - pan down -* T - more traces -* G - fewer traces -* -* E - toggle summary mode -* C - toggle color mode -* -* X - take snapshot -* Z - next snapshot -* P - persist snapshots to file -* L - load snapshots from file -* -* ctrl-Q - exit -* -****************************************************************************/ -gint -view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event) -{ - long long delta; - - switch (event->keyval) { - case GDK_w: // zoom in - view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON); - break; - - case GDK_s: // zoom out - view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON); - break; - - case GDK_a: // pan left - delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - if (s_v1->minvistime < delta) { - delta = s_v1->minvistime; - } - s_v1->minvistime -= delta; - s_v1->maxvistime -= delta; - recompute_hscrollbar(); - break; - - case GDK_d: // pan right - delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) { - /* - * @@@ this doesn't seem to quite reach the far right hand - * side correctly - not sure why. - */ - delta = g_events[g_nevents - 1].time - s_v1->maxvistime; - } - s_v1->minvistime += delta; - s_v1->maxvistime += delta; - recompute_hscrollbar(); - break; - - case GDK_r: // pan up - scroll_y(-1); - break; - - case GDK_f: // pan down - scroll_y(+1); - break; - - case GDK_t: // fewer tracks - view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON); - break; - - case GDK_g: // more tracks - view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON); - break; - - case GDK_e: // toggle summary mode - view1_button_click_callback - (NULL, (gpointer)(unsigned long long) - (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); - break; - - case GDK_c: // toggle color mode - color_mode ^= 1; - view1_display_when_idle(); - break; - - case GDK_p: // persist snapshots - write_snapshot(); - break; - - case GDK_l: // load snapshots - read_snapshot(); - break; - - case GDK_x: // take snapshot - view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON); - break; - - case GDK_z: // next snapshot - view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON); - break; - - case GDK_q: // ctrl-q is exit - if (event->state & GDK_CONTROL_MASK) { - gtk_main_quit(); - } - break; - } - return TRUE; -} - -/**************************************************************************** -* button_press_event -* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h -* -* This routine implements three functions: zoom-to-area, time ruler, and -* show/hide event detail popup. -* -* The left mouse button (button 1) has two simultaneous functions: event -* detail popup, and zoom-to-area. If the press and release events occur -* within a small delta-x, it's a detail popup event. Otherwise, it's -* an area zoom. -* -* The right mouse button (button 3) implements the time ruler. -****************************************************************************/ - -static gint -button_press_event (GtkWidget *widget, GdkEventButton *event) -{ - static GdkEventButton press1_event; - static boolean press1_valid; - static GdkEventButton press3_event; - static guint32 last_truler_time; - static boolean press3_valid; - static boolean zoom_bar_up; - int time_ax_y, xdelta; - char tmpbuf [128]; - double time_per_pixel; - - time_ax_y = 0; - - switch(event->type) { - case GDK_BUTTON_PRESS: - /* Capture the appropriate starting point */ - if (event->button == 1) { - press1_valid = TRUE; - press1_event = *event; - return(TRUE); - } - if (event->button == 3) { - press3_valid = TRUE; - press3_event = *event; - return(TRUE); - } - return(TRUE); - - case GDK_BUTTON_RELEASE: - /* Time ruler */ - if (press3_valid) { - press3_valid = FALSE; - /* Fix the cursor, and repaint the screen from scratch */ - gdk_window_set_cursor (da->window, norm_cursor); - view1_display_when_idle(); - return(TRUE); - } - /* Event select / zoom-to-area */ - if (press1_valid) { - press1_valid = FALSE; - xdelta = (int)(press1_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - /* is the mouse more or less where it started? */ - if (xdelta < 10) { - /* Control-left-mouse => sink the track */ - /* Shift-left-mouse => raise the track */ - if ((press1_event.state & GDK_CONTROL_MASK) == - GDK_CONTROL_MASK) { - move_current_track(event, s_v1, MOVE_BOTTOM); - } else if ((press1_event.state & GDK_SHIFT_MASK) == - GDK_SHIFT_MASK) { - move_current_track(event, s_v1, MOVE_TOP); - } else { - /* No modifiers: toggle the event */ - toggle_event_select(event, s_v1); - } - /* Repaint to get rid of the zoom bar */ - if (zoom_bar_up) { - /* Fix the cursor and leave. No zoom */ - gdk_window_set_cursor (da->window, norm_cursor); - zoom_bar_up = FALSE; - break; - } - } else { /* mouse moved enough to zoom */ - zoom_event(&press1_event, event, s_v1); - gdk_window_set_cursor (da->window, norm_cursor); - zoom_bar_up = FALSE; - } - } else if (event->button == 4) { - /* scroll wheel up */ - scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1); - } else if (event->button == 5) { - /* scroll wheel down */ - scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1); - } - return(TRUE); - - case GDK_MOTION_NOTIFY: - /* Button one followed by motion: draw zoom fence and fix cursor */ - if (press1_valid) { - /* Fence, cursor already set */ - if (zoom_bar_up) - return(TRUE); - - xdelta = (int)(press1_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - /* Haven't moved enough to declare a zoom sequence yet */ - if (xdelta < 10) - return(TRUE); - - /* Draw the zoom fence, use the key-down X coordinate */ - time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; - - line((int)(press1_event.x), s_v1->pop_offset, - (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK); - tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset, - TBOX_DRAW_BOXED); - gdk_window_set_cursor(da->window, zi_cursor); - zoom_bar_up = TRUE; - return(TRUE); - } - if (press3_valid) { - double nsec; - - gdk_window_set_cursor(da->window, zi_cursor); - - /* - * Some filtration is needed on Solaris, or the server will hang - */ - if (event->time - last_truler_time < 75) - return(TRUE); - - last_truler_time = event->time; - - line((int)(press3_event.x), s_v1->pop_offset, - (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); - - xdelta = (int)(press3_event.x - event->x); - if (xdelta < 0) - xdelta = -xdelta; - - time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) / - ((double)(s_v1->total_width - s_v1->pid_ax_width)); - - time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; - - line((int)(press3_event.x), s_v1->pop_offset, - (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); - /* - * Note: use a fixed-width format so it looks like we're - * erasing and redrawing the box. - */ - nsec = ((double)xdelta)*time_per_pixel; - if (nsec >1e9) { - sprintf(tmpbuf, "%8.3f sec ", nsec/1e9); - } else if (nsec > 1e6) { - sprintf(tmpbuf, "%8.3f msec", nsec/1e6); - } else if (nsec > 1e3) { - sprintf(tmpbuf, "%8.3f usec", nsec/1e3); - } else { - sprintf(tmpbuf, "%8.0f nsec", nsec); - } - tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset, - TBOX_DRAW_BOXED); - return(TRUE); - } - - default: - break; -#ifdef DEBUG - g_print("button:\ttype = %d\n", event->type); - g_print("\twindow = 0x%x\n", event->window); - g_print("\tsend_event = %d\n", event->send_event); - g_print("\ttime = %d\n", event->time); - g_print("\tx = %6.2f\n", event->x); - g_print("\ty = %6.2f\n", event->y); - g_print("\tpressure = %6.2f\n", event->pressure); - g_print("\txtilt = %6.2f\n", event->xtilt); - g_print("\tytilt = %6.2f\n", event->ytilt); - g_print("\tstate = %d\n", event->state); - g_print("\tbutton = %d\n", event->button); - g_print("\tsource = %d\n", event->source); - g_print("\tdeviceid = %d\n", event->deviceid); - g_print("\tx_root = %6.2f\n", event->x_root); - g_print("\ty_root = %6.2f\n", event->y_root); - return(TRUE); -#endif - } - - view1_display_when_idle(); - - return(TRUE); -} - -/**************************************************************************** -* configure_event -* Happens when the window manager resizes the viewer's main window. -****************************************************************************/ - -static gint -configure_event (GtkWidget *widget, GdkEventConfigure *event) -{ - /* Toss the previous drawing area backing store pixmap */ - if (pm) - gdk_pixmap_unref(pm); - - /* Create a new pixmap, paint it */ - pm = gdk_pixmap_new(widget->window, - widget->allocation.width, - widget->allocation.height, - -1); - gdk_draw_rectangle (pm, - widget->style->white_gc, - TRUE, - 0, 0, - widget->allocation.width, - widget->allocation.height); - - /* Reset the view geometry parameters, as required */ - s_v1->total_width = widget->allocation.width; - s_v1->total_height = widget->allocation.height; - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - - /* Schedule a repaint */ - view1_display_when_idle(); - return(TRUE); -} - -/**************************************************************************** -* expose_event -* Use backing store to fix the screen. -****************************************************************************/ -static gint expose_event (GtkWidget *widget, GdkEventExpose *event) -{ - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - pm, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - - return(FALSE); -} - -/**************************************************************************** -* event_search_internal -* This routine searches forward from s_srchindex, looking for s_srchcode; -* wraps at the end of the buffer. -****************************************************************************/ - -boolean event_search_internal (void) -{ - event_t *ep; - int i; - int index; - int pid_index; - boolean full_redisplay = FALSE; - ulonglong current_width; - char tmpbuf [64]; - - /* No events yet? Act like the search worked, to avoid a loop */ - if (g_nevents == 0) - return(TRUE); - - ep = (g_events + s_srchindex); - ep->flags &= ~EVENT_FLAG_SEARCHRSLT; - - /* - * Assume the user wants to search [plus or minus] - * from where they are. - */ -#ifdef notdef - if (ep->time < s_v1->minvistime) - s_srchindex = find_event_index (s_v1->minvistime); -#endif - - for (i = 1; i <= g_nevents; i++) { - index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ? - (s_srchindex - i) % g_nevents : - (i + s_srchindex) % g_nevents; - - ep = (g_events + index); - - if (ep->code == s_srchcode) { - if (s_srchfail_up) - message_line(""); - s_srchindex = index; - pid_index = ep->pid->pid_index; - - /* Need a vertical scroll? */ - if ((pid_index < s_v1->first_pid_index) || - (pid_index >= s_v1->first_pid_index + s_v1->npids)) { - if (pid_index > (g_npids - s_v1->npids)) - pid_index = (g_npids - s_v1->npids); - s_v1->first_pid_index = pid_index; - GTK_ADJUSTMENT(s_view1_vsadj)->value = - (gdouble)s_v1->first_pid_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - full_redisplay = TRUE; - } - - /* Need a horizontal scroll? */ - if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) { - current_width = (s_v1->maxvistime - s_v1->minvistime); - if (ep->time < ((current_width+1) / 2)) { - s_v1->minvistime = 0ll; - s_v1->maxvistime = current_width; - } else { - s_v1->minvistime = ep->time - ((current_width+1)/2); - s_v1->maxvistime = ep->time + ((current_width+1)/2); - } - recompute_hscrollbar(); - full_redisplay = TRUE; - } - ep->flags |= EVENT_FLAG_SEARCHRSLT; - full_redisplay = TRUE; - -#ifdef NOTDEF - if (!full_redisplay){ - if (!s_result_up) { - s_result_up = TRUE; - time_per_pixel = dtime_per_pixel(s_v1); - - y = pid_index*s_v1->strip_height + s_v1->event_offset; - x = s_v1->pid_ax_width + - (int)(((double)(ep->time - s_v1->minvistime)) / - time_per_pixel); - sprintf(tmpbuf, "SEARCH RESULT"); - tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED); - line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK); - } else { - full_redisplay = TRUE; - } - } -#endif - - if (full_redisplay) - view1_display_when_idle(); - return(TRUE); - } - } - sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode); - message_line(tmpbuf); - s_srchfail_up = TRUE; - return(TRUE); -} - -/**************************************************************************** -* event_search_callback -****************************************************************************/ - -boolean event_search_callback (char *s) -{ - /* No events yet? Act like the search worked, to avoid a loop */ - if (g_nevents == 0) - return(TRUE); - - s_srchcode = atol(s); - - if (s_srchcode == 0) - return(FALSE); - - return(event_search_internal()); -} - -/**************************************************************************** -* event_search -****************************************************************************/ - -static void event_search (void) -{ - modal_dialog ("Event Search: Please Enter Event Code", - "Invalid: Please Reenter Event Code", NULL, - event_search_callback); -} - -/**************************************************************************** -* init_track_colors -****************************************************************************/ -static void init_track_colors(void) -{ - int i; - unsigned hash; - char *label_char; - unsigned RGB[3]; - gboolean dont_care[g_npids]; - - /* - * If we've already allocated the colors once, then in theory we should - * just be able to re-order the GCs already created to match the new track - * order; the track -> color mapping doesn't currently change at runtime. - * However, it's easier just to allocate everything from fresh. As a nod in - * the direction of politeness towards our poor abused X server, we at - * least mop up the previously allocated GCs first, although in practice - * even omitting this didn't seem to cause a problem. - */ - if (s_color != NULL ) { - gdk_colormap_free_colors(gtk_widget_get_colormap(da), - s_color, g_npids); - memset(s_color, 0, sizeof(GdkColor) * g_npids); - } else { - /* - * First time through: allocate the array to hold the GCs. - */ - s_color = g_malloc(sizeof(GdkColor) * g_npids); - } - - /* - * Go through and assign a color for each track. - */ - for (i = 0; i < g_npids; i++) { - /* - * We compute the color from a hash of the thread name. That way we get - * a distribution of different colors, and the same thread has the same - * color across multiple data sets. Unfortunately, even though the - * process name and thread id are invariant across data sets, the - * process id isn't, so we want to exclude that from the hash. Since - * the pid appears in parentheses after the process name and tid, we - * can just stop at the '(' character. - * - * We could create a substring and use the CLIB Jenkins hash, but given - * we're hashing ascii data, a suitable Bernstein hash is pretty much - * just as good, and it's easiest just to compute it inline. - */ - label_char = get_track_label(g_pids[i].pid_value); - hash = 0; - while (*label_char != '\0' && *label_char != '(') { - hash = hash * 33 + *label_char++; - } - hash += hash >> 5; /* even out the lower order bits a touch */ - - /* - * OK, now we have our hash. We get the color by using the first three - * bytes of the hash for the RGB values (expanded from 8 to 16 bits), - * and then use the fourth byte to choose one of R, G, B and mask this - * one down. This ensures the color can't be too close to white and - * therefore hard to see. - * - * We also drop the top bit of the green, since bright green on its own - * is hard to see against white. Generally we err on the side of - * keeping it dark, rather than using the full spectrum of colors. This - * does result in something of a preponderance of muddy colors and a - * bit of a lack of cheery bright ones, but at least you can read - * everything. It would be nice to do better. - */ - RGB[0] = (hash & 0xff000000) >> 16; - RGB[1] = (hash & 0x007f0000) >> 8; - RGB[2] = (hash & 0x0000ff00); - RGB[hash % 3] &= 0x1fff; - - { - GdkColor color = {0, RGB[0], RGB[1], RGB[2]}; - s_color[i] = color; - g_pids[i].color_index = i; - } - } - - /* - * Actually allocate the colors in one bulk operation. We ignore the return - * values. - */ - gdk_colormap_alloc_colors(gtk_widget_get_colormap(da), - s_color, g_npids, FALSE, TRUE, dont_care); -} - - -/**************************************************************************** -* chase_event_etc -* Reorder the pid_index fields so the viewer "chases" the last selected -* event. -****************************************************************************/ - -static void chase_event_etc(enum chase_mode mode) -{ - pid_sort_t *psp, *new_pidvec; - pid_data_t *pp; - event_t *ep; - int pids_mapped; - ulong code_to_chase; - ulong datum_to_chase; - ulong pid_to_chase; - int i; - int winner; - - if (!s_last_selected_event) { - infobox("No selected event", - "\nPlease select an event and try again...\n"); - return; - } - - /* Clear all index assignments */ - psp = g_pids; - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = 0xFFFFFFFF; - psp++; - } - - ep = s_last_selected_event; - code_to_chase = ep->code; - datum_to_chase = ep->datum; - pid_to_chase = ep->pid->pid_value; - pids_mapped = 0; - new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); - - while (1) { - if (srch_chase_dir == SRCH_CHASE_FORWARD) { - if (ep >= g_events + g_nevents) - break; - } else { - if (ep < g_events) - break; - } - - winner = 0; - switch(mode) { - case CHASE_EVENT: - if (ep->code == code_to_chase) { - winner = 1; - } - break; - - case CHASE_DATUM: - if (ep->datum == datum_to_chase) { - winner = 1; - } - break; - - case CHASE_TRACK: - if (ep->pid->pid_value == pid_to_chase) { - winner = 1; - } - break; - - default: - infobox("BUG", "unknown mode in chase_event_etc\n"); - break; - } - - if (winner) { - if (ep->pid->pid_index == 0xFFFFFFFF) { - ep->pid->pid_index = pids_mapped; - new_pidvec[pids_mapped].pid = ep->pid; - new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; - new_pidvec[pids_mapped].color_index = 0; - pids_mapped++; - if (pids_mapped == g_npids) - break; - } - } - if (srch_chase_dir == SRCH_CHASE_FORWARD) - ep++; - else - ep--; - } - - /* Pass 2, first-to-last, to collect stragglers */ - ep = g_events; - - while (ep < g_events + g_nevents) { - if (ep->pid->pid_index == 0xFFFFFFFF) { - ep->pid->pid_index = pids_mapped; - new_pidvec[pids_mapped].pid = ep->pid; - new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; - new_pidvec[pids_mapped].color_index = 0; - pids_mapped++; - if (pids_mapped == g_npids) - break; - } - ep++; - } - - if (pids_mapped != g_npids) { - infobox("BUG", "\nDidn't map all pids in chase_event_etc\n"); - } - - g_free (g_pids); - g_pids = new_pidvec; - - /* - * The new g_pids vector contains the "chase" sort, so we revert - * the pid_index mapping to an identity map - */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - - /* AutoScroll the PID axis so we show the first "chased" event */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - init_track_colors(); - view1_display_when_idle(); -} - -/**************************************************************************** -* unchase_event_etc -* Copy g_original_pids to g_pids, revert index mapping -****************************************************************************/ -static void unchase_event_etc(void) -{ - int i; - pid_sort_t *psp; - pid_data_t *pp; - - memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids); - - /* Fix the pid structure index mappings */ - psp = g_pids; - - for (i = 0; i < g_npids; i++) { - pp = psp->pid; - pp->pid_index = i; - psp++; - } - - /* Scroll PID axis to the top */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - init_track_colors(); - view1_display_when_idle(); -} - -/**************************************************************************** -* print_ps_header -* To fit a reasonable-sized landscape mode plot onto letter-size paper, -* scale everything by .75. -****************************************************************************/ - -static void print_ps_header (v1_geometry_t *vp, char *filename) -{ - time_t now; - - now = time(0); - - fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n"); - fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n"); - fprintf(s_printfp, "%%%%Title: %s\n", filename); - fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now)); - fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n"); - fprintf(s_printfp, "%%%%Origin: 0 0\n"); - fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height, - vp->total_width); - fprintf(s_printfp, "%%%%LanguageLevel: 2\n"); - fprintf(s_printfp, "%%%%Pages: 1\n"); - fprintf(s_printfp, "%%%%Page: 1 1\n"); - fprintf(s_printfp, "%%%%EOF\n"); - fprintf(s_printfp, "/Times-Roman findfont\n"); - fprintf(s_printfp, "12 scalefont\n"); - fprintf(s_printfp, "setfont\n"); - fprintf(s_printfp, ".75 .75 scale\n"); -} - -/**************************************************************************** -* xrt -* Xcoordinate rotate and translate. We need to emit postscript that -* has a reasonable aspect ratio for printing. To do that, we rotate the -* intended picture by 90 degrees, using the standard 2D rotation -* formula: -* -* Xr = x*cos(theta) - y*sin(theta); -* Yr = x*sin(theta) + y*cos(theta); -* -* If we let theta = 90, this reduces to -* Xr = -y -* Yr = x -* -* Translate back to the origin in X by adding Ymax, yielding -* Xrt = Ymax - y -****************************************************************************/ - -static inline int xrt(int x, int y) -{ - return (s_v1->total_height - y); -} - -static inline int yrt(int x, int y) -{ - return(x); -} - -/**************************************************************************** -* print_screen_callback -****************************************************************************/ - -static boolean print_screen_callback(char *filename) -{ - s_printfp = fopen (filename, "wt"); - - if (s_printfp == NULL) - return(FALSE); - - /* - * This variable allows us to magically turn the view1 display - * code into a print-driver, with a minimum of fuss. The idea is to - * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding - * the required value, aka s_print_offset. - * Make sure to fix g2.h if you mess here, or vice versa. - */ - s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN; - - print_ps_header(s_v1, filename); - - display_pid_axis(s_v1); - display_event_data(s_v1); - display_time_axis(s_v1); - - fclose (s_printfp); - s_printfp = 0; - s_print_offset = 0; - - /* For tactile feedback */ - view1_display_when_idle(); - return(TRUE); -} - -/**************************************************************************** -* view1_button_click_callback -****************************************************************************/ - -static void view1_button_click_callback(GtkButton *item, gpointer data) -{ - enum view1_button_click click = (enum view1_button_click) data; - event_t *ep; - ulonglong event_incdec; - ulonglong current_width; - ulonglong zoom_delta; - - - current_width = s_v1->maxvistime - s_v1->minvistime; - event_incdec = (current_width) / 3; - - if (event_incdec == 0LL) - event_incdec = 1; - - zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6; - - switch(click) { - case TOP_BUTTON: - /* First PID to top of window */ - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - break; - - case BOTTOM_BUTTON: - s_v1->first_pid_index = g_npids - s_v1->npids; - if (s_v1->first_pid_index < 0) - s_v1->first_pid_index = 0; - GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index; - gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); - break; - - case SNAP_BUTTON: - add_snapshot(); - break; - - case NEXT_BUTTON: - next_snapshot(); - break; - - case DEL_BUTTON: - del_snapshot(); - break; - - case CHASE_EVENT_BUTTON: - chase_event_etc(CHASE_EVENT); - break; - - case CHASE_DATUM_BUTTON: - chase_event_etc(CHASE_DATUM); - break; - - case CHASE_TRACK_BUTTON: - chase_event_etc(CHASE_TRACK); - break; - - case UNCHASE_BUTTON: - unchase_event_etc(); - break; - - case START_BUTTON: - start_button: - s_v1->minvistime = 0LL; - s_v1->maxvistime = current_width; - recompute_hscrollbar(); - break; - - case ZOOMIN_BUTTON: - s_v1->minvistime += zoom_delta; - s_v1->maxvistime -= zoom_delta; - recompute_hscrollbar(); - break; - - case SEARCH_AGAIN_BUTTON: - if (s_srchcode) { - event_search_internal(); - break; - } - /* NOTE FALLTHROUGH */ - - case SEARCH_BUTTON: - event_search(); - break; - - case ZOOMOUT_BUTTON: - if (zoom_delta == 0LL) - zoom_delta = 1; - - if (s_v1->minvistime >= zoom_delta) { - s_v1->minvistime -= zoom_delta; - s_v1->maxvistime += zoom_delta; - } else { - s_v1->minvistime = 0; - s_v1->maxvistime += zoom_delta*2; - } - - if ((s_v1->maxvistime - s_v1->minvistime) * 8 > - g_events[g_nevents-1].time * 9) { - s_v1->minvistime = 0; - s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8; - } - recompute_hscrollbar(); - break; - - case END_BUTTON: - ep = (g_events + g_nevents - 1); - s_v1->maxvistime = ep->time + event_incdec/3; - s_v1->minvistime = s_v1->maxvistime - current_width; - if (s_v1->minvistime > s_v1->maxvistime) - goto start_button; - recompute_hscrollbar(); - break; - - case MORE_TRACES_BUTTON: - /* Reduce the strip height to fit more traces on screen */ - s_v1->strip_height -= 1; - - if (s_v1->strip_height < 1) { - s_v1->strip_height = 1; - } - - /* Recalculate the number of strips on the screen */ - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - recompute_vscrollbar(); - break; - - case LESS_TRACES_BUTTON: - /* Increase the strip height to fit fewer on the screen */ - s_v1->strip_height += 1; - if (s_v1->strip_height > 80) { - s_v1->strip_height = 80; - } - - /* Recalculate the number of strips on the screen */ - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - recompute_vscrollbar(); - break; - - case FORWARD_BUTTON: - srch_chase_dir = SRCH_CHASE_FORWARD; - gtk_widget_hide (s_view1_forward_button); - gtk_widget_show (s_view1_backward_button); - break; - - case BACKWARD_BUTTON: - srch_chase_dir = SRCH_CHASE_BACKWARD; - gtk_widget_show (s_view1_forward_button); - gtk_widget_hide (s_view1_backward_button); - break; - - case SUMMARY_BUTTON: - summary_mode = TRUE; - gtk_widget_hide (s_view1_summary_button); - gtk_widget_show (s_view1_nosummary_button); - break; - - case NOSUMMARY_BUTTON: - summary_mode = FALSE; - gtk_widget_show (s_view1_summary_button); - gtk_widget_hide (s_view1_nosummary_button); - break; - } - - view1_display_when_idle(); -} - -/**************************************************************************** -* view1_print_callback -****************************************************************************/ - -void view1_print_callback (GtkToggleButton *notused, gpointer nu2) -{ - modal_dialog("Print Screen (PostScript format) to file:", - "Invalid file: Print Screen to file:", - "g2.ps", print_screen_callback); -} - -/**************************************************************************** -* view1_hscroll -****************************************************************************/ - -static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused) -{ - ulonglong current_width; - - current_width = (s_v1->maxvistime - s_v1->minvistime); - - s_v1->minvistime = (ulonglong)(adj->value); - s_v1->maxvistime = s_v1->minvistime + current_width; - - view1_display_when_idle(); - -#ifdef NOTDEF - g_print ("adj->lower = %.2f\n", adj->lower); - g_print ("adj->upper = %.2f\n", adj->upper); - g_print ("adj->value = %.2f\n", adj->value); - g_print ("adj->step_increment = %.2f\n", adj->step_increment); - g_print ("adj->page_increment = %.2f\n", adj->page_increment); - g_print ("adj->page_size = %.2f\n", adj->page_size); -#endif -} - -/**************************************************************************** -* view1_vscroll -****************************************************************************/ - -static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused) -{ - s_v1->first_pid_index = (int)adj->value; - view1_display_when_idle(); -} - -void set_pid_ax_width(int width) -{ - s_v1->pid_ax_width = width; - view1_display_when_idle(); -} - -/**************************************************************************** -* view1_init -****************************************************************************/ - -void view1_init(void) -{ - - c_view1_draw_width = atol(getprop_default("drawbox_width", "700")); - c_view1_draw_height = atol(getprop_default("drawbox_height", "400")); - - s_v1->pid_ax_width = 80; - s_v1->time_ax_height = 80; - s_v1->time_ax_spacing = 100; - s_v1->strip_height = 25; - s_v1->pop_offset = 20; - s_v1->pid_ax_offset = 34; - s_v1->event_offset = 40; - s_v1->total_height = c_view1_draw_height; - s_v1->total_width = c_view1_draw_width; - s_v1->first_pid_index = 0; - - s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / - s_v1->strip_height; - - s_v1->minvistime = 0; - s_v1->maxvistime = 200; - - s_view1_vbox = gtk_vbox_new(FALSE, 5); - - s_view1_hbox = gtk_hbox_new(FALSE, 5); - - da = gtk_drawing_area_new(); - gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width, - c_view1_draw_height); - -#ifdef NOTDEF - gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", - (GtkSignalFunc) motion_notify_event, NULL); -#endif - - gtk_signal_connect (GTK_OBJECT (da), "expose_event", - (GtkSignalFunc) expose_event, NULL); - - gtk_signal_connect (GTK_OBJECT(da),"configure_event", - (GtkSignalFunc) configure_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "button_press_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "button_release_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", - (GtkSignalFunc) button_press_event, NULL); - - gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK - | GDK_BUTTON_MOTION_MASK); - - - gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0); - - g_font = gdk_font_load ("8x13"); - if (g_font == NULL) { - g_error("Couldn't load 8x13 font...\n"); - } - gdk_font_ref(g_font); - - /* PID axis menu */ - s_view1_vmenubox = gtk_vbox_new(FALSE, 5); - - s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj)); - - gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed", - GTK_SIGNAL_FUNC (view1_vscroll), - (gpointer)s_view1_vscroll); - - s_view1_topbutton = gtk_button_new_with_label("Top"); - s_view1_bottombutton = gtk_button_new_with_label("Bottom"); - - gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) TOP_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) BOTTOM_BUTTON); - - /* More Traces button and Less Traces button */ - s_view1_more_traces_button = gtk_button_new_with_label("More Traces"); - s_view1_less_traces_button = gtk_button_new_with_label("Less Traces"); - gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) MORE_TRACES_BUTTON); - gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) LESS_TRACES_BUTTON); - -#ifdef NOTDEF - /* Trick to bottom-justify the menu: */ - s_view1_pad1 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1, - TRUE, FALSE, 0); - -#endif - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox, - FALSE, FALSE, 0); - - /* Time axis menu */ - - s_view1_hmenubox = gtk_hbox_new(FALSE, 5); - - s_view1_startbutton = gtk_button_new_with_label("Start"); - - s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn"); - - s_view1_searchbutton = gtk_button_new_with_label("Search"); - - s_view1_srchagainbutton = gtk_button_new_with_label("Search Again"); - - s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut"); - - s_view1_endbutton = gtk_button_new_with_label("End"); - - gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) START_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) ZOOMIN_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SEARCH_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SEARCH_AGAIN_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) ZOOMOUT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) END_BUTTON); - - s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */, - 0.0 /* minimum value */, - 2000.0 /* maximum value */, - 0.1 /* step increment */, - 10.0/* page increment */, - 10.0/* page size */); - - s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj)); - - gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed", - GTK_SIGNAL_FUNC (view1_hscroll), - (gpointer)s_view1_hscroll); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox, - FALSE, FALSE, 0); - - - s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5); - - s_view1_snapbutton = gtk_button_new_with_label("Snap"); - - s_view1_nextbutton = gtk_button_new_with_label("Next"); - - s_view1_delbutton = gtk_button_new_with_label("Del"); - - s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent"); - - s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum"); - - s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack"); - - s_view1_unchasebutton = gtk_button_new_with_label("NoChase"); - - s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)"); - s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)"); - - s_view1_summary_button = gtk_button_new_with_label("Summary"); - s_view1_nosummary_button = gtk_button_new_with_label("NoSummary"); - - gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SNAP_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) NEXT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) DEL_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_EVENT_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_DATUM_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) CHASE_TRACK_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) UNCHASE_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) FORWARD_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) BACKWARD_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) SUMMARY_BUTTON); - - gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked", - GTK_SIGNAL_FUNC(view1_button_click_callback), - (gpointer) NOSUMMARY_BUTTON); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button, - FALSE, FALSE, 0); - - s_view1_label = gtk_label_new(NULL); - - gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox, - TRUE, TRUE, 0); - - gtk_widget_show_all (s_view1_vbox); - GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS); - gtk_widget_grab_focus(da); - - gtk_widget_hide (s_view1_forward_button); - gtk_widget_hide (summary_mode ? s_view1_summary_button - : s_view1_nosummary_button); - - zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width, - zi_height); - zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width, - zi_height); - - zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source, - zi_mask, &fg_black, - &bg_white, zi_x_hot, - zi_y_hot); - gdk_pixmap_unref (zi_source); - gdk_pixmap_unref (zi_mask); - - norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW); -} - -/**************************************************************************** -* line_print -****************************************************************************/ - -void line_print (int x1, int y1, int x2, int y2) -{ - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1), - yrt(x1, s_v1->total_height - y1)); - - fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2), - yrt (x2, s_v1->total_height - y2)); - fprintf(s_printfp, "1 setlinewidth\n"); - fprintf(s_printfp, "stroke\n"); -} - -/**************************************************************************** -* tbox_print -****************************************************************************/ -GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function, - GdkRectangle *rp) -{ - if (function == TBOX_PRINT_BOXED) { - rp->width -= 4; - } - - if ((function == TBOX_PRINT_BOXED) || - (function == TBOX_PRINT_EVENT)) { - - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "0 setlinewidth\n"); - fprintf(s_printfp, "%d %d moveto\n", - xrt(rp->x, s_v1->total_height - rp->y), - yrt(rp->x, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "%d %d lineto\n", - xrt (rp->x+rp->width, s_v1->total_height - rp->y), - yrt (rp->x+rp->width, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)), - yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height))); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x, s_v1->total_height - (rp->y+rp->height)), - yrt(rp->x, s_v1->total_height - (rp->y+rp->height))); - - fprintf(s_printfp, "%d %d lineto\n", - xrt(rp->x, s_v1->total_height - rp->y), - yrt(rp->x, s_v1->total_height - rp->y)); - - fprintf(s_printfp, "stroke\n"); - } - - if ((function == TBOX_PRINT_BOXED) || - (function == TBOX_PRINT_PLAIN)) { - - fprintf(s_printfp, "newpath\n"); - fprintf(s_printfp, "%d %d moveto\n", - xrt(x, s_v1->total_height - (y-2)), - yrt(x, s_v1->total_height - (y-2))); - fprintf(s_printfp, "gsave\n"); - fprintf(s_printfp, "90 rotate\n"); - fprintf(s_printfp, "(%s) show\n", s); - fprintf(s_printfp, "grestore\n"); - } - - return(rp); -} - -/**************************************************************************** -* tbox - draws an optionally boxed string whose lower lefthand -* corner is at (x, y). As usual, Y is backwards. -****************************************************************************/ - -GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function) -{ - static GdkRectangle update_rect; - gint lbearing, rbearing, width, ascent, descent; - - gdk_string_extents (g_font, s, - &lbearing, &rbearing, - &width, &ascent, &descent); - - /* - * If we have enough room to display full size events, then just - * use the BOXED function instead of the EVENT function. - */ - if (s_v1->strip_height > 9) { - switch (function) { - case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break; - case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break; - case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break; - default: - break; - /* Nothing */ - } - } - - switch (function) { - case TBOX_DRAW_BOXED: - gdk_draw_rectangle (pm, da->style->white_gc, TRUE, - x, y - (ascent+descent+3), width + 2, - ascent + descent + 3); - - gdk_draw_rectangle (pm, da->style->black_gc, FALSE, - x, y - (ascent+descent+3), width + 2, - ascent + descent + 3); - - gdk_draw_string (pm, g_font, da->style->black_gc, - x + 1, y - 1, (const gchar *)s); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_BOXED: - update_rect.x = x; - update_rect.y = y -(ascent+descent+3); - update_rect.width = width + 3; - update_rect.height = ascent + descent + 4; - if (function == TBOX_DRAW_BOXED) - gtk_widget_draw (da, &update_rect); - break; - - case TBOX_DRAW_EVENT: - /* We have a small event to draw...no text */ - gdk_draw_rectangle (pm, da->style->black_gc, FALSE, - x, y - 1, 3, 3); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_EVENT: - update_rect.x = x; - update_rect.y = y - 1; - update_rect.width = 4; - update_rect.height = 4; - if (function == TBOX_DRAW_EVENT) - gtk_widget_draw (da, &update_rect); - break; - - - case TBOX_DRAW_PLAIN: - - gdk_draw_string (pm, g_font, da->style->black_gc, - x + 1, y - 1, (const gchar *)s); - /* NOTE FALLTHROUGH */ - case TBOX_GETRECT_PLAIN: - update_rect.x = x; - update_rect.y = y -(ascent+descent+1); - update_rect.width = width; - update_rect.height = ascent + descent; - if (function == TBOX_DRAW_PLAIN) - gtk_widget_draw (da, &update_rect); - break; - - case TBOX_PRINT_BOXED: - update_rect.x = x; - update_rect.y = y -(ascent+descent+3); - update_rect.width = width + 3; - update_rect.height = ascent + descent + 4; - /* note fallthrough */ - case TBOX_PRINT_PLAIN: - return(tbox_print(s, x, y, function, &update_rect)); - - case TBOX_PRINT_EVENT: - /* We have a small event box to print...no text */ - update_rect.x = x; - update_rect.y = y - 1; - update_rect.width = 4; - update_rect.height = 4; - return(tbox_print(s, x, y, function, &update_rect)); - } - return(&update_rect); -} - -/**************************************************************************** -* line -* -* For lines there is a primitive batching facility, that doesn't update -* the drawing area until the batch is complete. This is handy for drawing -* the pid axis and for summary mode. -* -* line_batch_mode contains the state for this: -* -* BATCH_OFF: no batching, update for every line -* BATCH_NEW: just entered a batch, so initialize the area to update from -* scratch -* BATCH_EXISTING: have drawn at least one line in batch mode, so the update -* area should only be expanded from now on to include the -* union of the "rectangular hull" of all lines -****************************************************************************/ - -static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode; -static int line_batch_count; -static int line_minx, line_miny, line_maxx, line_maxy; - -void line_batch_start (void) -{ - line_batch_mode = BATCH_NEW; - line_batch_count = 0; -} - -void line_batch_end (void) -{ - GdkRectangle update_rect; - if (line_batch_count > 0) { - update_rect.x = line_minx; - update_rect.y = line_miny; - update_rect.width = (line_maxx - line_minx) + 1; - update_rect.height = (line_maxy - line_miny) + 1; - gtk_widget_draw (da, &update_rect); - } - line_batch_mode = BATCH_OFF; -} - -void line (int x1, int y1, int x2, int y2, enum view1_line_fn function) -{ - GdkRectangle update_rect; - GdkGC *gc = NULL; - - switch(function) { - case LINE_DRAW_BLACK: - gc = da->style->black_gc; - break; - - case LINE_DRAW_WHITE: - gc = da->style->white_gc; - break; - - case LINE_PRINT: - line_print (x1, y1, x2, y2); - return; - } - - gdk_draw_line (pm, gc, x1, y1, x2, y2); - - switch (line_batch_mode) { - case BATCH_OFF: - update_rect.x = x1; - update_rect.y = y1; - update_rect.width = (x2-x1) + 1; - update_rect.height = (y2-y1) + 1; - gtk_widget_draw (da, &update_rect); - break; - - case BATCH_NEW: - line_minx = x1; - line_maxx = x2; - line_miny = y1; - line_maxy = y2; - line_batch_mode = BATCH_EXISTING; - line_batch_count = 1; - break; - - case BATCH_EXISTING: - if (line_minx > x1) - line_minx = x1; - if (line_miny > y1) - line_miny = y1; - if (line_maxx < x2) - line_maxx = x2; - if (line_maxy < y2) - line_maxy = y2; - line_batch_count++; - break; - } -} - - -/**************************************************************************** -* display_pid_axis -****************************************************************************/ - -static void display_pid_axis(v1_geometry_t *vp) -{ - int y, i, label_tick; - int last_printed_y = -vp->strip_height; - pid_sort_t *pp; - int pid_index; - char *label_fmt; - char tmpbuf [128]; - - /* No pids yet? Outta here */ - if (g_pids == NULL) - return; - - line_batch_start(); - - for (i = 0; i < vp->npids; i++) { - pid_index = vp->first_pid_index + i; - if (pid_index >= g_npids) - break; - - set_color(pid_index); - pp = (g_pids + pid_index); - - label_fmt = get_track_label(pp->pid_value); - snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value); - - y = i*vp->strip_height + vp->pid_ax_offset; - - /* - * Have we incremented enough space to have another label not - * overlap the previous label? - */ - if (y - last_printed_y > 9) { - /* Draw label */ - tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset); - - last_printed_y = y; - - /* - * And let the line stick out a bit more to indicate this label - * relates to the following line. - */ - label_tick = 4; - } - else { - label_tick = 0; - } - - /* Draw axis line, but only if the lines aren't too close together */ - if (vp->strip_height > 4) { - line(vp->pid_ax_width - label_tick, y+4*s_print_offset, - vp->total_width, y+4*s_print_offset, - LINE_DRAW_BLACK+s_print_offset); - } - } - - set_color(COLOR_DEFAULT); - line_batch_end(); -} - -/**************************************************************************** -* view1_read_events_callback -* New event data just showed up, reset a few things. -****************************************************************************/ - -void view1_read_events_callback(void) -{ - int max_vis_index; - - s_v1->first_pid_index = 0; - - max_vis_index = 300; - if (max_vis_index > g_nevents) - max_vis_index = g_nevents-1; - - s_v1->minvistime = 0LL; - s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8; - s_srchindex = 0; - s_srchcode = 0; - s_last_selected_event = 0; - - init_track_colors(); - - recompute_hscrollbar(); - recompute_vscrollbar(); -} - -/**************************************************************************** -* display_event_data -****************************************************************************/ - -static void display_event_data(v1_geometry_t *vp) -{ - int start_index; - int pid_index; - int x, y; - event_t *ep; - event_def_t *edp; - double time_per_pixel; - char tmpbuf[1024]; - GdkRectangle *print_rect; - int *last_x_used; - - /* Happens if one loads the event def header first, for example. */ - if (g_nevents == 0) - return; - - time_per_pixel = dtime_per_pixel(vp); - - start_index = find_event_index (vp->minvistime); - - /* Scrolled too far right? */ - if (start_index >= g_nevents) - return; - - ep = (g_events + start_index); - - if (s_print_offset || summary_mode) { - last_x_used = (int *)g_malloc0(vp->npids * sizeof(int)); - } else { - last_x_used = NULL; - } - - line_batch_start(); - - while (ep < (g_events + g_nevents) && - (ep->time < vp->maxvistime)) { - pid_index = ep->pid->pid_index; - set_color(pid_index); - - /* First filter: pid out of range */ - if ((pid_index < vp->first_pid_index) || - (pid_index >= vp->first_pid_index + vp->npids)) { - ep++; - continue; - } - - /* Second filter: event hidden */ - edp = find_event_definition (ep->code); - if (!edp->selected) { - ep++; - continue; - } - - /* Display it... */ - - pid_index -= vp->first_pid_index; - - y = pid_index*vp->strip_height + vp->event_offset; - - x = vp->pid_ax_width + - (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); - - if (last_x_used != NULL && x < last_x_used[pid_index]) { - ep++; - continue; - } - - if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) { - if (ep->flags & EVENT_FLAG_SELECT) { - format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); -#ifdef NOTDEF - sprintf(tmpbuf, edp->name); - sprintf(tmpbuf+strlen(tmpbuf), ": "); - sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum); -#endif - } else { - sprintf(tmpbuf, "SEARCH RESULT"); - } - print_rect = tbox(tmpbuf, x, y - vp->pop_offset, - TBOX_DRAW_BOXED+s_print_offset); - line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset); - if (last_x_used != NULL) - last_x_used[pid_index] = x + print_rect->width; - } - if (summary_mode) { - int delta = vp->strip_height / 3; - if (delta < 1) - delta = 1; - y = pid_index*vp->strip_height + vp->pid_ax_offset; - line(x, y - delta, x, y + delta, LINE_DRAW_BLACK); - last_x_used[pid_index] = x + 1; - } else { - sprintf(tmpbuf, "%ld", ep->code); - print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset); - if (last_x_used != NULL) - last_x_used[pid_index] = x + print_rect->width; - } - - ep++; - } - if (last_x_used) - g_free(last_x_used); - line_batch_end(); - set_color(COLOR_DEFAULT); -} - -/**************************************************************************** -* display_clear -****************************************************************************/ - -static void display_clear(void) -{ - GdkRectangle update_rect; - - gdk_draw_rectangle (pm, da->style->white_gc, TRUE, - 0, 0, da->allocation.width, - da->allocation.height); - - update_rect.x = 0; - update_rect.y = 0; - update_rect.width = da->allocation.width; - update_rect.height = da->allocation.height; - - gtk_widget_draw (da, &update_rect); -} - -/**************************************************************************** -* display_time_axis -****************************************************************************/ - -static void display_time_axis(v1_geometry_t *vp) -{ - int x, y, i; - int xoffset, nticks; - char tmpbuf [128]; - double unit_divisor; - double time; - char *units; - double time_per_pixel; - - y = vp->npids * vp->strip_height + vp->pid_ax_offset; - - x = vp->pid_ax_width; - - nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing; - - time_per_pixel = dtime_per_pixel(vp); - - units = "ns"; - unit_divisor = 1.00; - - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "us"; - unit_divisor = 1000.00; - } - - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "ms"; - unit_divisor = 1000.00*1000.00; - } - if ((vp->maxvistime / unit_divisor) > 1000) { - units = "s"; - unit_divisor = 1000.00*1000.00*1000.00; - } - - /* Draw line */ - line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset); - - xoffset = 0; - - for (i = 0; i < nticks; i++) { - /* Tick mark */ - line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset); - - time = (double)(x + xoffset - vp->pid_ax_width); - time *= time_per_pixel; - time += (double)(vp->minvistime); - time /= unit_divisor; - - sprintf (tmpbuf, "%.2f%s", time, units); - - tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset); - - xoffset += vp->time_ax_spacing; - } -} - -/**************************************************************************** -* clear_scoreboard -* Forget about any temporary displays, they're gone now... -****************************************************************************/ - -static void clear_scoreboard(void) -{ - s_result_up = FALSE; -} - -/**************************************************************************** -* view1_display -****************************************************************************/ - -void view1_display(void) -{ - display_clear(); - display_pid_axis(s_v1); - display_event_data(s_v1); - display_time_axis(s_v1); - clear_scoreboard(); -} - -static gint idle_tag; - -/**************************************************************************** -* view1_display_eventually -****************************************************************************/ - -static void view1_display_eventually(void) -{ - gtk_idle_remove(idle_tag); - idle_tag = 0; - view1_display(); -} - - -/**************************************************************************** -* view1_display_when_idle -****************************************************************************/ - -void view1_display_when_idle(void) -{ - if (idle_tag == 0) { - idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0); - } -} - -/**************************************************************************** -* view1_about -****************************************************************************/ - -void view1_about (char *tmpbuf) -{ - int nsnaps; - snapshot_t *snaps; - - sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n", - s_v1->minvistime, s_v1->maxvistime); - sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n", - s_v1->strip_height); - - for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) { - nsnaps++; - } - sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps); -} diff --git a/gmod/gmod/mod_vpp.c b/gmod/gmod/mod_vpp.c index 4a1da83cacd..572f9ef58ab 100644 --- a/gmod/gmod/mod_vpp.c +++ b/gmod/gmod/mod_vpp.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include mmodule vpp_module; diff --git a/perftool/Makefile.am b/perftool/Makefile.am deleted file mode 100644 index ac652aa6a2c..00000000000 --- a/perftool/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign -AM_CFLAGS = -Wall - -bin_PROGRAMS = c2cpel cpelatency cpeldump cpelinreg cpelstate - -lib_LTLIBRARIES = libcperf.la - -libcperf_la_SOURCES = delsvec.c linreg.c props.c cpel_util.c - -TOOL_LIBS = libcperf.la -lvppinfra -lm - -c2cpel_SOURCE = c2cpel.c -c2cpel_LDADD = $(TOOL_LIBS) - -cpelatency_SOURCE = cpelatency.c -cpelatency_LDADD = $(TOOL_LIBS) - -cpeldump_SOURCE = cpeldump.c -cpeldump_LDADD = $(TOOL_LIBS) - -cpelinreg_SOURCE = cpelinreg.c -cpelinreg_LDADD = $(TOOL_LIBS) - -cpelstate_SOURCE = cpelstate.c -cpelstate_LDADD = $(TOOL_LIBS) - - - - - - diff --git a/perftool/c2cpel.c b/perftool/c2cpel.c deleted file mode 100644 index 38e6fe52e55..00000000000 --- a/perftool/c2cpel.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include "cpel_util.h" - -static elog_main_t elog_main; - -/* - * convert_clib_file - */ -void convert_clib_file(char *clib_file) -{ - clib_error_t *error = 0; - int i; - elog_main_t *em = &elog_main; - double starttime, delta; - - error = elog_read_file (&elog_main, clib_file); - - if (error) { - clib_warning("%U", format_clib_error, error); - exit (1); - } - - em = &elog_main; - - starttime = em->events[0].time; - - for (i = 0; i < vec_len (em->events); i++) { - elog_event_t *e; /* clib event */ - evt_t *ep; /* xxx2cpel event */ - u8 *s; - u64 timestamp; - elog_event_type_t *t; - u8 *brief_event_name; - u8 *track_name; - int j; - - e = vec_elt_at_index(em->events, i); - - /* Seconds since start of log */ - delta = e->time - starttime; - - /* u64 nanoseconds since start of log */ - timestamp = delta * 1e9; - - s = format (0, "%U%c", format_elog_event, em, e, 0); - - /* allocate an event instance */ - vec_add2(the_events, ep, 1); - ep->timestamp = timestamp; - - /* convert string event code to a real number */ - t = vec_elt_at_index (em->event_types, e->type); - - /* - * Construct a reasonable event name. - * Truncate the format string at the first whitespace break - * or printf format character. - */ - brief_event_name = format (0, "%s", t->format); - - for (j = 0; j < vec_len (brief_event_name); j++) { - if (brief_event_name[j] == ' ' || - brief_event_name[j] == '%' || - brief_event_name[j] == '(') { - brief_event_name[j] = 0; - break; - } - } - /* Throw away that much of the formatted event */ - vec_delete (s, j+1, 0); - - ep->event_id = find_or_add_event(brief_event_name, "%s"); - - track_name = format (0, "%U%c", format_elog_track, em, e, 0); - - ep->track_id = find_or_add_track (track_name); - - ep->datum = find_or_add_strtab(s); - - vec_free (track_name); - vec_free(brief_event_name); - vec_free(s); - } -} - -u8 *vec_basename (char *s) -{ - u8 * rv; - char *cp = s; - - while (*cp) - cp++; - - cp--; - - while (cp > s && *cp != '/') - cp--; - - if (cp > s) - cp++; - - rv = format (0, "%s", cp); - return rv; -} - - -int event_compare (const void *a0, const void *a1) -{ - evt_t *e0 = (evt_t *)a0; - evt_t *e1 = (evt_t *)a1; - - if (e0->timestamp < e1->timestamp) - return -1; - else if (e0->timestamp > e1->timestamp) - return 1; - return 0; -} - -int main (int argc, char **argv) -{ - int curarg=1; - char **inputfiles = 0; - char *outputfile = 0; - FILE *ofp; - - if (argc < 3) - goto usage; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - vec_add1 (inputfiles, argv[curarg]); - curarg++; - continue; - } - clib_warning("Missing filename after --input-file\n"); - exit (1); - } - - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - clib_warning("Missing filename after --output-file\n"); - exit(1); - } - vec_add1 (inputfiles, argv[curarg]); - curarg++; - continue; - - usage: - fformat(stderr, - "c2cpel [--input-file] --output-file \n"); - exit(1); - } - - if (vec_len(inputfiles) == 0 || outputfile == 0) - goto usage; - - if (vec_len(inputfiles) > 1) - goto usage; - - cpel_util_init(); - - convert_clib_file (inputfiles[0]); - - ofp = fopen (outputfile, "w"); - if (ofp == NULL) { - clib_unix_warning ("couldn't create %s", outputfile); - exit (1); - } - - alpha_sort_tracks(); - fixup_event_tracks(); - - /* - * Four sections: string-table, event definitions, track defs, events. - */ - if (!write_cpel_header(ofp, 4)) { - clib_warning ("Error writing cpel header to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_string_table(ofp)) { - clib_warning ("Error writing string table to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_event_defs(ofp)) { - clib_warning ("Error writing event defs to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_track_defs(ofp)) { - clib_warning ("Error writing track defs to %s...\n", outputfile); - unlink(outputfile); - exit(1); - } - - if (!write_events(ofp, (u64) 1e9)) { - clib_warning ("Error writing events to %s...\n", outputfile); - unlink(outputfile); - exit(1); - - } - fclose(ofp); - exit (0); -} diff --git a/perftool/configure.ac b/perftool/configure.ac deleted file mode 100644 index f4a986972c2..00000000000 --- a/perftool/configure.ac +++ /dev/null @@ -1,12 +0,0 @@ -AC_INIT(perftool, 2.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, - AC_MSG_ERROR([Please install the vpp-lib package])) -AC_CHECK_HEADER([vppinfra/clib.h],, - AC_MSG_ERROR([Please install the vpp-dev package])) - -AM_PROG_LIBTOOL - -AC_OUTPUT([Makefile]) diff --git a/perftool/cpel.h b/perftool/cpel.h deleted file mode 100644 index 0bfb1a68ef2..00000000000 --- a/perftool/cpel.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2005-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _CPEL_H_ -#define _CPEL_H_ 1 - -typedef struct cpel_file_header_ { - unsigned char endian_version; - unsigned char pad; - unsigned short nsections; - unsigned int file_date; -} cpel_file_header_t; - -#define CPEL_FILE_LITTLE_ENDIAN 0x80 -#define CPEL_FILE_VERSION 0x01 -#define CPEL_FILE_VERSION_MASK 0x7F - -typedef struct cpel_section_header_ { - unsigned int section_type; - unsigned int data_length; /* does NOT include type and itself */ -} cpel_section_header_t; - -#define CPEL_SECTION_STRTAB 1 -/* string at offset 0 is the name of the table */ - -#define CPEL_SECTION_SYMTAB 2 -#define CPEL_SECTION_EVTDEF 3 - -typedef struct event_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_event_definitions; -} event_definition_section_header_t; - -typedef struct event_definition_ { - unsigned int event; - unsigned int event_format; - unsigned int datum_format; -} event_definition_t; - -#define CPEL_SECTION_TRACKDEF 4 - -typedef struct track_definition_section_header_ { - char string_table_name[64]; - unsigned int number_of_track_definitions; -} track_definition_section_header_t; - -typedef struct track_definition_ { - unsigned int track; - unsigned int track_format; -} track_definition_t; - -#define CPEL_SECTION_EVENT 5 - -typedef struct event_section_header_ { - char string_table_name[64]; - unsigned int number_of_events; - unsigned int clock_ticks_per_second; -} event_section_header_t; - -typedef struct event_entry_ { - unsigned int time[2]; - unsigned int track; - unsigned int event_code; - unsigned int event_datum; -} event_entry_t; - -#define CPEL_NUM_SECTION_TYPES 5 - -#endif /* _CPEL_H_ */ - diff --git a/perftool/cpel_util.c b/perftool/cpel_util.c deleted file mode 100644 index 7ee9b6e2a00..00000000000 --- a/perftool/cpel_util.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include "cpel_util.h" - -evt_t *the_events; - -track_t *the_tracks; -u32 *track_alpha_map; - -event_definition_t *the_event_definitions; -i64 min_timestamp; - -/* Hash tables, used to find previous instances of the same items */ -uword *the_track_hash; -uword *the_msg_event_hash; -uword *the_strtab_hash; -uword *the_pidtid_hash; -uword *the_pid_to_name_hash; -u8 *the_strtab; - -uword *the_event_id_bitmap; - -/* - * find_or_add_strtab - * Finds or adds a string to the string table - */ -u32 find_or_add_strtab(void *s_arg) -{ - uword *p; - int len; - u8 *this_string; - u8 *scopy=0; - char *s = s_arg; - - p = hash_get_mem(the_strtab_hash, s); - if (p) { - return (p[0]); - } - - /* - * Here's a CLIB bear-trap. We can't add the string-table - * strings to the to the hash table (directly), since it - * expands and moves periodically. All of the hash table - * entries turn into dangling references, yadda yadda. - */ - - len = strlen(s)+1; - vec_add2(the_strtab, this_string, len); - memcpy(this_string, s, len); - - /* Make a copy which won't be moving around... */ - vec_validate(scopy, len); - memcpy(scopy, s, len); - - hash_set_mem(the_strtab_hash, scopy, this_string - the_strtab); - - return(this_string - the_strtab); -} - -/* - * find_or_add_track - * returns index in track table - */ -u32 find_or_add_track(void *s_arg) -{ - uword *p; - track_t *this_track; - u8 *copy_s; - char *s=s_arg; - - p = hash_get_mem(the_track_hash, s); - if (p) { - return (p[0]); - } - vec_add2(the_tracks, this_track, 1); - - this_track->original_index = this_track - the_tracks; - this_track->strtab_offset = find_or_add_strtab(s); - - copy_s = (u8 *)vec_dup(s); - - hash_set_mem(the_track_hash, copy_s, this_track - the_tracks); - return(this_track - the_tracks); -} - -/* - * find_or_add_event - * Adds an event to the event definition vector and add it to - * the event hash table - */ - -u32 find_or_add_event(void *s_arg, char *datum_format) -{ - uword *p; - u8 *copy_s; - event_definition_t *this_event_definition; - u32 event_id; - char *s=s_arg; - - p = hash_get_mem(the_msg_event_hash, s); - if (p) { - return (p[0]); - } - vec_add2(the_event_definitions, this_event_definition, 1); - - /* Allocate a new event-id */ - event_id = clib_bitmap_first_clear (the_event_id_bitmap); - the_event_id_bitmap = clib_bitmap_set(the_event_id_bitmap, event_id, 1); - this_event_definition->event = event_id; - this_event_definition->event_format = find_or_add_strtab(s); - this_event_definition->datum_format = find_or_add_strtab(datum_format); - - copy_s = (u8 *)vec_dup(s); - - hash_set_mem(the_msg_event_hash, copy_s, event_id); - - return(event_id); -} - -/* - * write_string_table - */ -int write_string_table(FILE *ofp) -{ - cpel_section_header_t sh; - - /* Round up string table size */ - while (vec_len(the_strtab) & 0x7) - vec_add1(the_strtab, 0); - - sh.section_type = ntohl(CPEL_SECTION_STRTAB); - sh.data_length = ntohl(vec_len(the_strtab)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - if (fwrite(the_strtab, 1, vec_len(the_strtab), ofp) != - vec_len(the_strtab)) - return(0); - - return(1); -} - -/* - * write_cpel_header - */ -int write_cpel_header(FILE *ofp, u32 nsections) -{ - cpel_file_header_t h; - - h.endian_version = CPEL_FILE_VERSION; - h.pad = 0; - h.nsections = ntohs(nsections); - h.file_date = ntohl(time(0)); - if (fwrite(&h, sizeof(h), 1, ofp) != 1) - return (0); - - return(1); -} - -/* - * write_event_defs - */ -int write_event_defs(FILE *ofp) -{ - cpel_section_header_t sh; - event_definition_section_header_t edsh; - event_definition_t *this_event_definition; - int i; - - /* Next, the event definitions */ - sh.section_type = ntohl(CPEL_SECTION_EVTDEF); - sh.data_length = ntohl(vec_len(the_event_definitions) - *sizeof(the_event_definitions[0]) - + sizeof(event_definition_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&edsh, 0, sizeof(edsh)); - - strcpy(edsh.string_table_name, "FileStrtab"); - edsh.number_of_event_definitions = ntohl(vec_len(the_event_definitions)); - - if (fwrite(&edsh, sizeof(edsh), 1, ofp) != 1) - return(0); - - for (i = 0; i < vec_len(the_event_definitions); i++) { - this_event_definition = &the_event_definitions[i]; - /* Endian fixup */ - this_event_definition->event = ntohl(this_event_definition->event); - this_event_definition->event_format = - ntohl(this_event_definition->event_format); - this_event_definition->datum_format = - ntohl(this_event_definition->datum_format); - - if (fwrite(this_event_definition, sizeof(the_event_definitions[0]), - 1, ofp) != 1) - return(0); - } - return(1); -} - -/* - * ntohll - */ -u64 ntohll (u64 x) { - if (clib_arch_is_little_endian) - x = ((((x >> 0) & 0xff) << 56) - | (((x >> 8) & 0xff) << 48) - | (((x >> 16) & 0xff) << 40) - | (((x >> 24) & 0xff) << 32) - | (((x >> 32) & 0xff) << 24) - | (((x >> 40) & 0xff) << 16) - | (((x >> 48) & 0xff) << 8) - | (((x >> 56) & 0xff) << 0)); - - return x; -} - -/* - * write_events - */ -int write_events(FILE *ofp, u64 clock_ticks_per_second) -{ - cpel_section_header_t sh; - event_section_header_t eh; - u32 number_of_events; - int i; - event_entry_t e; - u64 net_timestamp; - evt_t *this_event; - u32 time0, time1; - - number_of_events = vec_len(the_events); - - sh.section_type = ntohl(CPEL_SECTION_EVENT); - sh.data_length = ntohl(number_of_events * sizeof(e) + - sizeof(event_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&eh, 0, sizeof(eh)); - strcpy(eh.string_table_name, "FileStrtab"); - eh.number_of_events = ntohl(number_of_events); - eh.clock_ticks_per_second = ntohl(clock_ticks_per_second); - - if (fwrite(&eh, sizeof(eh), 1, ofp) != 1) - return(0); - - for (i = 0; i < number_of_events; i++) { - this_event = &the_events[i]; - net_timestamp = ntohll(this_event->timestamp); - - time1 = net_timestamp>>32; - time0 = net_timestamp & 0xFFFFFFFF; - - e.time[0] = time0; - e.time[1] = time1; - e.track = ntohl(this_event->track_id); - e.event_code = ntohl(this_event->event_id); - e.event_datum = ntohl(this_event->datum); - - if (fwrite(&e, sizeof(e), 1, ofp) != 1) - return(0); - } - return(1); -} - -/* - * write_track_defs - */ -int write_track_defs(FILE *ofp) -{ - cpel_section_header_t sh; - track_definition_section_header_t tdsh; - track_definition_t record; - track_definition_t *this_track_definition = &record; - int i; - event_definition_section_header_t edsh; - - /* Next, the event definitions */ - sh.section_type = ntohl(CPEL_SECTION_TRACKDEF); - sh.data_length = ntohl(vec_len(the_tracks) - *sizeof(this_track_definition[0]) - + sizeof(track_definition_section_header_t)); - - if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) - return(0); - - memset(&tdsh, 0, sizeof(tdsh)); - - strcpy(tdsh.string_table_name, "FileStrtab"); - tdsh.number_of_track_definitions = ntohl(vec_len(the_tracks)); - - if (fwrite(&tdsh, sizeof(edsh), 1, ofp) != 1) - return(0); - - for (i = 0; i < vec_len(the_tracks); i++) { - this_track_definition->track = ntohl(i); - this_track_definition->track_format = - ntohl(the_tracks[i].strtab_offset); - - if (fwrite(this_track_definition, sizeof(this_track_definition[0]), - 1, ofp) != 1) - return(0); - } - return(1); -} - -void cpel_util_init (void) -{ - u8 *eventstr; - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_msg_event_hash = hash_create_string (0, sizeof (uword)); - the_track_hash = hash_create_string (0, sizeof (uword)); - the_pidtid_hash = hash_create_string (0, sizeof(uword)); - the_pid_to_name_hash = hash_create(0, sizeof(uword)); - - /* Must be first, or no supper... */ - find_or_add_strtab("FileStrtab"); - - /* Historical canned events, no longer used. */ - if (0) { - /* event 0 (not used) */ - eventstr = format(0, "PlaceholderNotUsed"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 1 (thread on CPU) */ - eventstr = format(0, "THREAD/THRUNNING"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 2 (thread ready) */ - eventstr = format(0, "THREAD/THREADY"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "%s"); - vec_free(eventstr); - - /* event 3 (function enter) */ - eventstr = format(0, "FUNC/ENTER"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "0x%x"); - vec_free(eventstr); - - /* event 4 (function enter) */ - eventstr = format(0, "FUNC/EXIT"); - vec_add1(eventstr, 0); - find_or_add_event(eventstr, "0x%x"); - vec_free(eventstr); - } -} - -/* - * alpha_compare_tracks - */ -static int alpha_compare_tracks(const void *a1, const void *a2) -{ - int i; - track_t *t1 = (track_t *)a1; - track_t *t2 = (track_t *)a2; - u8 *s1 = &the_strtab[t1->strtab_offset]; - u8 *s2 = &the_strtab[t2->strtab_offset]; - - for (i = 0; s1[i] && s2[i]; i++) { - if (s1[i] < s2[i]) - return(-1); - if (s1[i] > s2[i]) - return(1); - } - return(0); -} - -/* - * alpha_sort_tracks - * Alphabetically sort tracks, set up a mapping - * vector so we can quickly map the original track index to - * the new/improved/alpha-sorted index - */ -void alpha_sort_tracks(void) -{ - track_t *this_track; - int i; - - qsort(the_tracks, vec_len(the_tracks), sizeof(track_t), - alpha_compare_tracks); - - vec_validate(track_alpha_map, vec_len(the_tracks)); - _vec_len(track_alpha_map) = vec_len(the_tracks); - - for (i = 0; i < vec_len(the_tracks); i++) { - this_track = &the_tracks[i]; - track_alpha_map[this_track->original_index] = i; - } -} - -/* - * fixup_event_tracks - * Use the track alpha mapping to account for the alphabetic - * sort performed by the previous routine - */ -void fixup_event_tracks(void) -{ - int i; - u32 old_track; - - for (i = 0; i < vec_len(the_events); i++) { - old_track = the_events[i].track_id; - the_events[i].track_id = track_alpha_map[old_track]; - } -} - -/* Indispensable for debugging in gdb... */ - -u32 vl(void *x) -{ - return vec_len(x); -} diff --git a/perftool/cpel_util.h b/perftool/cpel_util.h deleted file mode 100644 index b76f7a4b322..00000000000 --- a/perftool/cpel_util.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __cpel_util_h__ -#define __cpel_util_h__ - -/* - * Our idea of an event, as opposed to a CPEL event - */ -typedef struct evt_ { - u64 timestamp; - u32 track_id; - u32 event_id; - u32 datum; -} evt_t; - -evt_t *the_events; - -/* - * Track object, so we can sort the tracks alphabetically and - * fix the events later - */ -typedef struct track_ { - u32 original_index; - u32 strtab_offset; -} track_t; - -track_t *the_tracks; -u32 *track_alpha_map; - -event_definition_t *the_event_definitions; -i64 min_timestamp; - -/* Hash tables, used to find previous instances of the same items */ -uword *the_track_hash; -uword *the_msg_event_hash; -uword *the_strtab_hash; -uword *the_pidtid_hash; -uword *the_pid_to_name_hash; -u8 *the_strtab; - -u32 find_or_add_strtab(void *s_arg); -u32 find_or_add_track(void *s_arg); -u32 find_or_add_event(void *s_arg, char *datum_format); -int write_string_table(FILE *ofp); -int write_cpel_header(FILE *ofp, u32 nsections); -int write_event_defs(FILE *ofp); -u64 ntohll (u64 x); -int write_events(FILE *ofp, u64 clock_ticks_per_second); -int write_track_defs(FILE *ofp); -void cpel_util_init (void); -void alpha_sort_tracks(void); -void fixup_event_tracks(void); - -#endif /* __cpel_util_h__ */ diff --git a/perftool/cpelatency.c b/perftool/cpelatency.c deleted file mode 100644 index f40a1fb1c84..00000000000 --- a/perftool/cpelatency.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpelatency 2.0"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ -uword *the_pidtid_hash; /* ("pid:xxx tid:yy", track-definition) hash */ - -f64 ticks_per_us; -u32 start_event_code = 2; /* default: XR thread ready event */ -u32 end_event_code = 1; /* default: XR thread running event */ -int exclude_kernel_from_summary_stats=1; -int summary_stats_only; -int scatterplot; -u8 *name_filter; -int have_trackdefs; - -typedef enum { - SORT_MAX_TIME=1, - SORT_MAX_OCCURRENCES, - SORT_NAME, -} sort_t; - -sort_t sort_type = SORT_MAX_TIME; - -int widest_name_format=5; -int widest_track_format=20; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; - u64 state_start_ticks; - u64 *ticks_in_state; /* vector of state occurrences */ - f64 mean_ticks_in_state; - f64 variance_ticks_in_state; - f64 total_ticks_in_state; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *) bp->datum_str); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *) bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - u8 *pidstr; - u8 *pidtid_str; - u8 *cp; - int tid, pid; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(stderr, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - if (verbose) { - fprintf(stderr, "adding track '%s'\n", btp->track_str); - } - - thislen = strlen((char *) btp->track_str); - if (thislen > widest_track_format) - widest_track_format = thislen; - - /* convert track_str "eth_server t11(20498)" to "pid:20498 tid:11" */ - cp = btp->track_str; - while (*cp && *cp != '(') - cp++; - if (!*cp) { - fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); - goto out; - } - pidstr = cp+1; /* remember location of PID */ - - while (cp > btp->track_str && *cp != 't') - cp--; - - if (cp == btp->track_str) { - fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); - goto out; - } - tid = atol((char *)(cp+1)); - pid = atol((char *) pidstr); - pidtid_str = format(0, "pid:%d tid:%d", pid, tid); - vec_add1(pidtid_str, 0); - - /* - * Note: duplicates are possible due to thread create / - * thread destroy operations. - */ - p = hash_get_mem(the_pidtid_hash, pidtid_str); - if (p) { - vec_free(pidtid_str); - goto out; - } - hash_set_mem(the_pidtid_hash, pidtid_str, btp - bound_tracks); - - out: - tp++; - } - have_trackdefs = 1; - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u32 time0, time1; - u32 track_code; - u8 *this_strtab; - u64 ticks_in_state; - bound_track_t *btp; - bound_track_t *state_track=0; - u8 *pidtid_str; - u8 *pidtid_dup; - u8 *ecp; - u32 event_code; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - /* - * Some logger implementation that doesn't produce - * trackdef sections, synthesize the bound_tracks vector - */ - if (!have_trackdefs) { - for (i = 0; i < nevents; i++) { - track_code = ntohl(ep->track); - pidtid_dup = format(0, "%d", track_code); - vec_add1(pidtid_dup, 0); - p = hash_get_mem(the_pidtid_hash, pidtid_dup); - if (!p) { - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = pidtid_dup; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - hash_set_mem(the_pidtid_hash, pidtid_dup, btp - bound_tracks); - } else { - vec_free(pidtid_dup); - } - ep++; - } - } - - ep = (event_entry_t *)(eh+1); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - event_code = ntohl(ep->event_code); - - /* Find the corresponding track via the pidtid hash table */ - if (event_code == start_event_code || event_code == end_event_code) { - if (have_trackdefs) { - pidtid_str = this_strtab + ntohl(ep->event_datum); - pidtid_dup = format(0, (char *) pidtid_str); - vec_add1(pidtid_dup, 0); - ecp = &pidtid_dup[vec_len(pidtid_dup)-1]; - while (*--ecp == ' ') - *ecp = 0; - } else { - pidtid_dup = format(0, "%d", ntohl(ep->track)); - vec_add1(pidtid_dup, 0); - } - - p = hash_get_mem(the_pidtid_hash, pidtid_dup); - if (!p) { - fprintf(stderr, "warning: couldn't find '%s'\n", - pidtid_dup); - vec_free(pidtid_dup); - ep++; - continue; - } - state_track = &bound_tracks[p[0]]; - } - /* Found the start-event code ? */ - if (event_code == start_event_code) { - state_track->state_start_ticks = now; - } else if (event_code == end_event_code) { - /* - * Add a ticks-in-state record, unless - * e.g. the log started with the exit event - */ - if (state_track->state_start_ticks) { - ticks_in_state = now - state_track->state_start_ticks; - vec_add1(state_track->ticks_in_state, ticks_in_state); - state_track->state_start_ticks = 0; - } - /* Otherwise, nothing */ - } - ep++; - } - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - fprintf(ofp, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - -void compute_state_statistics(int verbose, FILE *ofp) -{ - int i, j; - bound_track_t *bp; - f64 fticks; - - /* Across the bound tracks */ - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - bp->mean_ticks_in_state = 0.0; - bp->variance_ticks_in_state = 0.0; - bp->total_ticks_in_state = 0.0; - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; - } - /* Compute mean */ - if (vec_len(bp->ticks_in_state)) { - bp->mean_ticks_in_state = bp->total_ticks_in_state / - ((f64) vec_len(bp->ticks_in_state)); - } - /* Accumulate sum: (Xi-Xbar)**2 */ - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fticks = bp->ticks_in_state[j]; - bp->variance_ticks_in_state += - (fticks - bp->mean_ticks_in_state)* - (fticks - bp->mean_ticks_in_state); - } - /* Compute s**2, the unbiased estimator of sigma**2 */ - if (vec_len(bp->ticks_in_state) > 1) { - bp->variance_ticks_in_state /= (f64) - (vec_len(bp->ticks_in_state)-1); - } - } -} - -int track_compare_max (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = a1->total_ticks_in_state; - v2 = a2->total_ticks_in_state; - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_occurrences (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = (f64) vec_len(a1->ticks_in_state); - v2 = (f64) vec_len(a2->ticks_in_state); - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_name (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - - return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); -} - -void sort_state_statistics(sort_t type, FILE *ofp) -{ - int (*compare)(const void *, const void *); - - if (summary_stats_only) - return; - - switch(type) { - case SORT_MAX_TIME: - fprintf(ofp, "Results sorted by max time in state.\n\n"); - compare = track_compare_max; - break; - - case SORT_MAX_OCCURRENCES: - fprintf(ofp, "Results sorted by max occurrences of state.\n\n"); - compare = track_compare_occurrences; - break; - - case SORT_NAME: - compare = track_compare_name; - fprintf(ofp, "Results sorted by process name, thread ID, PID\n\n"); - break; - - default: - fatal("sort type not set?"); - } - - qsort (bound_tracks, vec_len(bound_tracks), - sizeof (bound_track_t), compare); -} - -void print_state_statistics(int verbose, FILE *ofp) -{ - int i,j; - u8 *trackpad; - bound_track_t *bp; - f64 total_time = 0.0; - f64 total_switches = 0.0; - - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - if (!summary_stats_only) { - fprintf(ofp, (char *)trackpad, "ProcName Thread(PID)"); - fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); - } - - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - if (bp->mean_ticks_in_state == 0.0) - continue; - - if (name_filter && - strncmp((char *)bp->track_str, (char *)name_filter, - strlen((char *)name_filter))) - continue; - - /* - * Exclude kernel threads (e.g. idle thread) from - * state statistics - */ - if (exclude_kernel_from_summary_stats && - !strncmp((char *) bp->track_str, "kernel ", 7)) - continue; - - total_switches += (f64) vec_len(bp->ticks_in_state); - - if (!summary_stats_only) { - fprintf(ofp, (char *) trackpad, bp->track_str); - fprintf(ofp, "%10.3f +- %10.3f", - bp->mean_ticks_in_state / ticks_per_us, - sqrt(bp->variance_ticks_in_state) - / ticks_per_us); - fprintf(ofp, "%12.3f", - bp->total_ticks_in_state / ticks_per_us); - fprintf(ofp, "%8d\n", vec_len(bp->ticks_in_state)); - } - - if (scatterplot) { - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fprintf(ofp, "%.3f\n", - (f64)bp->ticks_in_state[j] / ticks_per_us); - } - } - - total_time += bp->total_ticks_in_state; - } - - if (!summary_stats_only) - fprintf(ofp, "\n"); - fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", - exclude_kernel_from_summary_stats ? "exclude" : "include"); - if (name_filter) - fprintf(ofp, - "Note: only pid/proc/threads matching '%s' are included.\n", - name_filter); - - fprintf(ofp, - "Total time in state: %10.3f (us), Total state occurrences: %.0f\n", - total_time / ticks_per_us, total_switches); - fprintf(ofp, "Average time in state: %10.3f (us)\n", - (total_time / total_switches) / ticks_per_us); - fprintf(ofp, "State start event: %d, state end event: %d\n", - start_event_code, end_event_code); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose++; - continue; - } - if (!strncmp(argv[curarg], "--scatterplot", 4)) { - curarg++; - scatterplot=1; - continue; - } - - if (!strncmp(argv[curarg], "--start-event", 4)) { - curarg++; - if (curarg < argc) { - start_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --start-event\n"); - } - if (!strncmp(argv[curarg], "--end-event", 4)) { - curarg++; - if (curarg < argc) { - end_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --end-event\n"); - } - if (!strncmp(argv[curarg], "--max-time-sort", 7)) { - sort_type = SORT_MAX_TIME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { - sort_type = SORT_MAX_OCCURRENCES; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--name-sort", 3)) { - sort_type = SORT_NAME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--kernel-included", 3)) { - exclude_kernel_from_summary_stats = 0; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--summary", 3)) { - summary_stats_only=1; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--filter", 3)) { - curarg ++; - if (curarg < argc) { - name_filter = (u8 *) argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filter string after --filter\n"); - } - - - usage: - fprintf(stderr, - "cpelatency --input-file [--output-file ]\n"); - fprintf(stderr, - " [--start-event ] [--verbose]\n"); - fprintf(stderr, - " [--end-event ]\n"); - fprintf(stderr, - " [--max-time-sort(default) | --max-occurrence-sort |\n"); - - fprintf(stderr, - " --name-sort-sort] [--kernel-included]\n"); - - fprintf(stderr, - " [--summary-stats-only] [--scatterplot]\n"); - - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - the_pidtid_hash = hash_create_string (0, sizeof(uword)); - - if (cpel_dump((u8 *)cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - compute_state_statistics(verbose, ofp); - sort_state_statistics(sort_type, ofp); - print_state_statistics(verbose, ofp); - - fclose(ofp); - return(0); -} diff --git a/perftool/cpeldump.c b/perftool/cpeldump.c deleted file mode 100644 index 9011bd039ec..00000000000 --- a/perftool/cpeldump.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpeldump 2.0"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -int widest_name_format=5; -int widest_track_format=5; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(stderr, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(stderr, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *)bp->datum_str); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *)bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(stderr, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - thislen = strlen((char *)btp->track_str); - if (thislen > widest_track_format) - widest_track_format = thislen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(stderr, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - f64 ticks_per_us; - u32 event_code, track_code; - u64 starttime = 0xFFFFFFFFFFFFFFFFULL; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u64 delta; - u32 hours, minutes, seconds, msec, usec; - u32 time0, time1; - double d; - bound_event_t *bp; - bound_event_t generic_event; - bound_track_t *tp=0; - bound_track_t generic_track; - u32 last_track_code; - u8 *s, *evtpad, *trackpad; - u8 *this_strtab; - - generic_event.event_str = (u8 *)"%d"; - generic_event.datum_str = (u8 *)"0x%08x"; - generic_event.is_strtab_ref = 0; - - generic_track.track_str = (u8 *)"%d"; - last_track_code = 0xdeadbeef; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; - - if (verbose) { - fprintf(stderr, "Event section: %d events, %.3f ticks_per_us\n", - nevents, ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - evtpad = format(0, "%%-%ds ", widest_name_format); - vec_add1(evtpad, 0); - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_us; - - now = d; - - if (starttime == 0xFFFFFFFFFFFFFFFFULL) - starttime = now; - - delta = now - starttime; - - /* Delta = time since first event, in usec */ - - hours = delta / USEC_PER_HOUR; - if (hours) - delta -= ((u64) hours * USEC_PER_HOUR); - minutes = delta / USEC_PER_MINUTE; - if (minutes) - delta -= ((u64) minutes * USEC_PER_MINUTE); - seconds = delta / USEC_PER_SECOND; - if (seconds) - delta -= ((u64) seconds * USEC_PER_SECOND); - msec = delta / USEC_PER_MS; - if (msec) - delta -= ((u64) msec * USEC_PER_MS); - - usec = delta; - - /* Output the timestamp */ - fprintf(ofp, time_format, hours, minutes, seconds, msec, usec); - - /* output the track */ - track_code = ntohl(ep->track); - - if (track_code != last_track_code) { - p = hash_get(the_trackdef_hash, track_code); - if (p) { - tp = &bound_tracks[p[0]]; - } else { - tp = &generic_track; - } - } - s = format(0, (char *)tp->track_str, track_code); - vec_add1(s, 0); - fprintf(ofp, (char *)trackpad, s); - vec_free(s); - - /* output the event and datum */ - if (0 && verbose) { - fprintf(stderr, "raw event code %d, raw event datum 0x%x\n", - ntohl(ep->event_code), ntohl(ep->event_datum)); - } - - event_code = ntohl(ep->event_code); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - bp = &bound_events[p[0]]; - } else { - bp = &generic_event; - } - s = format(0, (char *)bp->event_str, ntohl(ep->event_code)); - vec_add1(s, 0); - fprintf(ofp, (char *)evtpad, s); - vec_free(s); - if (bp->is_strtab_ref) { - fprintf(ofp, (char *) bp->datum_str, - &this_strtab[ntohl(ep->event_datum)]); - } else { - fprintf(ofp, (char *) bp->datum_str, ntohl(ep->event_datum)); - } - fputs("\n", ofp); - ep++; - } - vec_free(evtpad); - vec_free(trackpad); - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(stderr, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(stderr, "File created %s", ctime(&file_time)); - fprintf(stderr, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(stderr, - "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose = 1; - continue; - } - - usage: - fprintf(stderr, - "cpeldump --input-file [--output-file ]\n"); - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - -#ifdef TEST_TRACK_INFO - { - bound_track_t *btp; - vec_add2(bound_tracks, btp, 1); - btp->track = 0; - btp->track_str = "cpu %d"; - hash_set(the_trackdef_hash, 0, btp - bound_tracks); - hash_set(the_trackdef_hash, 1, btp - bound_tracks); - } -#endif - - if (cpel_dump((u8 *)cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - fclose(ofp); - return(0); -} diff --git a/perftool/cpelinreg.c b/perftool/cpelinreg.c deleted file mode 100644 index 115afad7fb2..00000000000 --- a/perftool/cpelinreg.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2008-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Search for O(N**2) functions bracketed by before/after - * events. The "before" event's datum is used as a tag, e.g. which function - * did we call that's strongly O(N). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" - -FILE *g_ifp; -char *g_ifile; - -typedef unsigned long long ulonglong; - -void process_traces (void); -void record_instance (ulong tag, ulonglong time); -void report_actors (void); -void scatterplot_data(void); -int entry_event, exit_event; -int nokey; -char *version = "cpelinreg 2.0"; -int model_these[10]; -int model_index; -int summary_stats; -ulonglong first_start_time; -ulonglong last_end_time; -ulonglong total_time; -ulong scatterkey; -int inline_mokus; - -typedef struct bound_track_ { - u32 track_code; - u32 *start_datum; - u8 *dup_event; - int state; - u64 *start_time; - u64 thread_timestamp; - u64 time_thread_on_cpu; -} bound_track_t; - -bound_track_t *bound_tracks; -uword *the_trackdef_hash; - - -#define MAXSTACK 128 - -typedef struct instance_ { - struct instance_ *next; - ulonglong time; -}instance_t; - -typedef struct actor_ { - struct actor_ *next; - ulong key; - struct instance_ *first; - struct instance_ *last; - double a; - double b; - double min; - double max; - double mean; - double r; - ulong ninst; -} actor_t; - -#define NBUCKETS 1811 - -actor_t *hash[NBUCKETS]; - -actor_t *find_or_create_actor (ulong key) -{ - ulong bucket; - actor_t *ap; - u8 *mem; - - bucket = key % NBUCKETS; - - ap = hash[bucket]; - - if (ap == NULL) { - /* Ensure 8-byte alignment to avoid (double) alignment faults */ - mem = malloc(sizeof(*ap) + 4); - if (((uword)(mem)) & 0x7) - mem += 4; - ap = (actor_t *)mem; - - if (ap == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ap->next = 0; - ap->key = key; - ap->first = 0; - ap->last = 0; - ap->a = 0.00; - ap->b = 0.00; - hash [bucket] = ap; - return (ap); - } - - while (ap) { - if (ap->key == key) - return (ap); - ap = ap->next; - } - - mem = malloc(sizeof(*ap)+4); - if (((uword)(mem) & 0x7)) - mem += 4; - ap = (actor_t *)mem; - - if (ap == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ap->key = key; - ap->first = 0; - ap->last = 0; - ap->a = 0.00; - ap->b = 0.00; - - ap->next = hash[bucket]; - hash[bucket] = ap; - - return (ap); -} - -void record_instance (ulong key, ulonglong time) -{ - actor_t *ap; - instance_t *ip; - - if (nokey) - key = 0; - - ap = find_or_create_actor (key); - - ip = (instance_t *)malloc(sizeof(*ip)); - if (ip == NULL) { - fprintf (stderr, "out of memory...\n"); - exit (1); - } - ip->time = time; - ip->next = 0; - - if (ap->first == 0) { - ap->first = ip; - ap->last = ip; - ap->ninst = 1; - } else { - ap->last->next = ip; - ap->last = ip; - ap->ninst++; - } -} - -#define NINSTANCE 200000 - -double x[NINSTANCE]; -double y[NINSTANCE]; - -int actor_compare (const void *arg1, const void *arg2) -{ - double e10k1, e10k2; - actor_t **a1 = (actor_t **)arg1; - actor_t **a2 = (actor_t **)arg2; - double ninst1, ninst2; - - ninst1 = ((double)((*a1)->ninst)); - ninst2 = ((double)((*a2)->ninst)); - - e10k1 = ninst1 * ((*a1)->mean); - e10k2 = ninst2 * ((*a2)->mean); - - if (e10k1 < e10k2) - return (1); - else if (e10k1 == e10k2) - return (0); - else - return (-1); -} - -void report_actors (void) -{ - int i; - actor_t *ap; - instance_t *ip; - int nactors = 0; - int ninstance; - actor_t **actor_vector; - double e10k; - extern void linreg (double *x, double *y, int nitems, double *a, double *b, - double *minp, double *maxp, double *meanp, double *r); - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - nactors++; - ninstance = 0; - - ip = ap->first; - - while (ip) { - if (ninstance < NINSTANCE) { - x[ninstance] = ninstance; - y[ninstance] = ((double)ip->time); - ninstance++; - } - ip = ip->next; - } - if (ninstance > 1) { -#if DEBUG > 0 - int j; - - for (j = 0; j < ninstance; j++) { - printf("x[%d] = %10.2f, y[%d] = %10.2f\n", - j, x[j], j, y[j]); - } -#endif - - linreg (x, y, ninstance, &ap->a, &ap->b, &ap->min, - &ap->max, &ap->mean, &ap->r); - } else { - ap->a = 0.00; - ap->b = 0.00; - } - - ap = ap->next; - } - } - - actor_vector = (actor_t **)malloc (nactors*sizeof(*actor_vector)); - nactors = 0; - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - if ((ap->a != 0.00) || (ap->b != 0.00)) { - actor_vector[nactors++] = ap; - } - ap = ap->next; - } - } - - qsort (actor_vector, nactors, sizeof (actor_t *), actor_compare); - - if (summary_stats) - printf("NInst Offset Slope T(Ninst) Min Max Avg %%InstTime R Key"); - else - printf("NInst Offset Slope T(Ninst) Key"); - - for (i = 0; i < model_index; i++) { - printf ("T @ %-8d ", model_these[i]); - } - - printf ("\n"); - - for (i = 0; i < nactors; i++) { - int j; - double ninst; - double pcttot; - ap = actor_vector[i]; - ninst = ap->ninst; - - e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); - - if (ap->ninst) { - if (summary_stats) { - pcttot = (e10k / ((double)total_time)) * 100.0; - printf ("%6ld %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f 0x%08lx ", - ap->ninst, ap->a, ap->b, e10k, ap->min, - ap->max, ap->mean, pcttot, ap->r, ap->key); - } - else - printf ("%6ld %11.2f %11.2f %11.2f 0x%08lx ", - ap->ninst, ap->a, ap->b, e10k, ap->key); - - for (j = 0; j < model_index; j++) { - ninst = model_these[j]; - e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); - printf ("%10.2f ", e10k); - } - printf ("\n"); - } - } -} - -void scatterplot_data(void) -{ - actor_t *ap; - int i; - instance_t *ip; - double time; - int count=0; - - for (i = 0; i < NBUCKETS; i++) { - ap = hash[i]; - if (ap == NULL) - continue; - while (ap) { - if (ap->key == scatterkey){ - ip = ap->first; - while (ip) { - time = ((double)ip->time); - printf ("%d\t%.0f\n", count++, time); - ip = ip->next; - } - return; - } - ap = ap->next; - } - } -} - - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - fprintf(stderr, "\n"); - exit(1); -} - -typedef enum { - PASS1=1, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int trackdef_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u32 track_code; - uword *p; - bound_track_t *btp; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(stderr, "Track Definition Section: %d definitions\n", - nevents); - } - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track_code = track_code; - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - tp++; - } - return (0); -} - - -int event_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - event_entry_t *ep; - f64 ticks_per_us; - long output_count; - long dup_events = 0; - ulonglong end_time = 0; - double t; - int sp, ancestor; - int nevents, i; - u64 now; - u64 time0, time1; - double d; - u32 last_track_code = 0xdeafb00b; - u32 track_code; - u32 event_code, event_datum; - bound_track_t *tp = 0; - uword *p; - - output_count = 0; - total_time = 0; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - d = now; - d /= ticks_per_us; - first_start_time = d; - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Convert from bus ticks to usec */ - d = now; - d /= ticks_per_us; - - now = d; - - track_code = ntohl(ep->track); - event_code = ntohl(ep->event_code); - event_datum = ntohl(ep->event_datum); - - if (track_code != last_track_code) { - if (tp) { - tp->thread_timestamp += now - tp->time_thread_on_cpu; - tp->time_thread_on_cpu = 0; - } - p = hash_get(the_trackdef_hash, track_code); - if (!p) { - /* synthesize a new track */ - vec_add2(bound_tracks, tp, 1); - tp->track_code = track_code; - hash_set(the_trackdef_hash, track_code, tp - bound_tracks); - } else { - tp = bound_tracks + p[0]; - } - last_track_code = track_code; - tp->time_thread_on_cpu = now; - } - - if (event_code != entry_event && - event_code != exit_event) { - ep++; - continue; - } - - again: - switch (tp->state) { - case 0: /* not in state */ - /* Another exit event? Stack pop */ - if (event_code == exit_event) { - /* Only if we have something on the stack */ - if (vec_len(tp->start_datum) > 0) { - tp->state = 1; - goto again; - } else { - fprintf (stderr, - "End event before start event, key 0x%x.", - ntohl(ep->event_datum)); - fprintf (stderr, " Interpret results carefully...\n"); - } - } - - tp->state = 1; - if (vec_len(tp->start_datum) >= MAXSTACK) { - int j; - - fprintf (stderr, "stack overflow..\n"); - for (j = vec_len(tp->start_datum)-1; j >= 0; j--) { - fprintf(stderr, "stack[%d]: datum 0x%x\n", - j, tp->start_datum[j]); - } - fprintf (stderr, - "Stack overflow... This occurs when " - "(start, datum)...(end, datum) events\n" - "are not properly paired.\n\n" - "A typical scenario looks like this:\n\n" - " ...\n" - " ELOG(..., START_EVENT, datum);\n" - " if (condition)\n" - " return; /*oops, forgot the end event*/\n" - " ELOG(..., END_EVENT, datum);\n" - " ...\n\n" - "The datum stack dump (above) should make it clear\n" - "where to start looking for a sneak path...\n"); - - exit (1); - } - vec_add1(tp->start_datum, event_datum); - vec_add1(tp->start_time, (tp->thread_timestamp + (now - tp->time_thread_on_cpu))); -#ifdef HAVING_TROUBLE - printf ("sp %lld key 0x%x start time %llu\n", - (long long) vec_len(tp->start_time)-1, event_datum, - (unsigned long long) - tp->start_time [vec_len(tp->start_time)-1]); - printf ("timestamp %llu, now %llu, thread on cpu %llu\n", - (unsigned long long) tp->thread_timestamp, - (unsigned long long) now, - (unsigned long long) tp->time_thread_on_cpu); -#endif - - - - /* - * Multiple identical enter events? If the user knows that - * gcc is producing bogus events due to inline functions, - * trash the duplicate. - */ - if (inline_mokus - && vec_len (tp->start_datum) > 1 - && tp->start_datum [vec_len(tp->start_datum)-1] == - tp->start_datum [vec_len(tp->start_datum)-2]) { - vec_add1 (tp->dup_event, 1); - } else { - vec_add1 (tp->dup_event, 0); - } - - - ep++; - continue; - - case 1: /* in state */ - /* Another entry event? Stack push*/ - if (event_code == entry_event) { - tp->state = 0; - goto again; - } - - if (vec_len(tp->start_datum) == 0) { - fprintf (stderr, "Stack underflow...\n"); - exit (1); - } - - sp = vec_len(tp->start_time)-1; - - end_time = tp->thread_timestamp + (now - tp->time_thread_on_cpu); - - if (!tp->dup_event[sp]) { -#ifdef HAVING_TROUBLE - printf ("sp %d key 0x%x charged %llu\n", sp, - tp->start_datum[sp], end_time - tp->start_time[sp]); - printf (" start %llu, end %llu\n", (unsigned long long) tp->start_time[sp], - (unsigned long long) end_time); -#endif - - record_instance (tp->start_datum[sp], (end_time - - tp->start_time[sp])); - - /* Factor out our time from surrounding services, if any */ - for (ancestor = sp-1; ancestor >= 0; ancestor--) { -#ifdef HAVING_TROUBLE - printf ("Factor out %lld from key 0x%08x\n", - (end_time - tp->start_time[sp]), tp->start_datum[ancestor]); -#endif - tp->start_time[ancestor] += (end_time - tp->start_time[sp]); - } - output_count++; - total_time += (end_time - tp->start_time[sp]); - tp->state = 0; - } else { - dup_events++; - } - _vec_len(tp->start_datum) = sp; - _vec_len(tp->start_time) = sp; - _vec_len(tp->dup_event) = sp; - } - - ep++; - } - last_end_time = now; - - if (scatterkey) { - scatterplot_data(); - exit (0); - } - - if (output_count) { - t = (double)total_time; - printf ("%ld instances of state, %.2f microseconds average\n", - output_count, t / output_count); - - printf ("Total instrumented runtime: %.2f microseconds\n", - ((double)total_time)); - printf ("Total runtime: %lld microseconds\n", - last_end_time - first_start_time); - - t /= (double)(last_end_time - first_start_time); - t *= 100.0; - - if (dup_events) { - printf ("Suppressed %ld duplicate state entry events\n", - dup_events); - } - printf ("Instrumented code accounts for %.2f%% of total time.\n\n", - t); - report_actors(); - } else { - printf ("No instances of state...\n"); - } - - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {unsupported_pass}, /* type 0 -- f**ked */ - {noop_pass}, /* type 1 -- STRTAB */ - {noop_pass}, /* type 2 -- SYMTAB */ - {noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass}, /* type 4 -- TRACKDEF */ - {event_pass}, /* type 5 -- EVENTS */ -}; - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -int process_file (u8 *cpel, int verbose) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - FILE *ofp = stderr; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - nsections = ntohs(fh->nsections); - - /* - * Take a passe through the file. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", - ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - return(0); -} - -/**************************************************************************** -* main - -****************************************************************************/ - -int main (int argc, char **argv) -{ - int curarg = 1; - u8 *cpel = 0; - int verbose = 0; - - if (argc < 6) - { - fprintf (stderr, "usage: cpelinreg -i \n"); - fprintf (stderr, " -s start-event --e end-event [-nokey]\n"); - fprintf (stderr, " [-m ][-xtra-stats]\n"); - fprintf (stderr, " [-keyscatterplot ]\n\n"); - fprintf (stderr, "%s\n", version); - exit (1); - } - - while (curarg < argc) { - if (!strncmp (argv[curarg], "-ifile", 2)) { - curarg++; - g_ifile = argv[curarg++]; - continue; - } - if (!strncmp (argv[curarg], "-start", 2)) { - curarg++; - entry_event = atol (argv [curarg++]); - continue; - } - if (!strncmp (argv[curarg], "-end", 2)) { - curarg++; - exit_event = atol (argv [curarg++]); - continue; - } - - if (!strncmp(argv[curarg], "-badinlines", 2)) { - curarg++; - inline_mokus = 1; - continue; - } - - if (!strncmp (argv[curarg], "-x", 2)) { - curarg++; - summary_stats=1; - continue; - } - if (!strncmp (argv[curarg], "-nokey", 2)) { - curarg++; - nokey = 1; - continue; - } - if (!strncmp (argv[curarg], "-keyscatterplot", 2)) { - curarg++; - sscanf (argv[curarg], "%lx", &scatterkey); - curarg++; - continue; - } - - if (!strncmp (argv[curarg], "-model", 2)) { - if (model_index >= sizeof(model_these) / sizeof(int)) { - fprintf (stderr, "Too many model requests\n"); - exit (1); - } - curarg++; - model_these[model_index++] = atol (argv [curarg++]); - continue; - } - if (!strncmp (argv[curarg], "-verbose", 2)) { - verbose++; - curarg++; - continue; - } - - fprintf (stderr, "unknown switch '%s'\n", argv[curarg]); - exit (1); - } - - cpel = (u8 *)mapfile(g_ifile); - - if (cpel == NULL) - { - fprintf (stderr, "Couldn't open %s\n", g_ifile); - exit (1); - } - - printf ("Extracting state info from %s\nentry_event %d, exit_event %d\n", - g_ifile, entry_event, exit_event); - if (nokey) { - printf ("All state instances mapped to a single actor chain\n"); - } - - the_trackdef_hash = hash_create (0, sizeof (uword)); - - process_file(cpel, verbose); - exit (0); -} diff --git a/perftool/cpelstate.c b/perftool/cpelstate.c deleted file mode 100644 index 3fd9ccb9c79..00000000000 --- a/perftool/cpelstate.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpel.h" -#include - -char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; -static char version[] = "cpelstate 2.0h"; - -#define USEC_PER_MS 1000LL -#define USEC_PER_SECOND (1000*USEC_PER_MS) -#define USEC_PER_MINUTE (60*USEC_PER_SECOND) -#define USEC_PER_HOUR (60*USEC_PER_MINUTE) - -uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ -uword *the_evtdef_hash; /* (event-id, event-definition) hash */ -uword *the_trackdef_hash; /* (track-id, track-definition) hash */ - -f64 ticks_per_us; -u32 state_event_code = 1; /* default: XR thread-on-cpu */ -int exclude_kernel_from_summary_stats=1; -int summary_stats_only; -int scatterplot; -u8 *name_filter; - -typedef enum { - SORT_MAX_TIME=1, - SORT_MAX_OCCURRENCES, - SORT_NAME, -} sort_t; - -sort_t sort_type = SORT_MAX_TIME; - -int widest_name_format=5; -int widest_track_format=5; - -typedef struct bound_event_ { - u32 event_code; - u8 *event_str; - u8 *datum_str; - u32 is_strtab_ref; -} bound_event_t; - -bound_event_t *bound_events; - -typedef struct bound_track_ { - u32 track; - u8 *track_str; - u64 *ticks_in_state; /* vector of state occurrences */ - f64 mean_ticks_in_state; - f64 variance_ticks_in_state; - f64 total_ticks_in_state; -} bound_track_t; - -bound_track_t *bound_tracks; - -void fatal(char *s) -{ - fprintf(stderr, "%s", s); - exit(1); -} - -typedef enum { - PASS1=1, - PASS2=2, -} pass_t; - -typedef struct { - int (*pass1)(cpel_section_header_t *, int, FILE *); - int (*pass2)(cpel_section_header_t *, int, FILE *); -} section_processor_t; - -int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - fprintf(ofp, "Bad (type 0) section, skipped...\n"); - return(0); -} - -int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - return(0); -} - -int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - uword *p; - u8 *strtab_data_area = (u8 *)(sh+1); - - /* Multiple string tables with the same name are Bad... */ - p = hash_get_mem(the_strtab_hash, strtab_data_area); - if (p) { - fprintf(ofp, "Duplicate string table name %s", strtab_data_area); - } - /* - * Looks funny, but we really do want key = first string in the - * table, value = address(first string in the table) - */ - hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); - if (verbose) { - fprintf(ofp, "String Table %s\n", strtab_data_area); - } - return(0); -} - -int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - event_definition_section_header_t *edh; - event_definition_t *ep; - u8 *this_strtab; - u32 event_code; - uword *p; - bound_event_t *bp; - int thislen; - - edh = (event_definition_section_header_t *)(sh+1); - nevents = ntohl(edh->number_of_event_definitions); - - if (verbose) { - fprintf(ofp, "Event Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, edh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - ep = (event_definition_t *)(edh+1); - - for (i = 0; i < nevents; i++) { - event_code = ntohl(ep->event); - p = hash_get(the_evtdef_hash, event_code); - if (p) { - fprintf(ofp, "Event %d redefined, retain first definition\n", - event_code); - continue; - } - vec_add2(bound_events, bp, 1); - bp->event_code = event_code; - bp->event_str = this_strtab + ntohl(ep->event_format); - bp->datum_str = this_strtab + ntohl(ep->datum_format); - bp->is_strtab_ref = 0; - /* Decide if the datum format is a %s format => strtab reference */ - { - int j; - int seen_percent=0; - - for (j = 0; j < strlen((char *)(bp->datum_str)); j++) { - if (bp->datum_str[j] == '%'){ - seen_percent=1; - continue; - } - if (seen_percent && bp->datum_str[j] == 's') { - bp->is_strtab_ref = 1; - } - } - } - - hash_set(the_evtdef_hash, event_code, bp - bound_events); - - thislen = strlen((char *)bp->event_str); - if (thislen > widest_name_format) - widest_name_format = thislen; - - ep++; - } - return (0); -} - -int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - int i, nevents; - track_definition_section_header_t *tdh; - track_definition_t *tp; - u8 *this_strtab; - u32 track_code; - uword *p; - bound_track_t *btp; - int thislen; - - tdh = (track_definition_section_header_t *)(sh+1); - nevents = ntohl(tdh->number_of_track_definitions); - - if (verbose) { - fprintf(ofp, "Track Definition Section: %d definitions\n", - nevents); - } - - p = hash_get_mem(the_strtab_hash, tdh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - this_strtab = (u8 *)p[0]; - - tp = (track_definition_t *)(tdh+1); - - for (i = 0; i < nevents; i++) { - track_code = ntohl(tp->track); - p = hash_get(the_trackdef_hash, track_code); - if (p) { - fprintf(ofp, "track %d redefined, retain first definition\n", - track_code); - continue; - } - vec_add2(bound_tracks, btp, 1); - btp->track = track_code; - btp->track_str = this_strtab + ntohl(tp->track_format); - hash_set(the_trackdef_hash, track_code, btp - bound_tracks); - - thislen = strlen((char *)(btp->track_str)); - if (thislen > widest_track_format) - widest_track_format = thislen; - tp++; - } - return (0); -} - -int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - if (verbose) { - fprintf(ofp, "Unsupported type %d section\n", - ntohl(sh->section_type)); - } - return(0); -} - -int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) -{ - event_section_header_t *eh; - u32 track_code; - int nevents; - int i; - uword *p; - event_entry_t *ep; - u64 now; - u32 time0, time1; - bound_track_t generic_track; - u32 last_track_code; - u64 state_start_ticks=0; - u64 ticks_in_state; - bound_track_t *state_track=0; - int in_state=0; - generic_track.track_str = (u8 *) "%d"; - last_track_code = 0xdeafbeef; - - eh = (event_section_header_t *)(sh+1); - nevents = ntohl(eh->number_of_events); - ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; - - if (verbose) { - fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); - } - - ep = (event_entry_t *)(eh+1); - - p = hash_get_mem(the_strtab_hash, eh->string_table_name); - if (!p) { - fprintf(ofp, "Fatal: couldn't find string table\n"); - return(1); - } - - for (i = 0; i < nevents; i++) { - time0 = ntohl (ep->time[0]); - time1 = ntohl (ep->time[1]); - - now = (((u64) time0)<<32) | time1; - - /* Found the state-change event ? */ - if (ntohl(ep->event_code) == state_event_code) { - /* - * Add a ticks-in-state record, unless - * this is the "prime mover" event instance - */ - if (in_state) { - ticks_in_state = now - state_start_ticks; - vec_add1(state_track->ticks_in_state, ticks_in_state); - } - /* switch to now-current track */ - state_start_ticks = now; - track_code = ntohl(ep->track); - if (track_code != last_track_code) { - p = hash_get(the_trackdef_hash, track_code); - if (p) { - state_track = &bound_tracks[p[0]]; - } else { - state_track = &generic_track; - } - last_track_code = track_code; - } - in_state = 1; - } - ep++; - } - return(0); -} - -/* - * Note: If necessary, add passes / columns to this table to - * handle section order dependencies. - */ - -section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = -{ - {bad_section, noop_pass}, /* type 0 -- f**ked */ - {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ - {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ - {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ - {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ - {noop_pass, event_pass2}, /* type 5 -- EVENTS */ -}; - - -int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, - pass_t pass) -{ - u32 type; - type = ntohl(sh->section_type); - int rv; - int (*fp)(cpel_section_header_t *, int, FILE *); - - if (type > CPEL_NUM_SECTION_TYPES) { - fprintf(stderr, "Unknown section type %d\n", type); - return(1); - } - switch(pass) { - case PASS1: - fp = processors[type].pass1; - break; - - case PASS2: - fp = processors[type].pass2; - break; - - default: - fprintf(stderr, "Unknown pass %d\n", pass); - return(1); - } - - rv = (*fp)(sh, verbose, ofp); - - return(rv); -} - -int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) -{ - time_t file_time; - - if (verbose) { - fprintf(ofp, "CPEL file: %s-endian, version %d\n", - ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? - "little" : "big"), - fh->endian_version & CPEL_FILE_VERSION_MASK); - - file_time = ntohl(fh->file_date); - - fprintf(ofp, "File created %s", ctime(&file_time)); - fprintf(ofp, "File has %d sections\n", - ntohs(fh->nsections)); - } - - return(0); -} - - -int cpel_dump(u8 *cpel, int verbose, FILE *ofp) -{ - cpel_file_header_t *fh; - cpel_section_header_t *sh; - u16 nsections; - u32 section_size; - int i; - - /* First, the file header */ - fh = (cpel_file_header_t *)cpel; - if (fh->endian_version != CPEL_FILE_VERSION) { - if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { - fprintf(stderr, "Little endian data format not supported\n"); - return(1); - } - fprintf(stderr, "Unsupported file version 0x%x\n", - fh->endian_version); - return(1); - } - cpel_dump_file_header(fh, verbose, ofp); - nsections = ntohs(fh->nsections); - - /* - * Take two passes through the file. PASS1 builds - * data structures, PASS2 actually dumps the file. - * Just in case the sections are in an unobvious order. - */ - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - section_size = ntohl(sh->data_length); - - if(verbose) { - fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), - section_size); - } - - if(process_section(sh, verbose, ofp, PASS1)) - return(1); - - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - - sh = (cpel_section_header_t *)(fh+1); - for (i = 0; i < nsections; i++) { - if(process_section(sh, verbose, ofp, PASS2)) - return(1); - section_size = ntohl(sh->data_length); - sh++; - sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); - } - return(0); -} - -void compute_state_statistics(int verbose, FILE *ofp) -{ - int i, j; - bound_track_t *bp; - f64 fticks; - - /* Across the bound tracks */ - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - bp->mean_ticks_in_state = 0.0; - bp->variance_ticks_in_state = 0.0; - bp->total_ticks_in_state = 0.0; - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; - } - /* Compute mean */ - if (vec_len(bp->ticks_in_state)) { - bp->mean_ticks_in_state = bp->total_ticks_in_state / - ((f64) vec_len(bp->ticks_in_state)); - } - /* Accumulate sum: (Xi-Xbar)**2 */ - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fticks = bp->ticks_in_state[j]; - bp->variance_ticks_in_state += - (fticks - bp->mean_ticks_in_state)* - (fticks - bp->mean_ticks_in_state); - } - /* Compute s**2, the unbiased estimator of sigma**2 */ - if (vec_len(bp->ticks_in_state) > 1) { - bp->variance_ticks_in_state /= (f64) - (vec_len(bp->ticks_in_state)-1); - } - } -} - -int track_compare_max (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = a1->total_ticks_in_state; - v2 = a2->total_ticks_in_state; - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_occurrences (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - f64 v1, v2; - - v1 = (f64) vec_len(a1->ticks_in_state); - v2 = (f64) vec_len(a2->ticks_in_state); - - if (v1 < v2) - return (1); - else if (v1 == v2) - return (0); - else return (-1); -} - -int track_compare_name (const void *arg1, const void *arg2) -{ - bound_track_t *a1 = (bound_track_t *)arg1; - bound_track_t *a2 = (bound_track_t *)arg2; - - return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); -} - -void sort_state_statistics(sort_t type, FILE *ofp) -{ - int (*compare)(const void *, const void *)=0; - - if (summary_stats_only) - return; - - switch(type) { - case SORT_MAX_TIME: - fprintf(ofp, "Results sorted by max time in state.\n"); - compare = track_compare_max; - break; - - case SORT_MAX_OCCURRENCES: - fprintf(ofp, "Results sorted by max occurrences of state.\n"); - compare = track_compare_occurrences; - break; - - case SORT_NAME: - compare = track_compare_name; - fprintf(ofp, "Results sorted by process-id/name/thread ID\n"); - break; - - default: - fatal("sort type not set?"); - } - - qsort (bound_tracks, vec_len(bound_tracks), - sizeof (bound_track_t), compare); -} - -void print_state_statistics(int verbose, FILE *ofp) -{ - int i,j; - u8 *trackpad; - bound_track_t *bp; - f64 total_time = 0.0; - f64 total_switches = 0.0; - - trackpad = format(0, "%%-%ds ", widest_track_format); - vec_add1(trackpad, 0); - - if (!summary_stats_only) { - fprintf(ofp, (char *)trackpad, "ProcThread"); - fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); - } - - for (i = 0; i < vec_len(bound_tracks); i++) { - bp = &bound_tracks[i]; - if (bp->mean_ticks_in_state == 0.0) - continue; - - if (name_filter && - strncmp((char *)(bp->track_str), (char *)name_filter, - strlen((char *)name_filter))) - continue; - - /* - * Exclude kernel threads (e.g. idle thread) from - * state statistics - */ - if (exclude_kernel_from_summary_stats && - !strncmp((char *)(bp->track_str), "kernel ", 7)) - continue; - - total_switches += (f64) vec_len(bp->ticks_in_state); - - if (!summary_stats_only) { - fprintf(ofp, (char *) trackpad, bp->track_str); - fprintf(ofp, "%10.3f +- %10.3f", - bp->mean_ticks_in_state / ticks_per_us, - sqrt(bp->variance_ticks_in_state) - / (f64) ticks_per_us); - fprintf(ofp, "%12.3f", - bp->total_ticks_in_state / ticks_per_us); - fprintf(ofp, "%8d\n", (int)vec_len(bp->ticks_in_state)); - } - - if (scatterplot) { - for (j = 0; j < vec_len(bp->ticks_in_state); j++) { - fprintf(ofp, "%.3f\n", - (f64)bp->ticks_in_state[j] / ticks_per_us); - } - } - - total_time += bp->total_ticks_in_state; - } - - if (!summary_stats_only) - fprintf(ofp, "\n"); - fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", - exclude_kernel_from_summary_stats ? "exclude" : "include"); - if (name_filter) - fprintf(ofp, - "Note: only pid/proc/threads matching '%s' are included.\n", - name_filter); - - fprintf(ofp, - "Total runtime: %10.3f (us), Total state switches: %.0f\n", - total_time / ticks_per_us, total_switches); - fprintf(ofp, "Average time in state: %10.3f (us)\n", - (total_time / total_switches) / ticks_per_us); -} - -char *mapfile (char *file) -{ - struct stat statb; - char *rv; - int maphfile; - size_t mapfsize; - - maphfile = open (file, O_RDONLY); - - if (maphfile < 0) - { - fprintf (stderr, "Couldn't read %s, skipping it...\n", file); - return (NULL); - } - - if (fstat (maphfile, &statb) < 0) - { - fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); - return (NULL); - } - - /* Don't try to mmap directories, FIFOs, semaphores, etc. */ - if (! (statb.st_mode & S_IFREG)) { - fprintf (stderr, "%s is not a regular file, skipping it...\n", file); - return (NULL); - } - - mapfsize = statb.st_size; - - if (mapfsize < 3) - { - fprintf (stderr, "%s zero-length, skipping it...\n", file); - close (maphfile); - return (NULL); - } - - rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); - - if (rv == 0) - { - fprintf (stderr, "%s problem mapping, I quit...\n", file); - exit (-1); - } - close (maphfile); - return (rv); -} - -/* - * main - */ -int main (int argc, char **argv) -{ - char *cpel_file = 0; - char *outputfile = 0; - FILE *ofp; - char *cpel; - int verbose=0; - int curarg=1; - - while (curarg < argc) { - if (!strncmp(argv[curarg], "--input-file", 3)) { - curarg++; - if (curarg < argc) { - cpel_file = argv[curarg]; - curarg++; - continue; - } - fatal("Missing filename after --input-file\n"); - } - if (!strncmp(argv[curarg], "--output-file", 3)) { - curarg ++; - if (curarg < argc) { - outputfile = argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filename after --output-file\n"); - } - if (!strncmp(argv[curarg], "--verbose", 3)) { - curarg++; - verbose++; - continue; - } - if (!strncmp(argv[curarg], "--scatterplot", 4)) { - curarg++; - scatterplot=1; - continue; - } - - if (!strncmp(argv[curarg], "--state-event", 4)) { - curarg++; - if (curarg < argc) { - state_event_code = atol(argv[curarg]); - curarg ++; - continue; - } - fatal("Missing integer after --state-event\n"); - } - if (!strncmp(argv[curarg], "--max-time-sort", 7)) { - sort_type = SORT_MAX_TIME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { - sort_type = SORT_MAX_OCCURRENCES; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--name-sort", 3)) { - sort_type = SORT_NAME; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--kernel-included", 3)) { - exclude_kernel_from_summary_stats = 0; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--summary", 3)) { - summary_stats_only=1; - curarg++; - continue; - } - if (!strncmp(argv[curarg], "--filter", 3)) { - curarg ++; - if (curarg < argc) { - name_filter = (u8 *)argv[curarg]; - curarg ++; - continue; - } - fatal("Missing filter string after --filter\n"); - } - - - usage: - fprintf(stderr, - "cpelstate --input-file [--output-file ]\n"); - fprintf(stderr, - " [--state-event ] [--verbose]\n"); - fprintf(stderr, - " [--max-time-sort(default) | --max-occurrence-sort |\n"); - - fprintf(stderr, - " --name-sort-sort] [--kernel-included]\n"); - - fprintf(stderr, - " [--summary-stats-only] [--scatterplot]\n"); - - fprintf(stderr, "%s\n", version); - exit(1); - } - - if (cpel_file == 0) - goto usage; - - cpel = mapfile(cpel_file); - if (cpel == 0) { - fprintf(stderr, "Couldn't map %s...\n", cpel_file); - exit(1); - } - - if (!outputfile) { - ofp = fdopen(1, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't fdopen(1)?\n"); - exit(1); - } - } else { - ofp = fopen(outputfile, "w"); - if (ofp == NULL) { - fprintf(stderr, "Couldn't create %s...\n", outputfile); - exit(1); - } - } - - the_strtab_hash = hash_create_string (0, sizeof (uword)); - the_evtdef_hash = hash_create (0, sizeof (uword)); - the_trackdef_hash = hash_create (0, sizeof (uword)); - - if (cpel_dump((u8 *) cpel, verbose, ofp)) { - if (outputfile) - unlink(outputfile); - } - - compute_state_statistics(verbose, ofp); - sort_state_statistics(sort_type, ofp); - print_state_statistics(verbose, ofp); - - fclose(ofp); - return(0); -} diff --git a/perftool/delsvec.c b/perftool/delsvec.c deleted file mode 100644 index 724935d331e..00000000000 --- a/perftool/delsvec.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Break up a delimited string into a vector of substrings */ - -#include -#include -#include -#include -#include - -/* - * #define UNIT_TESTS 1 - * #define MATCH_TRACE 1 - */ - -/* - * delsvec - * break up an input string into a vector of [null-terminated] u8 *'s - * - * Each supplied delimiter character results in a string in the output - * vector, unless the delimiters occur back-to-back. When matched, - * a whitespace character in the delimiter consumes an arbitrary - * run of whitespace. See the unit tests at the end of this file - * for a set of examples. - * - * Returns a u8 **, or NULL if the input fails to match. It is assumed - * that both input and fmt are C strings, not necessarily vectors. - * - * Output strings are both vectors and proper C strings. - */ - -static u8 **string_cache; -static u8 **svec_cache; - -void delsvec_recycle_this_string (u8 *s) -{ - if (s) { - _vec_len (s) = 0; - vec_add1(string_cache, s); - } -} - -void delsvec_recycle_this_svec (u8 **svec) -{ - if (svec) { - if (svec_cache) { - vec_free (svec_cache); - } - _vec_len (svec) = 0; - svec_cache = svec; - } -} - -int pvl (char *a) -{ - return vec_len(a); -} - -u8 **delsvec(void *input_arg, char *fmt) -{ - u8 **rv = 0; - int input_index=0; - u8 *this; - int dirflag=0; - int i; - u8 *input = input_arg; - - if (svec_cache) { - rv = svec_cache; - svec_cache = 0; - } - - while (fmt) { - dirflag=0; - if (vec_len (string_cache) > 0) { - this = string_cache [vec_len(string_cache)-1]; - _vec_len (string_cache) = vec_len (string_cache) - 1; - } else - this = 0; - /* - * '*' means one of two things: match the rest of the input, - * or match as many characters as possible - */ - if (fmt[0] == '*') { - fmt++; - dirflag=1; - /* - * no more format: eat rest of string... - */ - if (!fmt[0]) { - for (;input[input_index]; input_index++) - vec_add1(this, input[input_index]); - if (vec_len(this)) { - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("final star-match adds: '%s'\n", this); -#endif - vec_add1(rv, this); - } else { - vec_add1(string_cache, this); - } - - return(rv); - } - } - /* - * Left-to-right scan, adding chars until next delimiter char - * appears. - */ - if (!dirflag) { - while (input[input_index]) { - if (input[input_index] == fmt[0]) { - /* If we just (exact) matched a whitespace delimiter */ - if (fmt[0] == ' '){ - /* scan forward eating whitespace */ - while (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') - input_index++; - input_index--; - } - goto found; - } - /* If we're looking for whitespace */ - if (fmt[0] == ' ') { - /* and we have whitespace */ - if (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') { - /* scan forward eating whitespace */ - while (input[input_index] == ' ' || - input[input_index] == '\t' || - input[input_index] == '\n') { - input_index++; - } - input_index--; - goto found; - } - } - /* Not a delimiter, save it */ - vec_add1(this, input[input_index]); - input_index++; - } - /* - * Fell off the wagon, clean up and bail out - */ - bail: - -#ifdef MATCH_TRACE - printf("failed, fmt[0] = '%c', input[%d]='%s'\n", - fmt[0], input_index, &input[input_index]); -#endif - delsvec_recycle_this_string(this); - for (i = 0; i < vec_len(rv); i++) - delsvec_recycle_this_string(rv[i]); - delsvec_recycle_this_svec(rv); - return(0); - - found: - /* - * Delimiter matched - */ - input_index++; - fmt++; - /* - * If we actually accumulated non-delimiter characters, - * add them to the result vector - */ - if (vec_len(this)) { - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("match: add '%s'\n", this); -#endif - vec_add1(rv, this); - } else { - vec_add1(string_cache, this); - } - } else { - /* - * right-to-left scan, '*' not at - * the end of the delimiter string - */ - i = input_index; - while (input[++i]) - ; /* scan forward */ - i--; - while (i > input_index) { - if (input[i] == fmt[0]) - goto found2; - - if (fmt[0] == ' ' || fmt[0] == '\t' || - fmt[0] == '\n') { - if (input[i] == ' ' || - input[i] == '\t' || - input[i] == '\n') - goto found2; - } - i--; - } - goto bail; - - found2: - for (; input_index < i; input_index++) { - vec_add1(this, input[input_index]); - } - input_index++; - fmt++; - vec_add1(this, 0); -#ifdef MATCH_TRACE - printf("inner '*' match: add '%s'\n", this); -#endif - vec_add1(rv, this); - } - } - return (rv); -} - -#ifdef UNIT_TESTS - -typedef struct utest_ { - char *string; - char *fmt; -} utest_t; - -utest_t tests[] = { -#ifdef NOTDEF - {"Dec 7 08:56", - " :*"}, - {"Dec 17 08:56", - " :*"}, - {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", - " ::. / // [] *"}, - {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", - "///: ::. : []: *"}, - /* Expected to fail */ - {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", - "///: ::. : : *"}, - /* Expected to fail */ - {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", - " ::. / // [] *"}, - {"THIS that and + theother", "*+ *"}, - {"Dec 12 15:33:07.103 ifmgr/errors 0/RP0/CPU0 3# t2 Failed to open IM connection: No such file or directory", " ::. / // *"}, - {"Dec 16 21:43:47.328 ifmgr/bulk 0/3/CPU0 t8 Bulk DPC async download complete. Partitions 1, node_count 1, total_out 0, out_offset 0, out_expected 0: No error"," ::. / // *"}, - {"t:0x53034bd6 CPU:00 PROCESS :PROCCREATE_NAME", - ": : :*"}, - {" pid:1", " *"}, - {"t:0x53034cbb CPU:00 THREAD :THCREATE pid:1 tid:1", - ": : : pid: tid:*"}, - {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", - ": : : *"}, - {"/hfr-base-3.3.85/lib/libttyconnection.dll 0xfc000000 0x0000306c 0xfc027000 0x000001c8 1", - " *"}, - {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_receive:ifmgr/t8:IMC_MSG_MTU_UPDATE:ppp_ma/t1", - " ::. // ::::*"}, - - {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_send_event:call:ifmgr/t8:124/0:cdp/t1", - " ::. // :msg_send_event::::*"}, - - {"Feb 28 02:38:26.125 seqtrace 0/1/CPU0 t1 :msg_receive_event:cdp/t1:124/0", - " ::. // :msg_receive_event::*"} - {"t:0x645dd86d CPU:00 USREVENT:EVENT:100, d0:0x00000002 d1:0x00000000", - ": : USREVENT:EVENT:, d0: *"} - {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", - ": : : *"}, - {"t:0x2ccf9f5a CPU:00 INT_ENTR:0x80000000 (-2147483648) IP:0x002d8b18", - ": : INT_ENTR: IP:*"} - {"t:0xd473951c CPU:00 KER_EXIT:SCHED_GET/88 ret_val:2 sched_priority:10", - ": : KER_EXIT:SCHED_GET : sched_priority:*"} - {"t:0x00000123 CPU:01 SYSTEM :FUNC_ENTER thisfn:0x40e62048 call_site:0x00000000", - ": : SYSTEM :FUNC_ thisfn: *"}, - {"t:0x5af8de95 CPU:00 INT_HANDLER_ENTR:0x0000004d (77) PID:8200 IP:0x00000000 AREA:0x0bf9b290", ": : INT_HANDLER_*"}, -#endif - {"t:0x6d1ff92f CPU:00 CONTROL: BUFFER sequence = 1053, num_events = 714", - ": : CONTROL*"}, - {"t:0x6d1ff92f CPU:00 CONTROL :TIME msb:0x0000003c lsb(offset):0x6d1ff921", - ": : CONTROL*"}, -}; - -int main (int argc, char **argv) -{ - int i, j; - u8 **svec; - - for (j = 0; j < ARRAY_LEN(tests); j++) { - printf ("input string: '%s'\n", tests[j].string); - printf ("delimiter arg: '%s'\n", tests[j].fmt); - printf ("parse trace:\n"); - svec = delsvec(tests[j].string, tests[j].fmt); - if (!svec) { - printf("index %d failed\n", j); - continue; - } - printf("%d substring vectors\n", vec_len(svec)); - for (i = 0; i < vec_len(svec); i++) { - printf("[%d]: '%s'\n", i, svec[i]); - } - printf ("-------------------\n"); - } - exit(0); -} -#endif diff --git a/perftool/linreg.c b/perftool/linreg.c deleted file mode 100644 index 084091bb907..00000000000 --- a/perftool/linreg.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* see "Numerical Recipies in C, 2nd ed." p 665 */ - -#include -#include - -/* - * linreg - * Linear regression of (xi, yi), returns parameters for least-squares - * fit y = a + bx. Also, compute Pearson's R. - */ -void linreg (double *x, double *y, int nitems, double *a, double *b, - double *minp, double *maxp, double *meanp, double *r) -{ - double sx = 0.0; - double sy = 0.0; - double st2 = 0.0; - double min = y[0]; - double max = 0.0; - double ss, meanx, meany, t; - double errx, erry, prodsum, sqerrx, sqerry; - int i; - - *b = 0.0; - - for (i = 0; i < nitems; i++) { - sx += x[i]; - sy += y[i]; - if (y[i] < min) - min = y[i]; - if (y[i] > max) - max = y[i]; - } - ss = nitems; - meanx = sx / ss; - meany = *meanp = sy / ss; - *minp = min; - *maxp = max; - - for (i = 0; i < nitems; i++) { - t = x[i] - meanx; - st2 += t*t; - *b += t*y[i]; - } - - *b /= st2; - *a = (sy-sx*(*b))/ss; - - prodsum = 0.0; - sqerrx = 0.0; - sqerry = 0.0; - - /* Compute numerator of Pearson's R */ - for (i = 0; i < nitems; i++) { - errx = x[i] - meanx; - erry = y[i] - meany; - prodsum += errx * erry; - sqerrx += errx*errx; - sqerry += erry*erry; - } - - *r = prodsum / (sqrt(sqerrx)*sqrt(sqerry)); -} diff --git a/perftool/new.cpel b/perftool/new.cpel deleted file mode 100644 index b0f35958dc0..00000000000 Binary files a/perftool/new.cpel and /dev/null differ diff --git a/perftool/new.elog b/perftool/new.elog deleted file mode 100644 index 2d99bb16b82..00000000000 Binary files a/perftool/new.elog and /dev/null differ diff --git a/perftool/props.c b/perftool/props.c deleted file mode 100644 index 84af5b1c648..00000000000 --- a/perftool/props.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - *------------------------------------------------------------------ - * Copyright (c) 2006-2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -static char *sxerox (char *s); - -#define NBUCKETS 97 - -typedef struct prop_ { - struct prop_ *next; - char *name; - char *value; -} prop_t; - -static prop_t *buckets [NBUCKETS]; -static int hash_shifts[4] = {24, 16, 8, 0}; - -/* - * getprop - */ - -char *getprop (char *name) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t *bp; - int i=0; - - for (cp = (unsigned char *) name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bp = buckets [hash%NBUCKETS]; - - while (bp && strcmp(bp->name, name)) { - bp = bp->next; - } - - if (bp == NULL) - return (0); - else - return (bp->value); -} - -/* - * getprop_default - */ - -char *getprop_default (char *name, char *def) -{ - char *rv; - rv = getprop (name); - if (rv) - return (rv); - else - return (def); -} - -/* - * addprop - */ - -void addprop (char *name, char *value) -{ - unsigned char *cp; - unsigned long hash=0; - prop_t **bpp; - prop_t *bp; - int i=0; - - bp = (prop_t *)malloc (sizeof (prop_t)); - - bp->next = 0; - bp->name = sxerox (name); - bp->value = sxerox (value); - - for (cp = (unsigned char *)name; *cp; cp++) - hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); - - bpp = &buckets [hash%NBUCKETS]; - - if (*bpp == NULL) - *bpp = bp; - else { - bp->next = *bpp; - *bpp = bp; - } -} - -/* - * sxerox - */ - -static char *sxerox (char *s) -{ - char *rv = (char *) malloc (strlen (s) + 1); - strcpy (rv, s); - return rv; -} - -/* - * readprops - */ - -#define START 0 -#define READNAME 1 -#define READVALUE 2 -#define C_COMMENT 3 -#define CPP_COMMENT 4 - -int readprops (char *filename) -{ - FILE *ifp; - unsigned char c; - int state=START; - int linenum=1; - char namebuf [128]; - char valbuf [512]; - int i; - - ifp = fopen (filename, "r"); - - if (ifp == NULL) - return (-1); - - while (1) { - - readchar: - c = getc (ifp); - - again: - switch (state) { - case START: - if (feof (ifp)) { - fclose (ifp); - return (0); - } - - if (c == ' ' || c == '\t') - goto readchar; - - if (c == '\n') { - linenum++; - goto readchar; - } - if (isalpha (c) || (c == '_')) { - state = READNAME; - goto again; - } - if (c == '/') { - c = getc (ifp); - if (c == '/') { - state = CPP_COMMENT; - goto readchar; - } else if (c == '*') { - state = C_COMMENT; - goto readchar; - } else { - fprintf (stderr, "unknown token '/' line %d\n", - linenum); - exit(1); - } - } - fprintf (stderr, "unknown token '%c' line %d\n", - c, linenum); - exit (1); - break; - - case CPP_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) - return (0); - if (c == '\n') { - linenum++; - state = START; - goto readchar; - } - } - break; - - case C_COMMENT: - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "unterminated comment, line %d\n", - linenum); - exit (1); - } - if (c == '*') { - staragain: - c = getc (ifp); - if (c == '/') { - state = START; - goto readchar; - } - if (c == '*') - goto staragain; - } - } - break; - - case READNAME: - i = 0; - namebuf[i++] = c; - while (1) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a name, line %d\n", - linenum); - exit (1); - } - if ((!isalnum (c)) && (c != '_')) { - namebuf [i] = 0; - state = READVALUE; - goto again; - } - namebuf [i++] = c; - } - break; - - case READVALUE: - i = 0; - while ((c == ' ') || (c == '\t') || (c == '=')) { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF while reading a value, line %d\n", - linenum); - exit (1); - } - } - goto firsttime; - while (1) { - c = getc (ifp); - - firsttime: - if (c == '\\') { - c = getc (ifp); - if (feof (ifp)) { - fprintf (stderr, "EOF after '\\', line %d\n", - linenum); - exit (1); - } - valbuf[i++] = c; - continue; - } - if (c == '\n') { - linenum++; - while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') - i--; - valbuf[i] = 0; - addprop (namebuf, valbuf); - state = START; - goto readchar; - } - valbuf[i++] = c; - } - - } - } -} diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 100f089e0fe..a101e47f5d7 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -28,10 +28,6 @@ if ENABLE_sample_PLUGIN SUBDIRS += sample-plugin endif -if ENABLE_sixrd_PLUGIN -SUBDIRS += sixrd-plugin -endif - if ENABLE_ioam_PLUGIN SUBDIRS += ioam-plugin endif @@ -44,18 +40,10 @@ if ENABLE_snat_PLUGIN SUBDIRS += snat-plugin endif -if ENABLE_ila_PLUGIN -SUBDIRS += ila-plugin -endif - if ENABLE_lb_PLUGIN SUBDIRS += lb-plugin endif -if ENABLE_flowperpkt_PLUGIN -SUBDIRS += flowperpkt-plugin -endif - if ENABLE_acl_PLUGIN SUBDIRS += acl-plugin endif diff --git a/plugins/configure.ac b/plugins/configure.ac index 6e7d5b8ad1e..9c631634ff6 100644 --- a/plugins/configure.ac +++ b/plugins/configure.ac @@ -53,12 +53,9 @@ AM_CONDITIONAL(ENABLE_$1_PLUGIN, test "$enable_the_plugin" = "1") # SUBDIRS += new-plugin # endif -PLUGIN_ENABLED(sixrd) PLUGIN_ENABLED(ioam) PLUGIN_ENABLED(snat) -PLUGIN_ENABLED(ila) PLUGIN_ENABLED(lb) -PLUGIN_ENABLED(flowperpkt) PLUGIN_ENABLED(acl) # Disabled plugins, require --enable-XXX-plugin diff --git a/plugins/flowperpkt-plugin/Makefile.am b/plugins/flowperpkt-plugin/Makefile.am deleted file mode 100644 index 9354e26faa2..00000000000 --- a/plugins/flowperpkt-plugin/Makefile.am +++ /dev/null @@ -1,64 +0,0 @@ - -# Copyright (c) -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = flowperpkt_plugin.la -vppapitestplugins_LTLIBRARIES = flowperpkt_test_plugin.la - -flowperpkt_plugin_la_SOURCES = flowperpkt/flowperpkt.c \ - flowperpkt/l2_node.c \ - flowperpkt/node.c \ - flowperpkt/flowperpkt_plugin.api.h -flowperpkt_plugin_la_LDFLAGS = -module - -BUILT_SOURCES = \ - flowperpkt/flowperpkt.api.h \ - flowperpkt/flowperpkt.api.json - -SUFFIXES = .api.h .api .api.json - -%.api.h: %.api - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --output $@ --show-name $@ - -%.api.json: %.api - @echo " JSON APIGEN " $@ ; \ - mkdir -p `dirname $@` ; \ - $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ - | vppapigen --input - --json $@ - -apidir = $(prefix)/flowperpkt/ -api_DATA = flowperpkt/flowperpkt.api.json - -noinst_HEADERS = \ - flowperpkt/flowperpkt_all_api_h.h \ - flowperpkt/flowperpkt_msg_enum.h \ - flowperpkt/flowperpkt.api.h - -flowperpkt_test_plugin_la_SOURCES = \ - flowperpkt/flowperpkt_test.c flowperpkt/flowperpkt_plugin.api.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) - @(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) - diff --git a/plugins/flowperpkt-plugin/configure.ac b/plugins/flowperpkt-plugin/configure.ac deleted file mode 100644 index 80546169efd..00000000000 --- a/plugins/flowperpkt-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ - -AC_INIT(flowperpkt_plugin, 1.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) - -AC_PROG_LIBTOOL -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api deleted file mode 100644 index fa878f21ed3..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.api +++ /dev/null @@ -1,42 +0,0 @@ -/* Define a simple enable-disable binary API to control the feature */ - -/** \file - This file defines the vpp control-plane API messages - used to control the flowperpkt plugin -*/ - -/** \brief Enable / disable per-packet IPFIX recording on an interface - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param is_add - add address if non-zero, else delete - @param is_ipv6 - if non-zero the address is ipv6, else ipv4 - @param sw_if_index - index of the interface -*/ -manual_print define flowperpkt_tx_interface_add_del -{ - /* Client identifier, set from api_main.my_client_index */ - u32 client_index; - - /* Arbitrary context, so client can match reply to request */ - u32 context; - - /* Enable / disable the feature */ - u8 is_add; - u8 which; /* 0 = ipv4, 1 = l2, 2 = ipv6 (not yet implemented) */ - - /* Interface handle */ - u32 sw_if_index; -}; - -/** \brief Reply to enable/disable per-packet IPFIX recording messages - @param context - returned sender context, to match reply w/ request - @param retval - return code -*/ -define flowperpkt_tx_interface_add_del_reply -{ - /* From the request */ - u32 context; - - /* Return value, zero means all OK */ - i32 retval; -}; diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c deleted file mode 100644 index fb71d5b0ffc..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - * flowperpkt.c - per-packet data capture flow report plugin - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file - * @brief Per-packet IPFIX flow record generator plugin - * - * This file implements vpp plugin registration mechanics, - * debug CLI, and binary API handling. - */ - -#include -#include -#include - -#include -#include -#include - -/* define message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* define generated endian-swappers */ -#define vl_endianfun -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include -#undef vl_printfun - -flowperpkt_main_t flowperpkt_main; - -/* Get the API version number */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -/* Define the per-interface configurable features */ -/* *INDENT-OFF* */ -VNET_FEATURE_INIT (flow_perpacket_ipv4, static) = -{ - .arc_name = "ip4-output", - .node_name = "flowperpkt-ipv4", - .runs_before = VNET_FEATURES ("interface-output"), -}; - -VNET_FEATURE_INIT (flow_perpacket_l2, static) = -{ - .arc_name = "interface-output", - .node_name = "flowperpkt-l2", - .runs_before = VNET_FEATURES ("interface-tx"), -}; -/* *INDENT-ON* */ - -/* - * A handy macro to set up a message reply. - * Assumes that the following variables are available: - * mp - pointer to request message - * rmp - pointer to reply message type - * rv - return value - */ -#define REPLY_MACRO(t) \ -do { \ - unix_shared_memory_queue_t * q = \ - vl_api_client_index_to_input_queue (mp->client_index); \ - if (!q) \ - return; \ - \ - rmp = vl_msg_api_alloc (sizeof (*rmp)); \ - rmp->_vl_msg_id = ntohs((t)+fm->msg_id_base); \ - rmp->context = mp->context; \ - rmp->retval = ntohl(rv); \ - \ - vl_msg_api_send_shmem (q, (u8 *)&rmp); \ -} while(0); - -/* Macro to finish up custom dump fns */ -#define FINISH \ - vec_add1 (s, 0); \ - vl_print (handle, (char *)s); \ - vec_free (s); \ - return handle; - -#define VALIDATE_SW_IF_INDEX(mp) \ - do { u32 __sw_if_index = ntohl(mp->sw_if_index); \ - vnet_main_t *__vnm = vnet_get_main(); \ - if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ - __sw_if_index)) { \ - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ - goto bad_sw_if_index; \ - } \ -} while(0); - -#define BAD_SW_IF_INDEX_LABEL \ -do { \ -bad_sw_if_index: \ - ; \ -} while (0); - -/** - * @brief Create an IPFIX template packet rewrite string - * @param frm flow_report_main_t * - * @param fr flow_report_t * - * @param collector_address ip4_address_t * the IPFIX collector address - * @param src_address ip4_address_t * the source address we should use - * @param collector_port u16 the collector port we should use, host byte order - * @returns u8 * vector containing the indicated IPFIX template packet - */ -static inline u8 * -flowperpkt_template_rewrite_inline (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port, int variant) -{ - ip4_header_t *ip; - udp_header_t *udp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - ipfix_template_header_t *t; - ipfix_field_specifier_t *f; - ipfix_field_specifier_t *first_field; - u8 *rewrite = 0; - ip4_ipfix_template_packet_t *tp; - u32 field_count = 0; - flow_report_stream_t *stream; - flowperpkt_main_t *fm = &flowperpkt_main; - - stream = &frm->streams[fr->stream_index]; - - if (variant == FLOW_VARIANT_IPV4) - { - /* - * ip4 Supported Fields: - * - * ingressInterface, TLV type 10, u32 - * egressInterface, TLV type 14, u32 - * sourceIpv4Address, TLV type 8, u32 - * destinationIPv4Address, TLV type 12, u32 - * ipClassOfService, TLV type 5, u8 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * warning: wireshark doesn't really understand this TLV - * dataLinkFrameSize, TLV type 312, u16 - * warning: wireshark doesn't understand this TLV at all - */ - - /* Currently 7 fields */ - field_count += 7; - - /* allocate rewrite space */ - vec_validate_aligned - (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); - } - else if (variant == FLOW_VARIANT_L2) - { - /* - * L2 Supported Fields: - * - * ingressInterface, TLV type 10, u32 - * egressInterface, TLV type 14, u32 - * sourceMacAddress, TLV type 56, u8[6] we hope - * destinationMacAddress, TLV type 57, u8[6] we hope - * ethernetType, TLV type 256, u16 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * warning: wireshark doesn't really understand this TLV - * dataLinkFrameSize, TLV type 312, u16 - * warning: wireshark doesn't understand this TLV at all - */ - - /* Currently 7 fields */ - field_count += 7; - - /* allocate rewrite space */ - vec_validate_aligned - (rewrite, - sizeof (ip4_ipfix_template_packet_t) - + field_count * sizeof (ipfix_field_specifier_t) - 1, - CLIB_CACHE_LINE_BYTES); - } - - tp = (ip4_ipfix_template_packet_t *) rewrite; - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - t = (ipfix_template_header_t *) (s + 1); - first_field = f = (ipfix_field_specifier_t *) (t + 1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->src_address.as_u32 = src_address->as_u32; - ip->dst_address.as_u32 = collector_address->as_u32; - udp->src_port = clib_host_to_net_u16 (stream->src_port); - udp->dst_port = clib_host_to_net_u16 (collector_port); - udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); - - /* FIXUP: message header export_time */ - /* FIXUP: message header sequence_number */ - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* Add TLVs to the template */ - if (variant == FLOW_VARIANT_IPV4) - { - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ingressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , egressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, - 1); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, - 8); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, - 2); - f++; - } - else if (variant == FLOW_VARIANT_L2) - { - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , ingressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , egressInterface, - 4); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress, - 6); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6); - f++; - f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType, - 2); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, - 8); - f++; - f->e_id_length = - ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, - 2); - f++; - } - - /* Extend in the obvious way, right here... */ - - /* Back to the template packet... */ - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - - ASSERT (f - first_field); - /* Field count in this template */ - t->id_count = ipfix_id_count (fr->template_id, f - first_field); - - if (variant == FLOW_VARIANT_IPV4) - fm->ipv4_report_id = fr->template_id; - else if (variant == FLOW_VARIANT_L2) - fm->l2_report_id = fr->template_id; - - /* set length in octets */ - s->set_id_length = - ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); - - /* message length in octets */ - h->version_length = version_length ((u8 *) f - (u8 *) h); - - ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip); - ip->checksum = ip4_header_checksum (ip); - - return rewrite; -} - -u8 * -flowperpkt_template_rewrite_ipv4 (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return flowperpkt_template_rewrite_inline - (frm, fr, collector_address, src_address, collector_port, - FLOW_VARIANT_IPV4); -} - -u8 * -flowperpkt_template_rewrite_l2 (flow_report_main_t * frm, - flow_report_t * fr, - ip4_address_t * collector_address, - ip4_address_t * src_address, - u16 collector_port) -{ - return flowperpkt_template_rewrite_inline - (frm, fr, collector_address, src_address, collector_port, - FLOW_VARIANT_L2); -} - - -/** - * @brief Flush accumulated data - * @param frm flow_report_main_t * - * @param fr flow_report_t * - * @param f vlib_frame_t * - * - * Notes: - * This function must simply return the incoming frame, or no template packets - * will be sent. - */ -vlib_frame_t * -flowperpkt_data_callback_ipv4 (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, - u32 node_index) -{ - flowperpkt_flush_callback_ipv4 (); - return f; -} - -vlib_frame_t * -flowperpkt_data_callback_l2 (flow_report_main_t * frm, - flow_report_t * fr, - vlib_frame_t * f, u32 * to_next, u32 node_index) -{ - flowperpkt_flush_callback_l2 (); - return f; -} - -/** - * @brief configure / deconfigure the IPFIX flow-per-packet - * @param fm flowperpkt_main_t * fm - * @param sw_if_index u32 the desired interface - * @param is_add int 1 to enable the feature, 0 to disable it - * @returns 0 if successful, non-zero otherwise - */ - -static int flowperpkt_tx_interface_add_del_feature - (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add) -{ - flow_report_main_t *frm = &flow_report_main; - vnet_flow_report_add_del_args_t _a, *a = &_a; - int rv; - - if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created) - { - memset (a, 0, sizeof (*a)); - a->rewrite_callback = flowperpkt_template_rewrite_ipv4; - a->flow_data_callback = flowperpkt_data_callback_ipv4; - a->is_add = 1; - a->domain_id = 1; /*$$$$ config parameter */ - a->src_port = 4739; /*$$$$ config parameter */ - fm->ipv4_report_created = 1; - - rv = vnet_flow_report_add_del (frm, a); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created) - { - memset (a, 0, sizeof (*a)); - a->rewrite_callback = flowperpkt_template_rewrite_l2; - a->flow_data_callback = flowperpkt_data_callback_l2; - a->is_add = 1; - a->domain_id = 1; /*$$$$ config parameter */ - a->src_port = 4739; /*$$$$ config parameter */ - fm->l2_report_created = 1; - - rv = vnet_flow_report_add_del (frm, a); - if (rv) - { - clib_warning ("vnet_flow_report_add_del returned %d", rv); - return -1; - } - } - - if (which == FLOW_VARIANT_IPV4) - vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4", - sw_if_index, is_add, 0, 0); - else if (which == FLOW_VARIANT_L2) - vnet_feature_enable_disable ("interface-output", "flowperpkt-l2", - sw_if_index, is_add, 0, 0); - - return 0; -} - -/** - * @brief API message handler - * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message - */ -void vl_api_flowperpkt_tx_interface_add_del_t_handler - (vl_api_flowperpkt_tx_interface_add_del_t * mp) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - vl_api_flowperpkt_tx_interface_add_del_reply_t *rmp; - u32 sw_if_index = ntohl (mp->sw_if_index); - int rv = 0; - - VALIDATE_SW_IF_INDEX (mp); - - if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2) - { - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto out; - } - - rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which, - mp->is_add); -out: - BAD_SW_IF_INDEX_LABEL; - - REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY); -} - -/** - * @brief API message custom-dump function - * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message - * @param handle void * print function handle - * @returns u8 * output string - */ -static void *vl_api_flowperpkt_tx_interface_add_del_t_print - (vl_api_flowperpkt_tx_interface_add_del_t * mp, void *handle) -{ - u8 *s; - - s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del "); - s = format (s, "sw_if_index %d is_add %d which %d ", - clib_host_to_net_u32 (mp->sw_if_index), - (int) mp->is_add, (int) mp->which); - FINISH; -} - -/* List of message types that this plugin understands */ -#define foreach_flowperpkt_plugin_api_msg \ -_(FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del) - -/** - * @brief plugin-api required function - * @param vm vlib_main_t * vlib main data structure pointer - * @param h vlib_plugin_handoff_t * handoff structure - * @param from_early_init int notused - * - * Notes: - * This routine exists to convince the vlib plugin framework that - * we haven't accidentally copied a random .dll into the plugin directory. - * - * Also collects global variable pointers passed from the vpp engine - */ -clib_error_t * -vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, - int from_early_init) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - clib_error_t *error = 0; - - fm->vlib_main = vm; - fm->vnet_main = h->vnet_main; - - return error; -} - -static clib_error_t * -flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - u32 sw_if_index = ~0; - int is_add = 1; - u8 which = FLOW_VARIANT_IPV4; - - int rv; - - while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (input, "disable")) - is_add = 0; - else if (unformat (input, "%U", unformat_vnet_sw_interface, - fm->vnet_main, &sw_if_index)); - else if (unformat (input, "l2")) - which = FLOW_VARIANT_L2; - else - break; - } - - if (sw_if_index == ~0) - return clib_error_return (0, "Please specify an interface..."); - - rv = - flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add); - switch (rv) - { - case 0: - break; - - case VNET_API_ERROR_INVALID_SW_IF_INDEX: - return clib_error_return - (0, "Invalid interface, only works on physical ports"); - break; - - case VNET_API_ERROR_UNIMPLEMENTED: - return clib_error_return (0, "ip6 not supported"); - break; - - default: - return clib_error_return (0, "flowperpkt_enable_disable returned %d", - rv); - } - return 0; -} - -/*? - * 'flowperpkt feature add-del' commands to enable/disable - * per-packet IPFIX flow record generation on an interface - * - * @cliexpar - * @parblock - * To enable per-packet IPFIX flow-record generation on an interface: - * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0} - * - * To disable per-packet IPFIX flow-record generation on an interface: - * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0 disable} - * @cliexend - * @endparblock -?*/ -/* *INDENT-OFF* */ -VLIB_CLI_COMMAND (flowperpkt_enable_disable_command, static) = { - .path = "flowperpkt feature add-del", - .short_help = - "flowperpkt feature add-del [disable]", - .function = flowperpkt_tx_interface_add_del_feature_command_fn, -}; -/* *INDENT-ON* */ - -/** - * @brief Set up the API message handling tables - * @param vm vlib_main_t * vlib main data structure pointer - * @returns 0 to indicate all is well - */ -static clib_error_t * -flowperpkt_plugin_api_hookup (vlib_main_t * vm) -{ - flowperpkt_main_t *fm = &flowperpkt_main; -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + fm->msg_id_base), \ - #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_flowperpkt_plugin_api_msg; -#undef _ - - return 0; -} - -#define vl_msg_name_crc_list -#include -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (flowperpkt_main_t * fm, api_main_t * am) -{ -#define _(id,n,crc) \ - vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base); - foreach_vl_msg_name_crc_flowperpkt; -#undef _ -} - -/** - * @brief Set up the API message handling tables - * @param vm vlib_main_t * vlib main data structure pointer - * @returns 0 to indicate all is well, or a clib_error_t - */ -static clib_error_t * -flowperpkt_init (vlib_main_t * vm) -{ - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_thread_main_t *tm = &vlib_thread_main; - clib_error_t *error = 0; - u32 num_threads; - u8 *name; - - /* Construct the API name */ - name = format (0, "flowperpkt_%08x%c", api_version, 0); - - /* Ask for a correctly-sized block of API message decode slots */ - fm->msg_id_base = vl_msg_api_get_msg_ids - ((char *) name, VL_MSG_FIRST_AVAILABLE); - - /* Hook up message handlers */ - error = flowperpkt_plugin_api_hookup (vm); - - /* Add our API messages to the global name_crc hash table */ - setup_message_id_table (fm, &api_main); - - vec_free (name); - - /* Decide how many worker threads we have */ - num_threads = 1 /* main thread */ + tm->n_eal_threads; - - /* Allocate per worker thread vectors */ - vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1); - vec_validate (fm->l2_buffers_per_worker, num_threads - 1); - vec_validate (fm->ipv4_frames_per_worker, num_threads - 1); - vec_validate (fm->l2_frames_per_worker, num_threads - 1); - vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1); - vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1); - - /* Set up time reference pair */ - fm->vlib_time_0 = vlib_time_now (vm); - fm->nanosecond_time_0 = unix_time_now_nsec (); - - return error; -} - -VLIB_INIT_FUNCTION (flowperpkt_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h deleted file mode 100644 index 20f6939dda5..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * flowperpkt.h - skeleton vpp engine plug-in header file - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __included_flowperpkt_h__ -#define __included_flowperpkt_h__ - -#include -#include -#include - -#include -#include -#include -#include - -/** - * @file - * @brief flow-per-packet plugin header file - */ -typedef struct -{ - /** API message ID base */ - u16 msg_id_base; - - /** Have the reports [templates] been created? */ - int ipv4_report_created; - int l2_report_created; - - /** stream/template IDs */ - u16 ipv4_report_id; - u16 l2_report_id; - - /** ipfix buffers under construction, per-worker thread */ - vlib_buffer_t **ipv4_buffers_per_worker; - vlib_buffer_t **l2_buffers_per_worker; - - /** frames containing ipfix buffers, per-worker thread */ - vlib_frame_t **ipv4_frames_per_worker; - vlib_frame_t **l2_frames_per_worker; - - /** next record offset, per worker thread */ - u16 *ipv4_next_record_offset_per_worker; - u16 *l2_next_record_offset_per_worker; - - /** Time reference pair */ - u64 nanosecond_time_0; - f64 vlib_time_0; - - /** convenience vlib_main_t pointer */ - vlib_main_t *vlib_main; - /** convenience vnet_main_t pointer */ - vnet_main_t *vnet_main; -} flowperpkt_main_t; - -typedef enum -{ - FLOW_VARIANT_IPV4, - FLOW_VARIANT_L2, - FLOW_N_VARIANTS, -} flowperpkt_variant_t; - -extern flowperpkt_main_t flowperpkt_main; - -extern vlib_node_registration_t flowperpkt_ipv4_node; - -void flowperpkt_flush_callback_ipv4 (void); -void flowperpkt_flush_callback_l2 (void); - -#endif /* __included_flowperpkt_h__ */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h deleted file mode 100644 index 329c375abca..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_all_api_h.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * flowperpkt_all_api_h.h - plug-in api #include file - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* Include the generated file, see BUILT_SOURCES in Makefile.am */ -#include diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h deleted file mode 100644 index 3177e77a63b..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_msg_enum.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * flowperpkt_msg_enum.h - vpp engine plug-in message enumeration - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef included_flowperpkt_msg_enum_h -#define included_flowperpkt_msg_enum_h - -#include - -#define vl_msg_id(n,h) n, -typedef enum -{ -#include - /* We'll want to know how many messages IDs we need... */ - VL_MSG_FIRST_AVAILABLE, -} vl_msg_id_t; -#undef vl_msg_id - -#endif /* included_flowperpkt_msg_enum_h */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c b/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c deleted file mode 100644 index 716818ffe0a..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/flowperpkt_test.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * flowperpkt.c - skeleton vpp-api-test plug-in - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -/** - * @file vpp_api_test plugin - */ - -uword unformat_sw_if_index (unformat_input_t * input, va_list * args); - -/* Declare message IDs */ -#include - -/* define message structures */ -#define vl_typedefs -#include -#undef vl_typedefs - -/* declare message handlers for each api */ - -#define vl_endianfun /* define message structures */ -#include -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) -#define vl_printfun -#include -#undef vl_printfun - -/* Get the API version number. */ -#define vl_api_version(n,v) static u32 api_version=(v); -#include -#undef vl_api_version - -typedef struct -{ - /** API message ID base */ - u16 msg_id_base; - /** vat_main_t pointer */ - vat_main_t *vat_main; -} flowperpkt_test_main_t; - -flowperpkt_test_main_t flowperpkt_test_main; - -#define foreach_standard_reply_retval_handler \ -_(flowperpkt_tx_interface_add_del_reply) - -#define _(n) \ - static void vl_api_##n##_t_handler \ - (vl_api_##n##_t * mp) \ - { \ - vat_main_t * vam = flowperpkt_test_main.vat_main; \ - i32 retval = ntohl(mp->retval); \ - if (vam->async_mode) { \ - vam->async_errors += (retval < 0); \ - } else { \ - vam->retval = retval; \ - vam->result_ready = 1; \ - } \ - } -foreach_standard_reply_retval_handler; -#undef _ - -/* - * Table of message reply handlers, must include boilerplate handlers - * we just generated - */ -#define foreach_vpe_api_reply_msg \ -_(FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY, \ - flowperpkt_tx_interface_add_del_reply) - - -/* M: construct, but don't yet send a message */ - -#define M(T,t) \ -do { \ - vam->result_ready = 0; \ - mp = vl_msg_api_alloc(sizeof(*mp)); \ - memset (mp, 0, sizeof (*mp)); \ - mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base); \ - mp->client_index = vam->my_client_index; \ -} while(0); - -#define M2(T,t,n) \ -do { \ - vam->result_ready = 0; \ - mp = vl_msg_api_alloc(sizeof(*mp)+(n)); \ - memset (mp, 0, sizeof (*mp)); \ - mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base); \ - mp->client_index = vam->my_client_index; \ -} while(0); - -/* S: send a message */ -#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp)) - -/* W: wait for results, with timeout */ -#define W \ -do { \ - timeout = vat_time_now (vam) + 1.0; \ - \ - while (vat_time_now (vam) < timeout) { \ - if (vam->result_ready == 1) { \ - return (vam->retval); \ - } \ - } \ - return -99; \ -} while(0); - -static int -api_flowperpkt_tx_interface_add_del (vat_main_t * vam) -{ - flowperpkt_test_main_t *sm = &flowperpkt_test_main; - unformat_input_t *i = vam->input; - f64 timeout; - int enable_disable = 1; - u8 which = 0; /* ipv4 by default */ - u32 sw_if_index = ~0; - vl_api_flowperpkt_tx_interface_add_del_t *mp; - - /* Parse args required to build the message */ - while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) - { - if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) - ; - else if (unformat (i, "sw_if_index %d", &sw_if_index)) - ; - else if (unformat (i, "disable")) - enable_disable = 0; - else if (unformat (i, "l2")) - which = 1; - else - break; - } - - if (sw_if_index == ~0) - { - errmsg ("missing interface name / explicit sw_if_index number \n"); - return -99; - } - - /* Construct the API message */ - M (FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del); - mp->sw_if_index = ntohl (sw_if_index); - mp->is_add = enable_disable; - mp->which = which; - - /* send it... */ - S; - - /* Wait for a reply... */ - W; -} - -/* - * List of messages that the api test plugin sends, - * and that the data plane plugin processes - */ -#define foreach_vpe_api_msg \ -_(flowperpkt_tx_interface_add_del, " [disable]") - -void -vat_api_hookup (vat_main_t * vam) -{ - flowperpkt_test_main_t *sm = &flowperpkt_test_main; - /* Hook up handlers for replies from the data plane plug-in */ -#define _(N,n) \ - vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ - #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_vpe_api_reply_msg; -#undef _ - - /* API messages we can send */ -#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n); - foreach_vpe_api_msg; -#undef _ - - /* Help strings */ -#define _(n,h) hash_set_mem (vam->help_by_name, #n, h); - foreach_vpe_api_msg; -#undef _ -} - -clib_error_t * -vat_plugin_register (vat_main_t * vam) -{ - flowperpkt_test_main_t *sm = &flowperpkt_test_main; - u8 *name; - - sm->vat_main = vam; - - /* Ask the vpp engine for the first assigned message-id */ - name = format (0, "flowperpkt_%08x%c", api_version, 0); - sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); - - /* Don't attempt to hook up API messages if the data plane plugin is AWOL */ - if (sm->msg_id_base != (u16) ~ 0) - vat_api_hookup (vam); - - vec_free (name); - - return 0; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/l2_node.c b/plugins/flowperpkt-plugin/flowperpkt/l2_node.c deleted file mode 100644 index 1c2f681e1e1..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/l2_node.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * l2_node.c - l2 ipfix-per-packet graph node - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -/** - * @file l2 flow record generator graph node - */ - -typedef struct -{ - /** interface handle */ - u32 rx_sw_if_index; - u32 tx_sw_if_index; - /** src and dst L2 addresses */ - u8 src_mac[6]; - u8 dst_mac[6]; - /** Ethertype */ - u16 ethertype; - /** packet timestamp */ - u64 timestamp; - /** size of the buffer */ - u16 buffer_size; -} flowperpkt_l2_trace_t; - -/* packet trace format function */ -static u8 * -format_flowperpkt_l2_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - flowperpkt_l2_trace_t *t = va_arg (*args, flowperpkt_l2_trace_t *); - - s = format (s, - "FLOWPERPKT-L2: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U ethertype %0x2, timestamp %lld, size %d", - t->rx_sw_if_index, t->tx_sw_if_index, - format_ethernet_address, &t->src_mac, - format_ethernet_address, &t->dst_mac, - t->ethertype, t->timestamp, t->buffer_size); - return s; -} - -vlib_node_registration_t flowperpkt_l2_node; - -/* No counters at the moment */ -#define foreach_flowperpkt_l2_error - -typedef enum -{ -#define _(sym,str) FLOWPERPKT_ERROR_##sym, - foreach_flowperpkt_l2_error -#undef _ - FLOWPERPKT_N_ERROR, -} flowperpkt_l2_error_t; - -static char *flowperpkt_l2_error_strings[] = { -#define _(sym,string) string, - foreach_flowperpkt_l2_error -#undef _ -}; - -typedef enum -{ - FLOWPERPKT_L2_NEXT_DROP, - FLOWPERPKT_L2_NEXT_IP4_LOOKUP, - FLOWPERPKT_L2_N_NEXT, -} flowperpkt_l2_next_t; - -/** - * @brief add an entry to the flow record under construction - * @param vm vlib_main_t * current worker thread main structure pointer - * @param fm flowperpkt_main_t * flow-per-packet main structure pointer - * @param sw_if_index u32 interface handle - * @param tos u8 ToS bits from the packet - * @param timestamp u64 timestamp, nanoseconds since 1/1/70 - * @param length u16 ip length of the packet - * @param do_flush int 1 = flush all cached records, 0 = construct a record - */ - -static inline void -add_to_flow_record_l2 (vlib_main_t * vm, - vlib_node_runtime_t * node, - flowperpkt_main_t * fm, - u32 rx_sw_if_index, u32 tx_sw_if_index, - u8 * src_mac, u8 * dst_mac, - u16 ethertype, u64 timestamp, u16 length, int do_flush) -{ - u32 my_cpu_number = vm->cpu_index; - flow_report_main_t *frm = &flow_report_main; - ip4_header_t *ip; - udp_header_t *udp; - ip4_ipfix_template_packet_t *tp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - vlib_frame_t *f; - vlib_buffer_t *b0; - u16 offset; - u32 bi0; - vlib_buffer_free_list_t *fl; - - /* Find or allocate a buffer */ - b0 = fm->l2_buffers_per_worker[my_cpu_number]; - - /* Need to allocate a buffer? */ - if (PREDICT_FALSE (b0 == 0)) - { - /* Nothing to flush */ - if (do_flush) - return; - - /* $$$$ drop counter? */ - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - return; - - /* Initialize the buffer */ - b0 = fm->l2_buffers_per_worker[my_cpu_number] = - vlib_get_buffer (vm, bi0); - fl = - vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - /* use the current buffer */ - bi0 = vlib_get_buffer_index (vm, b0); - offset = fm->l2_next_record_offset_per_worker[my_cpu_number]; - } - - /* Find or allocate a frame */ - f = fm->l2_frames_per_worker[my_cpu_number]; - if (PREDICT_FALSE (f == 0)) - { - u32 *to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - fm->l2_frames_per_worker[my_cpu_number] = f; - - /* Enqueue the buffer */ - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - /* Fresh packet, construct header */ - if (PREDICT_FALSE (offset == 0)) - { - flow_report_stream_t *stream; - - stream = &frm->streams[0]; - - b0->current_data = 0; - b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + - sizeof (*s); - b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; - - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; - udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->checksum = 0; - - /* FIXUP: message header export_time */ - h->export_time = (u32) - (((f64) frm->unix_time_0) + - (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); - h->export_time = clib_host_to_net_u32 (h->export_time); - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* FIXUP: message header sequence_number */ - h->sequence_number = stream->sequence_number++; - h->sequence_number = clib_host_to_net_u32 (h->sequence_number); - - offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); - } - - /* Add data, unless we're flushing stale data */ - if (PREDICT_TRUE (do_flush == 0)) - { - - /* Add data */ - /* Ingress interface */ - { - u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); - clib_memcpy (b0->data + offset, &ingress_interface, - sizeof (ingress_interface)); - offset += sizeof (ingress_interface); - } - /* Egress interface */ - { - u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); - clib_memcpy (b0->data + offset, &egress_interface, - sizeof (egress_interface)); - offset += sizeof (egress_interface); - } - /* src mac address */ - { - clib_memcpy (b0->data + offset, src_mac, 6); - offset += 6; - } - /* dst mac address */ - { - clib_memcpy (b0->data + offset, dst_mac, 6); - offset += 6; - } - - /* ethertype */ - b0->data[offset++] = ethertype >> 8; - b0->data[offset++] = ethertype & 0xFF; - - /* Timestamp */ - clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); - offset += sizeof (f64); - - /* pkt size */ - { - u16 pkt_size = clib_host_to_net_u16 (length); - clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); - offset += sizeof (pkt_size); - } - - b0->current_length += - /* 2*sw_if_index + 2*mac + ethertype + timestamp + length = 32 */ - 2 * sizeof (u32) + 12 + sizeof (u16) + sizeof (f64) + sizeof (u16); - - } - /* Time to flush the buffer? */ - if (PREDICT_FALSE - (do_flush || (offset + 2 * sizeof (u32) + 12 + sizeof (u16) + - +sizeof (f64) + sizeof (u16)) > frm->path_mtu)) - { - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - s->set_id_length = ipfix_set_id_length (fm->l2_report_id, - b0->current_length - - (sizeof (*ip) + sizeof (*udp) + - sizeof (*h))); - h->version_length = version_length (b0->current_length - - (sizeof (*ip) + sizeof (*udp))); - - ip->length = clib_host_to_net_u16 (b0->current_length); - - ip->checksum = ip4_header_checksum (ip); - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - - if (frm->udp_checksum) - { - /* RFC 7011 section 10.3.2. */ - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); - if (udp->checksum == 0) - udp->checksum = 0xffff; - } - - ASSERT (ip->checksum == ip4_header_checksum (ip)); - - if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) - { - vlib_trace_buffer (vm, node, FLOWPERPKT_L2_NEXT_IP4_LOOKUP, b0, - 0 /* follow chain */ ); - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - memset (t, 0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->buffer_size = b0->current_length; - } - - vlib_put_frame_to_node (vm, ip4_lookup_node.index, - fm->l2_frames_per_worker[my_cpu_number]); - fm->l2_frames_per_worker[my_cpu_number] = 0; - fm->l2_buffers_per_worker[my_cpu_number] = 0; - offset = 0; - } - - fm->l2_next_record_offset_per_worker[my_cpu_number] = offset; -} - -void -flowperpkt_flush_callback_l2 (void) -{ - vlib_main_t *vm = vlib_get_main (); - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_node_runtime_t *node; - node = vlib_node_get_runtime (vm, flowperpkt_l2_node.index); - - add_to_flow_record_l2 (vm, node, fm, 0 /* rx_sw_if_index */ , - 0 /* tx_sw_if_index */ , - 0 /* src mac */ , - 0 /* dst mac */ , - 0 /* ethertype */ , - 0ULL /* timestamp */ , - 0 /* length */ , - 1 /* do_flush */ ); -} - - -static uword -flowperpkt_l2_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - flowperpkt_l2_next_t next_index; - flowperpkt_main_t *fm = &flowperpkt_main; - u64 now; - - now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); - now += fm->nanosecond_time_0; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = FLOWPERPKT_L2_NEXT_DROP; - u32 next1 = FLOWPERPKT_L2_NEXT_DROP; - ethernet_header_t *eh0, *eh1; - u16 len0, len1; - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], - &next1, b1); - - eh0 = vlib_buffer_get_current (b0); - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - eh0->src_address, - eh0->dst_address, - eh0->type, now, len0, 0 /* flush */ ); - - eh1 = vlib_buffer_get_current (b0); - len1 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b1)->sw_if_index[VLIB_RX], - vnet_buffer (b1)->sw_if_index[VLIB_TX], - eh1->src_address, - eh1->dst_address, - eh1->type, now, len1, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh0->src_address, 6); - clib_memcpy (t->dst_mac, eh0->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh0->type); - t->timestamp = now; - t->buffer_size = len0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh1->src_address, 6); - clib_memcpy (t->dst_mac, eh1->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh1->type); - t->timestamp = now; - t->buffer_size = len1; - } - } - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = FLOWPERPKT_L2_NEXT_DROP; - ethernet_header_t *eh0; - u16 len0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - - eh0 = vlib_buffer_get_current (b0); - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_l2 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - eh0->src_address, - eh0->dst_address, - eh0->type, now, len0, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - flowperpkt_l2_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - clib_memcpy (t->src_mac, eh0->src_address, 6); - clib_memcpy (t->dst_mac, eh0->dst_address, 6); - t->ethertype = clib_net_to_host_u16 (eh0->type); - t->timestamp = now; - t->buffer_size = len0; - } - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - return frame->n_vectors; -} - -/** - * @brief IPFIX l2 flow-per-packet graph node - * @node flowperpkt-l2 - * - * This is the IPFIX flow-record-per-packet node. - * - * @param vm vlib_main_t corresponding to the current thread. - * @param node vlib_node_runtime_t data for this node. - * @param frame vlib_frame_t whose contents should be dispatched. - * - * @par Graph mechanics: buffer metadata, next index usage - * - * Uses: - * - vnet_buffer(b)->ip.save_rewrite_length - * - tells the node the length of the rewrite which was applied in - * ip4/6_rewrite_inline, allows the code to find the IP header without - * having to parse L2 headers, or make stupid assumptions about their - * length. - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - Used to suppress flow record generation for flow record packets. - * - * Sets: - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - To suppress flow record generation for flow record packets - * - * Next Index: - * - Next configured output feature on the interface, usually - * "interface-output." Generated flow records head for ip4-lookup - */ - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (flowperpkt_l2_node) = { - .function = flowperpkt_l2_node_fn, - .name = "flowperpkt-l2", - .vector_size = sizeof (u32), - .format_trace = format_flowperpkt_l2_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(flowperpkt_l2_error_strings), - .error_strings = flowperpkt_l2_error_strings, - - .n_next_nodes = FLOWPERPKT_L2_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [FLOWPERPKT_L2_NEXT_DROP] = "error-drop", - [FLOWPERPKT_L2_NEXT_IP4_LOOKUP] = "ip4-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt/node.c b/plugins/flowperpkt-plugin/flowperpkt/node.c deleted file mode 100644 index f77f087dc78..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt/node.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * node.c - ipv4 ipfix-per-packet graph node - * - * Copyright (c) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include - -/** - * @file ipv4 flow record generator graph node - */ - -typedef struct -{ - /** interface handle */ - u32 rx_sw_if_index; - u32 tx_sw_if_index; - u32 src_address; - u32 dst_address; - /** ToS bits */ - u8 tos; - /** packet timestamp */ - u64 timestamp; - /** size of the buffer */ - u16 buffer_size; -} flowperpkt_ipv4_trace_t; - -/* packet trace format function */ -static u8 * -format_flowperpkt_ipv4_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - flowperpkt_ipv4_trace_t *t = va_arg (*args, flowperpkt_ipv4_trace_t *); - - s = format (s, - "FLOWPERPKT-V4: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U tos %0x2, timestamp %lld, size %d", - t->rx_sw_if_index, t->tx_sw_if_index, - format_ip4_address, &t->src_address, - format_ip4_address, &t->dst_address, - t->tos, t->timestamp, t->buffer_size); - return s; -} - -vlib_node_registration_t flowperpkt_ipv4_node; - -/* No counters at the moment */ -#define foreach_flowperpkt_ipv4_error - -typedef enum -{ -#define _(sym,str) FLOWPERPKT_ERROR_##sym, - foreach_flowperpkt_ipv4_error -#undef _ - FLOWPERPKT_N_ERROR, -} flowperpkt_ipv4_error_t; - -static char *flowperpkt_ipv4_error_strings[] = { -#define _(sym,string) string, - foreach_flowperpkt_ipv4_error -#undef _ -}; - -typedef enum -{ - FLOWPERPKT_IPV4_NEXT_DROP, - FLOWPERPKT_IPV4_NEXT_LOOKUP, - FLOWPERPKT_IPV4_N_NEXT, -} flowperpkt_ipv4_next_t; - -/** - * @brief add an entry to the flow record under construction - * @param vm vlib_main_t * current worker thread main structure pointer - * @param fm flowperpkt_main_t * flow-per-packet main structure pointer - * @param sw_if_index u32 interface handle - * @param tos u8 ToS bits from the packet - * @param timestamp u64 timestamp, nanoseconds since 1/1/70 - * @param length u16 ip length of the packet - * @param do_flush int 1 = flush all cached records, 0 = construct a record - */ - -static inline void -add_to_flow_record_ipv4 (vlib_main_t * vm, - vlib_node_runtime_t * node, - flowperpkt_main_t * fm, - u32 rx_sw_if_index, u32 tx_sw_if_index, - u32 src_address, u32 dst_address, - u8 tos, u64 timestamp, u16 length, int do_flush) -{ - u32 my_cpu_number = vm->cpu_index; - flow_report_main_t *frm = &flow_report_main; - ip4_header_t *ip; - udp_header_t *udp; - ip4_ipfix_template_packet_t *tp; - ipfix_message_header_t *h; - ipfix_set_header_t *s; - vlib_frame_t *f; - vlib_buffer_t *b0; - u16 offset; - u32 bi0; - vlib_buffer_free_list_t *fl; - - /* Find or allocate a buffer */ - b0 = fm->ipv4_buffers_per_worker[my_cpu_number]; - - /* Need to allocate a buffer? */ - if (PREDICT_FALSE (b0 == 0)) - { - /* Nothing to flush */ - if (do_flush) - return; - - /* $$$$ drop counter? */ - if (vlib_buffer_alloc (vm, &bi0, 1) != 1) - return; - - /* Initialize the buffer */ - b0 = fm->ipv4_buffers_per_worker[my_cpu_number] = - vlib_get_buffer (vm, bi0); - fl = - vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); - vlib_buffer_init_for_free_list (b0, fl); - VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); - offset = 0; - } - else - { - /* use the current buffer */ - bi0 = vlib_get_buffer_index (vm, b0); - offset = fm->ipv4_next_record_offset_per_worker[my_cpu_number]; - } - - /* Find or allocate a frame */ - f = fm->ipv4_frames_per_worker[my_cpu_number]; - if (PREDICT_FALSE (f == 0)) - { - u32 *to_next; - f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); - fm->ipv4_frames_per_worker[my_cpu_number] = f; - - /* Enqueue the buffer */ - to_next = vlib_frame_vector_args (f); - to_next[0] = bi0; - f->n_vectors = 1; - } - - /* Fresh packet, construct header */ - if (PREDICT_FALSE (offset == 0)) - { - flow_report_stream_t *stream; - - stream = &frm->streams[0]; - - b0->current_data = 0; - b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + - sizeof (*s); - b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); - vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; - - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - ip->ip_version_and_header_length = 0x45; - ip->ttl = 254; - ip->protocol = IP_PROTOCOL_UDP; - ip->flags_and_fragment_offset = 0; - ip->src_address.as_u32 = frm->src_address.as_u32; - ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; - udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); - udp->checksum = 0; - - /* FIXUP: message header export_time */ - h->export_time = (u32) - (((f64) frm->unix_time_0) + - (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); - h->export_time = clib_host_to_net_u32 (h->export_time); - h->domain_id = clib_host_to_net_u32 (stream->domain_id); - - /* FIXUP: message header sequence_number */ - h->sequence_number = stream->sequence_number++; - h->sequence_number = clib_host_to_net_u32 (h->sequence_number); - - offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); - } - - /* Add data, unless we're flushing stale data */ - if (PREDICT_TRUE (do_flush == 0)) - { - - /* Add data */ - /* Ingress interface */ - { - u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); - clib_memcpy (b0->data + offset, &ingress_interface, - sizeof (ingress_interface)); - offset += sizeof (ingress_interface); - } - /* Egress interface */ - { - u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); - clib_memcpy (b0->data + offset, &egress_interface, - sizeof (egress_interface)); - offset += sizeof (egress_interface); - } - /* ip4 src address */ - { - clib_memcpy (b0->data + offset, &src_address, sizeof (src_address)); - offset += sizeof (src_address); - } - /* ip4 dst address */ - { - clib_memcpy (b0->data + offset, &dst_address, sizeof (dst_address)); - offset += sizeof (dst_address); - } - - /* ToS */ - b0->data[offset++] = tos; - - /* Timestamp */ - clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); - offset += sizeof (f64); - - /* pkt size */ - { - u16 pkt_size = clib_host_to_net_u16 (length); - clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); - offset += sizeof (pkt_size); - } - - b0->current_length += - /* sw_if_index + tos + timestamp + length = 15 */ - 4 * sizeof (u32) + sizeof (u8) + sizeof (f64) + sizeof (u16); - - } - /* Time to flush the buffer? */ - if (PREDICT_FALSE - (do_flush || (offset + 4 * sizeof (u32) + sizeof (u8) - + sizeof (f64) + sizeof (u16)) > frm->path_mtu)) - { - tp = vlib_buffer_get_current (b0); - ip = (ip4_header_t *) & tp->ip4; - udp = (udp_header_t *) (ip + 1); - h = (ipfix_message_header_t *) (udp + 1); - s = (ipfix_set_header_t *) (h + 1); - - s->set_id_length = ipfix_set_id_length (fm->ipv4_report_id, - b0->current_length - - (sizeof (*ip) + sizeof (*udp) + - sizeof (*h))); - h->version_length = version_length (b0->current_length - - (sizeof (*ip) + sizeof (*udp))); - - ip->length = clib_host_to_net_u16 (b0->current_length); - - ip->checksum = ip4_header_checksum (ip); - udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); - - if (frm->udp_checksum) - { - /* RFC 7011 section 10.3.2. */ - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); - if (udp->checksum == 0) - udp->checksum = 0xffff; - } - - ASSERT (ip->checksum == ip4_header_checksum (ip)); - - if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) - { - vlib_trace_buffer (vm, node, FLOWPERPKT_IPV4_NEXT_LOOKUP, b0, - 0 /* follow chain */ ); - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = 0; - t->dst_address = 0; - t->tos = 0; - t->timestamp = 0; - t->buffer_size = b0->current_length; - } - - vlib_put_frame_to_node (vm, ip4_lookup_node.index, - fm->ipv4_frames_per_worker[my_cpu_number]); - fm->ipv4_frames_per_worker[my_cpu_number] = 0; - fm->ipv4_buffers_per_worker[my_cpu_number] = 0; - offset = 0; - } - - fm->ipv4_next_record_offset_per_worker[my_cpu_number] = offset; -} - -void -flowperpkt_flush_callback_ipv4 (void) -{ - vlib_main_t *vm = vlib_get_main (); - flowperpkt_main_t *fm = &flowperpkt_main; - vlib_node_runtime_t *node; - node = vlib_node_get_runtime (vm, flowperpkt_ipv4_node.index); - - add_to_flow_record_ipv4 (vm, node, fm, 0 /* rx_sw_if_index */ , - 0 /* tx_sw_if_index */ , - 0 /* src_address */ , - 0 /* dst_address */ , - 0 /* ToS */ , - 0ULL /* timestamp */ , - 0 /* length */ , - 1 /* do_flush */ ); -} - - -static uword -flowperpkt_ipv4_node_fn (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, *to_next; - flowperpkt_ipv4_next_t next_index; - flowperpkt_main_t *fm = &flowperpkt_main; - u64 now; - - now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); - now += fm->nanosecond_time_0; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - u32 n_left_to_next; - - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 next0 = FLOWPERPKT_IPV4_NEXT_DROP; - u32 next1 = FLOWPERPKT_IPV4_NEXT_DROP; - ip4_header_t *ip0, *ip1; - u16 len0, len1; - u32 bi0, bi1; - vlib_buffer_t *b0, *b1; - - /* Prefetch next iteration. */ - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - - CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); - CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); - } - - /* speculatively enqueue b0 and b1 to the current next frame */ - to_next[0] = bi0 = from[0]; - to_next[1] = bi1 = from[1]; - from += 2; - to_next += 2; - n_left_from -= 2; - n_left_to_next -= 2; - - b0 = vlib_get_buffer (vm, bi0); - b1 = vlib_get_buffer (vm, bi1); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], - &next1, b1); - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - vnet_buffer (b0)->ip.save_rewrite_length); - - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - ip0->src_address.as_u32, - ip0->dst_address.as_u32, - ip0->tos, now, len0, 0 /* flush */ ); - - ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) + - vnet_buffer (b1)->ip.save_rewrite_length); - len1 = vlib_buffer_length_in_chain (vm, b1); - - if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b1)->sw_if_index[VLIB_RX], - vnet_buffer (b1)->sw_if_index[VLIB_TX], - ip1->src_address.as_u32, - ip1->dst_address.as_u32, - ip1->tos, now, len1, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) - { - if (b0->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = ip0->src_address.as_u32; - t->dst_address = ip0->dst_address.as_u32; - t->tos = ip0->tos; - t->timestamp = now; - t->buffer_size = len0; - } - if (b1->flags & VLIB_BUFFER_IS_TRACED) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b1, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; - t->src_address = ip1->src_address.as_u32; - t->dst_address = ip1->dst_address.as_u32; - t->tos = ip1->tos; - t->timestamp = now; - t->buffer_size = len1; - } - } - - /* verify speculative enqueues, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, - to_next, n_left_to_next, - bi0, bi1, next0, next1); - } - - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 bi0; - vlib_buffer_t *b0; - u32 next0 = FLOWPERPKT_IPV4_NEXT_DROP; - ip4_header_t *ip0; - u16 len0; - - /* speculatively enqueue b0 to the current next frame */ - bi0 = from[0]; - to_next[0] = bi0; - from += 1; - to_next += 1; - n_left_from -= 1; - n_left_to_next -= 1; - - b0 = vlib_get_buffer (vm, bi0); - - vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], - &next0, b0); - - ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + - vnet_buffer (b0)->ip.save_rewrite_length); - /* - * egressInterface, TLV type 14, u32 - * ipClassOfService, TLV type 5, u8 - * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) - * Implementation: f64 nanoseconds since VPP started - * dataLinkFrameSize, TLV type 312, u16 - */ - len0 = vlib_buffer_length_in_chain (vm, b0); - - if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) - add_to_flow_record_ipv4 (vm, node, fm, - vnet_buffer (b0)->sw_if_index[VLIB_RX], - vnet_buffer (b0)->sw_if_index[VLIB_TX], - ip0->src_address.as_u32, - ip0->dst_address.as_u32, - ip0->tos, now, len0, 0 /* flush */ ); - - if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) - && (b0->flags & VLIB_BUFFER_IS_TRACED))) - { - flowperpkt_ipv4_trace_t *t = - vlib_add_trace (vm, node, b0, sizeof (*t)); - t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; - t->src_address = ip0->src_address.as_u32; - t->dst_address = ip0->dst_address.as_u32; - t->tos = ip0->tos; - t->timestamp = now; - t->buffer_size = len0; - } - - /* verify speculative enqueue, maybe switch current next frame */ - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, n_left_to_next, - bi0, next0); - } - - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - return frame->n_vectors; -} - -/** - * @brief IPFIX ipv4 flow-per-packet graph node - * @node flowperpkt-ipv4 - * - * This is the IPFIX flow-record-per-packet node. - * - * @param vm vlib_main_t corresponding to the current thread. - * @param node vlib_node_runtime_t data for this node. - * @param frame vlib_frame_t whose contents should be dispatched. - * - * @par Graph mechanics: buffer metadata, next index usage - * - * Uses: - * - vnet_buffer(b)->ip.save_rewrite_length - * - tells the node the length of the rewrite which was applied in - * ip4/6_rewrite_inline, allows the code to find the IP header without - * having to parse L2 headers, or make stupid assumptions about their - * length. - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - Used to suppress flow record generation for flow record packets. - * - * Sets: - * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT - * - To suppress flow record generation for flow record packets - * - * Next Index: - * - Next configured output feature on the interface, usually - * "interface-output." Generated flow records head for ip4-lookup - */ - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (flowperpkt_ipv4_node) = { - .function = flowperpkt_ipv4_node_fn, - .name = "flowperpkt-ipv4", - .vector_size = sizeof (u32), - .format_trace = format_flowperpkt_ipv4_trace, - .type = VLIB_NODE_TYPE_INTERNAL, - - .n_errors = ARRAY_LEN(flowperpkt_ipv4_error_strings), - .error_strings = flowperpkt_ipv4_error_strings, - - .n_next_nodes = FLOWPERPKT_IPV4_N_NEXT, - - /* edit / add dispositions here */ - .next_nodes = { - [FLOWPERPKT_IPV4_NEXT_DROP] = "error-drop", - /* Used only to trace ipfix data packets */ - [FLOWPERPKT_IPV4_NEXT_LOOKUP] = "ip4-lookup", - }, -}; -/* *INDENT-ON* */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md b/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md deleted file mode 100644 index ed76c45c2dc..00000000000 --- a/plugins/flowperpkt-plugin/flowperpkt_plugin_doc.md +++ /dev/null @@ -1,13 +0,0 @@ -Per-packet IPFIX flow record plugin {#flowperpkt_plugin_doc} -=================================== - -## Introduction - -This plugin generates one ipfix record entry per packet transmitted -on interfaces which have the feature enabled - -## Sample configuration - -set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1500 - -flowperpkt feature add-del GigabitEthernet2/3/0 diff --git a/plugins/ila-plugin/Makefile.am b/plugins/ila-plugin/Makefile.am deleted file mode 100644 index fe785df9bc3..00000000000 --- a/plugins/ila-plugin/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2016 Cisco Systems, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = ila_plugin.la - -ila_plugin_la_SOURCES = ila/ila.c - -noinst_HEADERS = ila/ila.h - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) diff --git a/plugins/ila-plugin/configure.ac b/plugins/ila-plugin/configure.ac deleted file mode 100644 index 56016b4d22d..00000000000 --- a/plugins/ila-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(ila_plugin, 1.0) -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_LIBTOOL -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/ila-plugin/ila/ila.c b/plugins/ila-plugin/ila/ila.c deleted file mode 100644 index 336f4cf560c..00000000000 --- a/plugins/ila-plugin/ila/ila.c +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include - -static ila_main_t ila_main; - -#define ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) -#define ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE (32<<20) - -#define foreach_ila_error \ - _(NONE, "valid ILA packets") - -typedef enum { -#define _(sym,str) ILA_ERROR_##sym, - foreach_ila_error -#undef _ - ILA_N_ERROR, -} ila_error_t; - -static char *ila_error_strings[] = { -#define _(sym,string) string, - foreach_ila_error -#undef _ -}; - -typedef enum { - ILA_ILA2SIR_NEXT_DROP, - ILA_ILA2SIR_N_NEXT, -} ila_ila2sir_next_t; - -typedef struct { - u32 ila_index; - ip6_address_t initial_dst; - u32 adj_index; -} ila_ila2sir_trace_t; - -static ila_entry_t ila_sir2ila_default_entry = { - .csum_mode = ILA_CSUM_MODE_NO_ACTION, - .type = ILA_TYPE_IID, - .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no -}; - -/** - * @brief Dynamically registered DPO Type for ILA - */ -static dpo_type_t ila_dpo_type; - -/** - * @brief Dynamically registered FIB node type for ILA - */ -static fib_node_type_t ila_fib_node_type; - -u8 * -format_half_ip6_address (u8 * s, va_list * va) -{ - u64 v = clib_net_to_host_u64 (va_arg (*va, u64)); - - return format (s, "%04x:%04x:%04x:%04x", - v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff); - -} - -u8 * -format_ila_direction (u8 * s, va_list * args) -{ - ila_direction_t t = va_arg (*args, ila_direction_t); -#define _(i,n,st) \ - if (t == ILA_DIR_##i) \ - return format(s, st); - ila_foreach_direction -#undef _ - return format (s, "invalid_ila_direction"); -} - -static u8 * -format_csum_mode (u8 * s, va_list * va) -{ - ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t); - char *txt; - - switch (csum_mode) - { -#define _(i,n,st) \ - case ILA_CSUM_MODE_##i: \ - txt = st; \ - break; - ila_csum_foreach_type -#undef _ - default: - txt = "invalid_ila_csum_mode"; - break; - } - return format (s, txt); -} - -u8 * -format_ila_type (u8 * s, va_list * args) -{ - ila_type_t t = va_arg (*args, ila_type_t); -#define _(i,n,st) \ - if (t == ILA_TYPE_##i) \ - return format(s, st); - ila_foreach_type -#undef _ - return format (s, "invalid_ila_type"); -} - -static u8 * -format_ila_entry (u8 * s, va_list * va) -{ - vnet_main_t *vnm = va_arg (*va, vnet_main_t *); - ila_entry_t *e = va_arg (*va, ila_entry_t *); - - if (!e) - { - return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", - "ILA Address", "Checksum Mode", "Direction", "Next DPO"); - } - else if (vnm) - { - if (ip6_address_is_zero(&e->next_hop)) - { - return format (s, "%-15U%=40U%=40U%18U%11U%s", - format_ila_type, e->type, - format_ip6_address, &e->sir_address, - format_ip6_address, &e->ila_address, - format_csum_mode, e->csum_mode, - format_ila_direction, e->dir, - "n/a"); - } - else - { - return format (s, "%-15U%=40U%=40U%18U%11U%U", - format_ila_type, e->type, - format_ip6_address, &e->sir_address, - format_ip6_address, &e->ila_address, - format_csum_mode, e->csum_mode, - format_ila_direction, e->dir, - format_dpo_id, &e->ila_dpo, 0); - } - } - - return NULL; -} - -u8 * -format_ila_ila2sir_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *); - return format (s, - "ILA -> SIR adj index: %d entry index: %d initial_dst: %U", - t->adj_index, t->ila_index, format_ip6_address, - &t->initial_dst); -} - -static uword -unformat_ila_direction (unformat_input_t * input, va_list * args) -{ - ila_direction_t *result = va_arg (*args, ila_direction_t *); -#define _(i,n,s) \ - if (unformat(input, s)) \ - { \ - *result = ILA_DIR_##i; \ - return 1;\ - } - - ila_foreach_direction -#undef _ - return 0; -} - -static uword -unformat_ila_type (unformat_input_t * input, va_list * args) -{ - ila_type_t *result = va_arg (*args, ila_type_t *); -#define _(i,n,s) \ - if (unformat(input, s)) \ - { \ - *result = ILA_TYPE_##i; \ - return 1;\ - } - - ila_foreach_type -#undef _ - return 0; -} - -static uword -unformat_ila_csum_mode (unformat_input_t * input, va_list * args) -{ - ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *); - if (unformat (input, "none") || unformat (input, "no-action")) - { - *result = ILA_CSUM_MODE_NO_ACTION; - return 1; - } - if (unformat (input, "neutral-map")) - { - *result = ILA_CSUM_MODE_NEUTRAL_MAP; - return 1; - } - if (unformat (input, "adjust-transport")) - { - *result = ILA_CSUM_MODE_ADJUST_TRANSPORT; - return 1; - } - return 0; -} - -static uword -unformat_half_ip6_address (unformat_input_t * input, va_list * args) -{ - u64 *result = va_arg (*args, u64 *); - u32 a[4]; - - if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3])) - return 0; - - if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF) - return 0; - - *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) | - (((u64) a[1]) << 32) | - (((u64) a[2]) << 16) | (((u64) a[3]))); - - return 1; -} - -static vlib_node_registration_t ila_ila2sir_node; - -static uword -ila_ila2sir (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - ila_main_t *ilm = &ila_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 pi0, pi1; - vlib_buffer_t *p0, *p1; - ila_entry_t *ie0, *ie1; - ip6_header_t *ip60, *ip61; - ip6_address_t *sir_address0, *sir_address1; - - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); - CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); - } - - pi0 = to_next[0] = from[0]; - pi1 = to_next[1] = from[1]; - from += 2; - n_left_from -= 2; - to_next += 2; - n_left_to_next -= 2; - - p0 = vlib_get_buffer (vm, pi0); - p1 = vlib_get_buffer (vm, pi1); - ip60 = vlib_buffer_get_current (p0); - ip61 = vlib_buffer_get_current (p1); - sir_address0 = &ip60->dst_address; - sir_address1 = &ip61->dst_address; - ie0 = pool_elt_at_index (ilm->entries, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - ie1 = pool_elt_at_index (ilm->entries, - vnet_buffer (p1)->ip.adj_index[VLIB_TX]); - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = ie0 - ilm->entries; - tr->initial_dst = ip60->dst_address; - tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; - } - - if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p1, sizeof (*tr)); - tr->ila_index = ie1 - ilm->entries; - tr->initial_dst = ip61->dst_address; - tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; - } - - sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; - sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1; - ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; - ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; - ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; - - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; - vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, pi0, pi1, - ie0->ila_dpo.dpoi_next_node, - ie1->ila_dpo.dpoi_next_node); - } - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 pi0; - vlib_buffer_t *p0; - ila_entry_t *ie0; - ip6_header_t *ip60; - ip6_address_t *sir_address0; - - pi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next += 1; - n_left_to_next -= 1; - - p0 = vlib_get_buffer (vm, pi0); - ip60 = vlib_buffer_get_current (p0); - sir_address0 = &ip60->dst_address; - ie0 = pool_elt_at_index (ilm->entries, - vnet_buffer (p0)->ip.adj_index[VLIB_TX]); - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_ila2sir_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; - } - - sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; - ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; - vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, pi0, - ie0->ila_dpo.dpoi_next_node); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/** *INDENT-OFF* */ -VLIB_REGISTER_NODE (ila_ila2sir_node, static) = -{ - .function = ila_ila2sir, - .name = "ila-to-sir", - .vector_size = sizeof (u32), - .format_trace = format_ila_ila2sir_trace, - .n_errors = ILA_N_ERROR, - .error_strings = ila_error_strings, - .n_next_nodes = ILA_ILA2SIR_N_NEXT, - .next_nodes = - { - [ILA_ILA2SIR_NEXT_DROP] = "error-drop" - }, -}; -/** *INDENT-ON* */ - -typedef enum -{ - ILA_SIR2ILA_NEXT_DROP, - ILA_SIR2ILA_N_NEXT, -} ila_sir2ila_next_t; - -typedef struct -{ - u32 ila_index; - ip6_address_t initial_dst; -} ila_sir2ila_trace_t; - -u8 * -format_ila_sir2ila_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *); - - return format (s, "SIR -> ILA entry index: %d initial_dst: %U", - t->ila_index, format_ip6_address, &t->initial_dst); -} - -static vlib_node_registration_t ila_sir2ila_node; - -static uword -ila_sir2ila (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - ila_main_t *ilm = &ila_main; - - from = vlib_frame_vector_args (frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) - { - vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from >= 4 && n_left_to_next >= 2) - { - u32 pi0, pi1; - vlib_buffer_t *p0, *p1; - ip6_header_t *ip60, *ip61; - u32 next0 = ILA_SIR2ILA_NEXT_DROP; - u32 next1 = ILA_SIR2ILA_NEXT_DROP; - BVT (clib_bihash_kv) kv0, value0; - BVT (clib_bihash_kv) kv1, value1; - ila_entry_t *ie0 = &ila_sir2ila_default_entry; - ila_entry_t *ie1 = &ila_sir2ila_default_entry; - ip6_address_t *ila_address0, *ila_address1; - - { - vlib_buffer_t *p2, *p3; - - p2 = vlib_get_buffer (vm, from[2]); - p3 = vlib_get_buffer (vm, from[3]); - - vlib_prefetch_buffer_header (p2, LOAD); - vlib_prefetch_buffer_header (p3, LOAD); - CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); - CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); - } - - pi0 = to_next[0] = from[0]; - pi1 = to_next[1] = from[1]; - from += 2; - n_left_from -= 2; - to_next += 2; - n_left_to_next -= 2; - - p0 = vlib_get_buffer (vm, pi0); - p1 = vlib_get_buffer (vm, pi1); - ip60 = vlib_buffer_get_current (p0); - ip61 = vlib_buffer_get_current (p1); - ila_address0 = &ip60->dst_address; - ila_address1 = &ip61->dst_address; - kv0.key[0] = ip60->dst_address.as_u64[0]; - kv0.key[1] = ip60->dst_address.as_u64[1]; - kv0.key[2] = 0; - kv1.key[0] = ip61->dst_address.as_u64[0]; - kv1.key[1] = ip61->dst_address.as_u64[1]; - kv1.key[2] = 0; - - if (PREDICT_TRUE((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { - ie0 = &ilm->entries[value0.value]; - ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; - } - - if ((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv1, &value1)) == 0) { - ie1 = &ilm->entries[value1.value]; - ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1; - } - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = - (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - } - - if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p1, sizeof (*tr)); - tr->ila_index = - (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0; - tr->initial_dst = ip61->dst_address; - } - - ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; - ip61->dst_address.as_u64[0] = ila_address1->as_u64[0]; - ip61->dst_address.as_u64[1] = ila_address1->as_u64[1]; - - vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); - vnet_feature_next (vnet_buffer (p1)->sw_if_index[VLIB_RX], &next1, p1); - - vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, - n_left_to_next, pi0, pi1, next0, - next1); - } - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) - { - u32 pi0; - vlib_buffer_t *p0; - ip6_header_t *ip60; - u32 next0 = ILA_SIR2ILA_NEXT_DROP; - BVT (clib_bihash_kv) kv0, value0; - ila_entry_t *ie0 = &ila_sir2ila_default_entry; - ip6_address_t *ila_address0; - - pi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next += 1; - n_left_to_next -= 1; - - p0 = vlib_get_buffer (vm, pi0); - ip60 = vlib_buffer_get_current (p0); - ila_address0 = &ip60->dst_address; - - kv0.key[0] = ip60->dst_address.as_u64[0]; - kv0.key[1] = ip60->dst_address.as_u64[1]; - kv0.key[2] = 0; - - if (PREDICT_TRUE((BV (clib_bihash_search) - (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { - ie0 = &ilm->entries[value0.value]; - ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; - } - - if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) - { - ila_sir2ila_trace_t *tr = - vlib_add_trace (vm, node, p0, sizeof (*tr)); - tr->ila_index = - (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; - tr->initial_dst = ip60->dst_address; - } - - //This operation should do everything for any type (except vnid4 obviously) - ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; - ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; - - vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); - - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, - n_left_to_next, pi0, next0); - } - vlib_put_next_frame (vm, node, next_index, n_left_to_next); - } - - return frame->n_vectors; -} - -/** *INDENT-OFF* */ -VLIB_REGISTER_NODE (ila_sir2ila_node, static) = -{ - .function = ila_sir2ila,.name = "sir-to-ila", - .vector_size = sizeof (u32), - .format_trace = format_ila_sir2ila_trace, - .n_errors = ILA_N_ERROR, - .error_strings = ila_error_strings, - .n_next_nodes = ILA_SIR2ILA_N_NEXT, - .next_nodes = - { - [ILA_SIR2ILA_NEXT_DROP] = "error-drop" - }, -}; -/** *INDENT-ON* */ - -/** *INDENT-OFF* */ -VNET_FEATURE_INIT (ila_sir2ila, static) = -{ - .arc_name = "ip6-unicast", - .node_name = "sir-to-ila", - .runs_before = VNET_FEATURES ("ip6-lookup"), -}; -/** *INDENT-ON* */ - -static void -ila_entry_stack (ila_entry_t *ie) -{ - /* - * restack on the next-hop's FIB entry - */ - dpo_stack(ila_dpo_type, - DPO_PROTO_IP6, - &ie->ila_dpo, - fib_entry_contribute_ip_forwarding( - ie->next_hop_fib_entry_index)); -} - -int -ila_add_del_entry (ila_add_del_entry_args_t * args) -{ - ila_main_t *ilm = &ila_main; - BVT (clib_bihash_kv) kv, value; - - //Sanity check - if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID) - { - if ((args->sir_address.as_u8[8] >> 5) != args->type) - { - clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)", - args->sir_address.as_u8[8] >> 1, args->type); - return -1; - } - if (args->sir_address.as_u8[8] & 0x10) - { - clib_warning ("Checksum bit should not be set in SIR address"); - return -1; - } - } - else if (args->type == ILA_TYPE_VNIDM) - { - if (args->sir_address.as_u8[0] != 0xff || - (args->sir_address.as_u8[1] & 0xf0) != 0xf0) - { - clib_warning ("SIR multicast address must start with fff"); - return -1; - } - if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] || - args->sir_address.as_u16[3] || args->sir_address.as_u16[4] || - args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0)) - { - clib_warning ("SIR multicast address must start with fff"); - return -1; - } - } - - if (!args->is_del) - { - ila_entry_t *e; - pool_get (ilm->entries, e); - e->type = args->type; - e->sir_address = args->sir_address; - e->next_hop = args->next_hop_address; - e->csum_mode = args->csum_mode; - e->dir = args->dir; - - //Construct ILA address - switch (e->type) - { - case ILA_TYPE_IID: - e->ila_address = e->sir_address; - break; - case ILA_TYPE_LUID: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u64[1] = args->sir_address.as_u64[1]; - break; - case ILA_TYPE_VNID6: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1); - e->ila_address.as_u32[2] |= args->vnid; - e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; - break; - case ILA_TYPE_VNIDM: - e->ila_address.as_u64[0] = args->locator; - e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1); - e->ila_address.as_u32[2] |= args->vnid; - e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; - e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4; - break; - case ILA_TYPE_VNID4: - clib_warning ("ILA type '%U' is not supported", format_ila_type, - e->type); - return -1; - } - - //Modify ILA checksum if necessary - if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP) - { - ip_csum_t csum = e->ila_address.as_u16[7]; - int i; - for (i = 0; i < 4; i++) - { - csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]); - csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]); - } - csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000)); - e->ila_address.as_u16[7] = ip_csum_fold (csum); - e->ila_address.as_u8[8] |= 0x10; - } - - //Create entry with the sir address - kv.key[0] = e->sir_address.as_u64[0]; - kv.key[1] = e->sir_address.as_u64[1]; - kv.key[2] = 0; - kv.value = e - ilm->entries; - BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, - 1 /* is_add */ ); - - if (!ip6_address_is_zero(&e->next_hop)) - { - /* - * become a child of the FIB netry for the next-hop - * so we are informed when its forwarding changes - */ - fib_prefix_t next_hop = { - .fp_addr = { - .ip6 = e->next_hop, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - e->next_hop_fib_entry_index = - fib_table_entry_special_add(0, - &next_hop, - FIB_SOURCE_RR, - FIB_ENTRY_FLAG_NONE, - ADJ_INDEX_INVALID); - e->next_hop_child_index = - fib_entry_child_add(e->next_hop_fib_entry_index, - ila_fib_node_type, - e - ilm->entries); - - /* - * Create a route that results in the ILA entry - */ - dpo_id_t dpo = DPO_INVALID; - fib_prefix_t pfx = { - .fp_addr = { - .ip6 = e->ila_address, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); - - fib_table_entry_special_dpo_add(0, - &pfx, - FIB_SOURCE_PLUGIN_HI, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo); - dpo_reset(&dpo); - - /* - * finally stack the ILA entry so it will forward to the next-hop - */ - ila_entry_stack (e); - } - } - else - { - ila_entry_t *e; - kv.key[0] = args->sir_address.as_u64[0]; - kv.key[1] = args->sir_address.as_u64[1]; - kv.key[2] = 0; - - if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) < - 0)) - { - return -1; - } - - e = &ilm->entries[value.value]; - - if (!ip6_address_is_zero(&e->next_hop)) - { - fib_prefix_t pfx = { - .fp_addr = { - .ip6 = e->ila_address, - }, - .fp_len = 128, - .fp_proto = FIB_PROTOCOL_IP6, - }; - - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); - /* - * remove this ILA entry as child of the FIB netry for the next-hop - */ - fib_entry_child_remove(e->next_hop_fib_entry_index, - e->next_hop_child_index); - fib_table_entry_delete_index(e->next_hop_fib_entry_index, - FIB_SOURCE_RR); - e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; - } - dpo_reset (&e->ila_dpo); - - BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, - 0 /* is_add */ ); - pool_put (ilm->entries, e); - } - return 0; -} - -int -ila_interface (u32 sw_if_index, u8 disable) -{ - vnet_feature_enable_disable ("ip4-unicast", "sir-to-ila", sw_if_index, - !disable, 0, 0); - return 0; -} - -clib_error_t * -vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, - int from_early_init) -{ - clib_error_t *error = 0; - - return error; -} - -u8 *format_ila_dpo (u8 * s, va_list * va) -{ - index_t index = va_arg (*va, index_t); - CLIB_UNUSED(u32 indent) = va_arg (*va, u32); - ila_main_t *ilm = &ila_main; - ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); - return format(s, "ILA: idx:%d sir:%U", - index, - format_ip6_address, &ie->sir_address); -} - -/** - * @brief no-op lock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_dpo_lock (dpo_id_t *dpo) -{ -} - -/** - * @brief no-op unlock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_dpo_unlock (dpo_id_t *dpo) -{ -} - -const static dpo_vft_t ila_vft = { - .dv_lock = ila_dpo_lock, - .dv_unlock = ila_dpo_unlock, - .dv_format = format_ila_dpo, -}; -const static char* const ila_ip6_nodes[] = -{ - "ila-to-sir", - NULL, -}; -const static char* const * const ila_nodes[DPO_PROTO_NUM] = -{ - [DPO_PROTO_IP6] = ila_ip6_nodes, -}; - -static fib_node_t * -ila_fib_node_get_node (fib_node_index_t index) -{ - ila_main_t *ilm = &ila_main; - ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); - - return (&ie->ila_fib_node); -} - -/** - * @brief no-op unlock function. - * The lifetime of the ILA entry is managed by the control plane - */ -static void -ila_fib_node_last_lock_gone (fib_node_t *node) -{ -} - -static ila_entry_t * -ila_entry_from_fib_node (fib_node_t *node) -{ - return ((ila_entry_t*)(((char*)node) - - STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); -} - -/** - * @brief - * Callback function invoked when the forwarding changes for the ILA next-hop - */ -static fib_node_back_walk_rc_t -ila_fib_node_back_walk_notify (fib_node_t *node, - fib_node_back_walk_ctx_t *ctx) -{ - ila_entry_stack(ila_entry_from_fib_node(node)); - - return (FIB_NODE_BACK_WALK_CONTINUE); -} - -/* - * ILA's FIB graph node virtual function table - */ -static const fib_node_vft_t ila_fib_node_vft = { - .fnv_get = ila_fib_node_get_node, - .fnv_last_lock = ila_fib_node_last_lock_gone, - .fnv_back_walk = ila_fib_node_back_walk_notify, -}; - -clib_error_t * -ila_init (vlib_main_t * vm) -{ - ila_main_t *ilm = &ila_main; - ilm->entries = NULL; - - ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; - ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); - ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; - - BV (clib_bihash_init) (&ilm->id_to_entry_table, - "ila id to entry index table", - ilm->lookup_table_nbuckets, ilm->lookup_table_size); - - ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); - ila_fib_node_type = fib_node_register_new_type(&ila_fib_node_vft); - - return NULL; -} - -VLIB_INIT_FUNCTION (ila_init); - -static clib_error_t * -ila_entry_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ila_add_del_entry_args_t args = { 0 }; - u8 next_hop_set = 0; - int ret; - - args.type = ILA_TYPE_IID; - args.csum_mode = ILA_CSUM_MODE_NO_ACTION; - args.local_adj_index = ~0; - args.dir = ILA_DIR_BIDIR; - - if (!unformat_user (input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "type %U", unformat_ila_type, &args.type)) - ; - else if (unformat - (line_input, "sir-address %U", unformat_ip6_address, - &args.sir_address)) - ; - else if (unformat - (line_input, "locator %U", unformat_half_ip6_address, - &args.locator)) - ; - else if (unformat - (line_input, "csum-mode %U", unformat_ila_csum_mode, - &args.csum_mode)) - ; - else if (unformat (line_input, "vnid %x", &args.vnid)) - ; - else if (unformat - (line_input, "next-hop %U", unformat_ip6_address, - &args.next_hop_address)) - ; - else if (unformat - (line_input, "direction %U", unformat_ila_direction, &args.dir)) - next_hop_set = 1; - else if (unformat (line_input, "del")) - args.is_del = 1; - else - return clib_error_return (0, "parse error: '%U'", - format_unformat_error, line_input); - } - - unformat_free (line_input); - - if (!next_hop_set) - return clib_error_return (0, "Specified a next hop"); - - if ((ret = ila_add_del_entry (&args))) - return clib_error_return (0, "ila_add_del_entry returned error %d", ret); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_entry_command, static) = -{ - .path = "ila entry", - .short_help = "ila entry [type ] [sir-address
] [locator ] [vnid ]" - " [adj-index ] [next-hop ] [direction (bidir|sir2ila|ila2sir)]" - " [csum-mode (no-action|neutral-map|transport-adjust)] [del]", - .function = ila_entry_command_fn, -}; - -static clib_error_t * -ila_interface_command_fn (vlib_main_t * vm, - unformat_input_t * input, vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ~0; - u8 disable = 0; - - if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) - { - return clib_error_return (0, "Invalid interface name"); - } - - if (unformat (input, "disable")) - { - disable = 1; - } - - int ret; - if ((ret = ila_interface (sw_if_index, disable))) - return clib_error_return (0, "ila_interface returned error %d", ret); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_interface_command, static) = -{ - .path = "ila interface", - .short_help = "ila interface [disable]", - .function = ila_interface_command_fn, -}; - -static clib_error_t * -ila_show_entries_command_fn (vlib_main_t * vm, - unformat_input_t * input, - vlib_cli_command_t * cmd) -{ - vnet_main_t *vnm = vnet_get_main (); - ila_main_t *ilm = &ila_main; - ila_entry_t *e; - - vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, NULL); - pool_foreach (e, ilm->entries, - ({ - vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, e); - })); - - return NULL; -} - -VLIB_CLI_COMMAND (ila_show_entries_command, static) = -{ - .path = "show ila entries", - .short_help = "show ila entries", - .function = ila_show_entries_command_fn, -}; diff --git a/plugins/ila-plugin/ila/ila.h b/plugins/ila-plugin/ila/ila.h deleted file mode 100644 index 26620983823..00000000000 --- a/plugins/ila-plugin/ila/ila.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ILA_H -#define ILA_H - -#include -#include -#include - -#include -#include - -#define ila_foreach_type \ - _(IID, 0, "iid") \ - _(LUID, 1, "luid") \ - _(VNID4, 2, "vnid-ip4") \ - _(VNID6, 3, "vnid-ip6") \ - _(VNIDM, 4, "vnid-multicast") - -typedef enum { -#define _(i,n,s) ILA_TYPE_##i = n, - ila_foreach_type -#undef _ -} ila_type_t; - -#define ila_csum_foreach_type \ -_(NO_ACTION, 0, "no-action") \ -_(NEUTRAL_MAP, 1, "neutral-map") \ -_(ADJUST_TRANSPORT, 2, "adjust-transport") - -typedef enum { -#define _(i,n,s) ILA_CSUM_MODE_##i = n, - ila_csum_foreach_type -#undef _ - ILA_CSUM_N_TYPES -} ila_csum_mode_t; - -#define ila_foreach_direction \ -_(BIDIR, 0, "bidir") \ -_(SIR2ILA, 1, "sir2ila") \ -_(ILA2SIR, 2, "ila2sir") - -typedef enum { -#define _(i,n,s) ILA_DIR_##i = n, - ila_foreach_direction -#undef _ -} ila_direction_t; - -typedef struct { - /** - * Fib Node base class - */ - fib_node_t ila_fib_node; - ila_type_t type; - ip6_address_t sir_address; - ip6_address_t ila_address; - ip6_address_t next_hop; - ila_csum_mode_t csum_mode; - ila_direction_t dir; - - /** - * The FIB entry index for the next-hop - */ - fib_node_index_t next_hop_fib_entry_index; - - /** - * The child index on the FIB entry - */ - u32 next_hop_child_index; - - /** - * The next DPO in the grpah to follow - */ - dpo_id_t ila_dpo; -} ila_entry_t; - -typedef struct { - ila_entry_t *entries; //Pool of ILA entries - - u64 lookup_table_nbuckets; - u64 lookup_table_size; - clib_bihash_24_8_t id_to_entry_table; - - u32 ip6_lookup_next_index; -} ila_main_t; - - -typedef struct { - ila_type_t type; - ip6_address_t sir_address; - ip6_address_t next_hop_address; - u64 locator; - u32 vnid; - u32 local_adj_index; - ila_csum_mode_t csum_mode; - ila_direction_t dir; - u8 is_del; -} ila_add_del_entry_args_t; - -int ila_add_del_entry (ila_add_del_entry_args_t * args); -int ila_interface (u32 sw_if_index, u8 disable); - -#endif //ILA_H diff --git a/plugins/sixrd-plugin/Makefile.am b/plugins/sixrd-plugin/Makefile.am deleted file mode 100644 index eb0d806aa6a..00000000000 --- a/plugins/sixrd-plugin/Makefile.am +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2015 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -AUTOMAKE_OPTIONS = foreign subdir-objects - -AM_CFLAGS = -Wall -AM_LDFLAGS = -module -shared -avoid-version - -libsixrd_plugin_la_SOURCES = \ - sixrd/sixrd.c \ - sixrd/sixrd_dpo.c \ - sixrd/ip4_sixrd.c \ - sixrd/ip6_sixrd.c - -noinst_HEADERS = \ - sixrd/sixrd.h \ - sixrd/sixrd_dpo.h - -BUILT_SOURCES = - -vpppluginsdir = ${libdir}/vpp_plugins - -vppplugins_LTLIBRARIES = libsixrd_plugin.la - - -# Remove *.la files -install-data-hook: - @(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) diff --git a/plugins/sixrd-plugin/configure.ac b/plugins/sixrd-plugin/configure.ac deleted file mode 100644 index 3aa4c425158..00000000000 --- a/plugins/sixrd-plugin/configure.ac +++ /dev/null @@ -1,9 +0,0 @@ -AC_INIT(sixrd_plugin, 1.0) -LT_INIT -AM_INIT_AUTOMAKE -AM_SILENT_RULES([yes]) -AC_PREFIX_DEFAULT([/usr]) - -AC_PROG_CC - -AC_OUTPUT([Makefile]) diff --git a/plugins/sixrd-plugin/sixrd/ip4_sixrd.c b/plugins/sixrd-plugin/sixrd/ip4_sixrd.c deleted file mode 100644 index 2fb8015d994..00000000000 --- a/plugins/sixrd-plugin/sixrd/ip4_sixrd.c +++ /dev/null @@ -1,127 +0,0 @@ -/*--------------------------------------------------------------------------- - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#include "sixrd.h" - -static vlib_node_registration_t ip4_sixrd_node; - -typedef enum { - IP4_SIXRD_NEXT_IP6_LOOKUP, - IP4_SIXRD_NEXT_DROP, - IP4_SIXRD_N_NEXT, -} ip4_sixrd_next_t; - -/* - * ip4_sixrd_sec_check - */ -static_always_inline void -ip4_sixrd_sec_check (sixrd_domain_t *d, ip4_address_t sa4, ip6_address_t sa6, u8 *error) -{ - u32 a = sixrd_get_addr(d, sa6.as_u64[0]); - clib_warning("Security check: %U %U", format_ip4_address, &a, format_ip4_address, &sa4); - if (PREDICT_FALSE(sixrd_get_addr(d, sa6.as_u64[0]) != sa4.as_u32)) - *error = SIXRD_ERROR_SEC_CHECK; -} - -/* - * ip4_sixrd - */ -static uword -ip4_sixrd (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_sixrd_node.index); - u32 decap = 0; - - from = vlib_frame_vector_args(frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - while (n_left_from > 0) { - vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); - - /* Single loop */ - while (n_left_from > 0 && n_left_to_next > 0) { - u32 pi0; - vlib_buffer_t *p0; - u8 error0 = SIXRD_ERROR_NONE; - sixrd_domain_t *d0 = 0; - ip4_header_t *ip40; - ip6_header_t *ip60; - u32 sixrd_domain_index0 = ~0; - u32 next0; - - pi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next +=1; - n_left_to_next -= 1; - - p0 = vlib_get_buffer(vm, pi0); - ip40 = vlib_buffer_get_current(p0); - - /* Throw away anything that isn't IP in IP. */ - if (PREDICT_TRUE(ip40->protocol == IP_PROTOCOL_IPV6 && clib_net_to_host_u16(ip40->length) >= 60)) { - vlib_buffer_advance(p0, sizeof(ip4_header_t)); - ip60 = vlib_buffer_get_current(p0); - d0 = ip4_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], (ip6_address_t *)&ip60->src_address, - &sixrd_domain_index0, &error0); - } else { - error0 = SIXRD_ERROR_BAD_PROTOCOL; - } - if (d0) { - /* SIXRD inbound security check */ - ip4_sixrd_sec_check(d0, ip40->src_address, ip60->src_address, &error0); - } - - next0 = error0 == SIXRD_ERROR_NONE ? IP4_SIXRD_NEXT_IP6_LOOKUP : IP4_SIXRD_NEXT_DROP; - - if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { - sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); - tr->sixrd_domain_index = sixrd_domain_index0; - } - - p0->error = error_node->errors[error0]; - if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) decap++; - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); - - } - vlib_put_next_frame(vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter(vm, ip4_sixrd_node.index, SIXRD_ERROR_DECAPSULATED, decap); - - return frame->n_vectors; -} - -static char *sixrd_error_strings[] = { -#define _(sym,string) string, - foreach_sixrd_error -#undef _ -}; - -VLIB_REGISTER_NODE(ip4_sixrd_node,static) = { - .function = ip4_sixrd, - .name = "ip4-sixrd", - .vector_size = sizeof(u32), - .format_trace = format_sixrd_trace, - .n_errors = SIXRD_N_ERROR, - .error_strings = sixrd_error_strings, - .n_next_nodes = IP4_SIXRD_N_NEXT, - .next_nodes = { - [IP4_SIXRD_NEXT_IP6_LOOKUP] = "ip6-lookup", - [IP4_SIXRD_NEXT_DROP] = "error-drop", - }, -}; diff --git a/plugins/sixrd-plugin/sixrd/ip6_sixrd.c b/plugins/sixrd-plugin/sixrd/ip6_sixrd.c deleted file mode 100644 index 36f3fab320b..00000000000 --- a/plugins/sixrd-plugin/sixrd/ip6_sixrd.c +++ /dev/null @@ -1,129 +0,0 @@ -/*--------------------------------------------------------------------------- - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -/* - * Defines used for testing various optimisation schemes - */ -#define SIXRD_ENCAP_DUAL 0 - -#include "sixrd.h" - -static vlib_node_registration_t ip6_sixrd_node; - -typedef enum { - IP6_SIXRD_NEXT_IP4_LOOKUP, - IP6_SIXRD_NEXT_DROP, - IP6_SIXRD_N_NEXT, -} ip6_sixrd_next_t; - -/* - * ip6_sixrd - */ -static uword -ip6_sixrd (vlib_main_t *vm, - vlib_node_runtime_t *node, - vlib_frame_t *frame) -{ - u32 n_left_from, *from, next_index, *to_next, n_left_to_next; - vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip6_sixrd_node.index); - u32 encap = 0; - from = vlib_frame_vector_args(frame); - n_left_from = frame->n_vectors; - next_index = node->cached_next_index; - - while (n_left_from > 0) { - vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); - - while (n_left_from > 0 && n_left_to_next > 0) { - u32 pi0; - vlib_buffer_t *p0; - sixrd_domain_t *d0; - u8 error0 = SIXRD_ERROR_NONE; - ip6_header_t *ip60; - ip4_header_t *ip4h0; - u32 next0 = IP6_SIXRD_NEXT_IP4_LOOKUP; - u32 sixrd_domain_index0 = ~0; - - pi0 = to_next[0] = from[0]; - from += 1; - n_left_from -= 1; - to_next +=1; - n_left_to_next -= 1; - - p0 = vlib_get_buffer(vm, pi0); - ip60 = vlib_buffer_get_current(p0); - // p0->current_length = clib_net_to_host_u16(ip40->length); - d0 = ip6_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &sixrd_domain_index0); - ASSERT(d0); - - /* SIXRD calc */ - u64 dal60 = clib_net_to_host_u64(ip60->dst_address.as_u64[0]); - u32 da40 = sixrd_get_addr(d0, dal60); - u16 len = clib_net_to_host_u16(ip60->payload_length) + 60; - if (da40 == 0) error0 = SIXRD_ERROR_UNKNOWN; - - /* construct ipv4 header */ - vlib_buffer_advance(p0, - (sizeof(ip4_header_t))); - ip4h0 = vlib_buffer_get_current(p0); - vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0; - ip4h0->ip_version_and_header_length = 0x45; - ip4h0->tos = 0; - ip4h0->length = clib_host_to_net_u16(len); - ip4h0->fragment_id = 0; - ip4h0->flags_and_fragment_offset = 0; - ip4h0->ttl = 0x40; - ip4h0->protocol = IP_PROTOCOL_IPV6; - ip4h0->src_address = d0->ip4_src; - ip4h0->dst_address.as_u32 = clib_host_to_net_u32(da40); - ip4h0->checksum = ip4_header_checksum(ip4h0); - - next0 = error0 == SIXRD_ERROR_NONE ? IP6_SIXRD_NEXT_IP4_LOOKUP : IP6_SIXRD_NEXT_DROP; - - if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { - sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); - tr->sixrd_domain_index = sixrd_domain_index0; - } - - p0->error = error_node->errors[error0]; - if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) encap++; - - vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); - } - vlib_put_next_frame(vm, node, next_index, n_left_to_next); - } - vlib_node_increment_counter(vm, ip6_sixrd_node.index, SIXRD_ERROR_ENCAPSULATED, encap); - - return frame->n_vectors; -} - -static char *sixrd_error_strings[] = { -#define _(sym,string) string, - foreach_sixrd_error -#undef _ -}; - -VLIB_REGISTER_NODE(ip6_sixrd_node,static) = { - .function = ip6_sixrd, - .name = "ip6-sixrd", - .vector_size = sizeof(u32), - .format_trace = format_sixrd_trace, - .n_errors = SIXRD_N_ERROR, - .error_strings = sixrd_error_strings, - .n_next_nodes = IP6_SIXRD_N_NEXT, - .next_nodes = { - [IP6_SIXRD_NEXT_IP4_LOOKUP] = "ip4-lookup", - [IP6_SIXRD_NEXT_DROP] = "error-drop", - }, -}; diff --git a/plugins/sixrd-plugin/sixrd/sixrd.c b/plugins/sixrd-plugin/sixrd/sixrd.c deleted file mode 100644 index 66e631a2b6a..00000000000 --- a/plugins/sixrd-plugin/sixrd/sixrd.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sixrd.h" -#include - -#include -#include -#include - -/* - * This code supports the following sixrd modes: - * - * 32 EA bits (Complete IPv4 address is embedded): - * ea_bits_len = 32 - * IPv4 suffix is embedded: - * ea_bits_len = < 32 - * No embedded address bits (1:1 mode): - * ea_bits_len = 0 - */ - -int -sixrd_create_domain (ip6_address_t *ip6_prefix, - u8 ip6_prefix_len, - ip4_address_t *ip4_prefix, - u8 ip4_prefix_len, - ip4_address_t *ip4_src, - u32 *sixrd_domain_index, - u16 mtu) -{ - dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID; - sixrd_main_t *mm = &sixrd_main; - fib_node_index_t fei; - sixrd_domain_t *d; - - /* Get domain index */ - pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES); - memset(d, 0, sizeof (*d)); - *sixrd_domain_index = d - mm->domains; - - /* Init domain struct */ - d->ip4_prefix.as_u32 = ip4_prefix->as_u32; - d->ip4_prefix_len = ip4_prefix_len; - d->ip6_prefix = *ip6_prefix; - d->ip6_prefix_len = ip6_prefix_len; - d->ip4_src = *ip4_src; - d->mtu = mtu; - - if (ip4_prefix_len < 32) - d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len); - - /* Create IPv6 route/adjacency */ - fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, - }; - sixrd_dpo_create(DPO_PROTO_IP6, - *sixrd_domain_index, - &dpo_v6); - fib_table_entry_special_dpo_add(0, &pfx6, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v6); - dpo_reset (&dpo_v6); - - /* - * Multiple SIXRD domains may share same source IPv4 TEP - * In this case the route will exist and be SixRD sourced. - * Find the adj (if any) already contributed and modify it - */ - fib_prefix_t pfx4 = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, - }; - fei = fib_table_lookup_exact_match(0, &pfx4); - - if (FIB_NODE_INDEX_INVALID != fei) - { - dpo_id_t dpo = DPO_INVALID; - - if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo)) - { - /* - * modify the existing adj to indicate it's shared - * skip to route add. - * It is locked to pair with the unlock below. - */ - const dpo_id_t *sd_dpo; - sixrd_dpo_t *sd; - - ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type); - - sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0); - sd = sixrd_dpo_get (sd_dpo->dpoi_index); - - sd->sd_domain = ~0; - dpo_copy (&dpo_v4, sd_dpo); - dpo_reset (&dpo); - - goto route_add; - } - } - /* first time addition of the route */ - sixrd_dpo_create(DPO_PROTO_IP4, - *sixrd_domain_index, - &dpo_v4); - -route_add: - /* - * Create ip4 route. This is a reference counted add. If the prefix - * already exists and is SixRD sourced, it is now SixRD source n+1 times - * and will need to be removed n+1 times. - */ - fib_table_entry_special_dpo_add(0, &pfx4, - FIB_SOURCE_SIXRD, - FIB_ENTRY_FLAG_EXCLUSIVE, - &dpo_v4); - dpo_reset (&dpo_v4); - - return 0; -} - -/* - * sixrd_delete_domain - */ -int -sixrd_delete_domain (u32 sixrd_domain_index) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - - if (pool_is_free_index(mm->domains, sixrd_domain_index)) { - clib_warning("SIXRD domain delete: domain does not exist: %d", - sixrd_domain_index); - return -1; - } - - d = pool_elt_at_index(mm->domains, sixrd_domain_index); - - fib_prefix_t pfx = { - .fp_proto = FIB_PROTOCOL_IP4, - .fp_len = 32, - .fp_addr = { - .ip4 = d->ip4_src, - }, - }; - fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD); - - fib_prefix_t pfx6 = { - .fp_proto = FIB_PROTOCOL_IP6, - .fp_len = d->ip6_prefix_len, - .fp_addr = { - .ip6 = d->ip6_prefix, - }, - }; - fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD); - - pool_put(mm->domains, d); - - return 0; -} - -static clib_error_t * -sixrd_add_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - ip4_address_t ip4_prefix; - ip6_address_t ip6_prefix; - ip4_address_t ip4_src; - u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index; - u32 num_m_args = 0; - /* Optional arguments */ - u32 mtu = 0; - - /* Get a line of input. */ - if (!unformat_user(input, unformat_line_input, line_input)) - return 0; - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat(line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len)) - num_m_args++; - else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) - num_m_args++; - else if (unformat(line_input, "mtu %d", &mtu)) - num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); - } - unformat_free(line_input); - - if (num_m_args < 3) - return clib_error_return(0, "mandatory argument(s) missing"); - - sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, - &ip4_src, &sixrd_domain_index, mtu); - - return 0; -} - -static clib_error_t * -sixrd_del_domain_command_fn (vlib_main_t *vm, - unformat_input_t *input, - vlib_cli_command_t *cmd) -{ - unformat_input_t _line_input, *line_input = &_line_input; - u32 num_m_args = 0; - u32 sixrd_domain_index; - - /* Get a line of input. */ - if (! unformat_user(input, unformat_line_input, line_input)) - return 0; - - while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) { - if (unformat(line_input, "index %d", &sixrd_domain_index)) - num_m_args++; - else - return clib_error_return(0, "unknown input `%U'", - format_unformat_error, input); - } - unformat_free(line_input); - - if (num_m_args != 1) - return clib_error_return(0, "mandatory argument(s) missing"); - - sixrd_delete_domain(sixrd_domain_index); - - return 0; -} - -static u8 * -format_sixrd_domain (u8 *s, va_list *args) -{ - sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *); - sixrd_main_t *mm = &sixrd_main; - - s = format(s, - "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d", - d - mm->domains, - format_ip6_address, &d->ip6_prefix, d->ip6_prefix_len, - format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len, - format_ip4_address, &d->ip4_src, d->mtu); - - return s; -} - -static clib_error_t * -show_sixrd_domain_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - - if (pool_elts(mm->domains) == 0) - vlib_cli_output(vm, "No SIXRD domains are configured..."); - - pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);})); - - return 0; - -} - -static clib_error_t * -show_sixrd_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_domain_t *d; - int domains = 0, domaincount = 0; - if (pool_elts (mm->domains) == 0) - vlib_cli_output (vm, "No SIXRD domains are configured..."); - - pool_foreach(d, mm->domains, ({ - domains += sizeof(*d); - domaincount++; - })); - - vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t)); - vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains); - - return 0; -} - -/* - * packet trace format function - */ -u8 * -format_sixrd_trace (u8 *s, va_list *args) -{ - CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *); - sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *); - u32 sixrd_domain_index = t->sixrd_domain_index; - - s = format(s, "SIXRD domain index: %d", sixrd_domain_index); - - return s; -} - -VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = { - .path = "sixrd add domain", - .short_help = - "sixrd add domain ip6-pfx ip4-pfx ip4-src ", - .function = sixrd_add_domain_command_fn, -}; - -VLIB_CLI_COMMAND(sixrd_del_command, static) = { - .path = "sixrd del domain", - .short_help = - "sixrd del domain index ", - .function = sixrd_del_domain_command_fn, -}; - -VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = { - .path = "show sixrd domain", - .function = show_sixrd_domain_command_fn, -}; - -VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = { - .path = "show sixrd stats", - .function = show_sixrd_stats_command_fn, -}; - -/* - * This routine exists to convince the vlib plugin framework that - * we haven't accidentally copied a random .dll into the plugin directory. - * - * Also collects global variable pointers passed from the vpp engine - */ -clib_error_t * -vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, - int from_early_init) -{ - clib_error_t * error = 0; - sixrd_main_t *mm = &sixrd_main; - - mm->vnet_main = vnet_get_main(); - mm->vlib_main = vm; - - return error; -} - -static clib_error_t * sixrd_init (vlib_main_t * vm) -{ - sixrd_dpo_module_init (); - - return (NULL); -} - -VLIB_INIT_FUNCTION (sixrd_init); diff --git a/plugins/sixrd-plugin/sixrd/sixrd.h b/plugins/sixrd-plugin/sixrd/sixrd.h deleted file mode 100644 index 56714c9e3bd..00000000000 --- a/plugins/sixrd-plugin/sixrd/sixrd.h +++ /dev/null @@ -1,141 +0,0 @@ -/*--------------------------------------------------------------------------- - * Copyright (c) 2009-2014 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *--------------------------------------------------------------------------- - */ -#include -#include -#include -#include -#include - -#include "sixrd_dpo.h" - -int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len, - ip4_address_t *ip4_prefix, u8 ip4_prefix_len, - ip4_address_t *ip4_src, u32 *sixrd_domain_index, u16 mtu); -int sixrd_delete_domain(u32 sixrd_domain_index); -u8 *format_sixrd_trace(u8 *s, va_list *args); - -typedef struct { - ip6_address_t ip6_prefix; - ip4_address_t ip4_prefix; - ip4_address_t ip4_src; - u8 ip6_prefix_len; - u8 ip4_prefix_len; - - /* helpers */ - u8 shift; - - u16 mtu; -} sixrd_domain_t; - -typedef struct { - /* pool of SIXRD domains */ - sixrd_domain_t *domains; - - /* convenience */ - vlib_main_t *vlib_main; - vnet_main_t *vnet_main; -} sixrd_main_t; - -#define foreach_sixrd_error \ - /* Must be first. */ \ - _(NONE, "valid SIXRD packets") \ - _(BAD_PROTOCOL, "bad protocol") \ - _(WRONG_ICMP_TYPE, "wrong icmp type") \ - _(SEC_CHECK, "security check failed") \ - _(ICMP, "unable to translate ICMP") \ - _(UNKNOWN, "unknown") \ - _(NO_DOMAIN, "no domain") \ - _(ENCAPSULATED, "encapsulated") \ - _(DECAPSULATED, "decapsulated") \ - _(TRANSLATED_4TO6, "translated 4 to 6") \ - _(TRANSLATED_6TO4, "translated 6 to 4") \ - _(FRAGMENT, "fragment handling error") \ - _(FRAGMENT_QUEUED, "dropped, missing first fragment") \ - _(FRAGMENTED, "packets requiring fragmentation") \ - _(FRAGMENT_PARTS, "fragment parts") \ - _(MALFORMED, "malformed packet") - -typedef enum { -#define _(sym,str) SIXRD_ERROR_##sym, - foreach_sixrd_error -#undef _ - SIXRD_N_ERROR, - } sixrd_error_t; - -typedef struct { - u32 sixrd_domain_index; -} sixrd_trace_t; - -sixrd_main_t sixrd_main; - -/* - * sixrd_get_addr - */ -static_always_inline u32 -sixrd_get_addr (sixrd_domain_t *d, u64 dal) -{ - - /* 1:1 mode */ - if (d->ip4_prefix_len == 32) return (d->ip4_prefix.as_u32); - - /* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset ip6_prefix_len */ - return (d->ip4_prefix.as_u32 | (u32)(dal >> d->shift)); -} - -/* - * Get the SIXRD domain from an IPv6 lookup adjacency. - */ -static_always_inline sixrd_domain_t * -ip6_sixrd_get_domain (u32 sdi, u32 *sixrd_domain_index) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(sdi); - - ASSERT(sd); - *sixrd_domain_index = sd->sd_domain; - return pool_elt_at_index(mm->domains, *sixrd_domain_index); -} - -/* - * Get the SIXRD domain from an IPv4 lookup adjacency. - * If the IPv4 address is not shared, no lookup is required. - * The IPv6 address is used otherwise. - */ -static_always_inline sixrd_domain_t * -ip4_sixrd_get_domain (u32 sdi, ip6_address_t *addr, - u32 *sixrd_domain_index, u8 *error) -{ - sixrd_main_t *mm = &sixrd_main; - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(sdi); - *sixrd_domain_index = sd->sd_domain; - if (*sixrd_domain_index != ~0) - return pool_elt_at_index(mm->domains, *sixrd_domain_index); - - u32 lbi = ip6_fib_table_fwding_lookup(&ip6_main, 0, addr); - const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0); - if (PREDICT_TRUE(dpo->dpoi_type == sixrd_dpo_type)) - { - sd = sixrd_dpo_get(dpo->dpoi_index); - *sixrd_domain_index = sd->sd_domain; - return pool_elt_at_index(mm->domains, *sixrd_domain_index); - } - *error = SIXRD_ERROR_NO_DOMAIN; - return NULL; -} diff --git a/plugins/sixrd-plugin/sixrd/sixrd_dpo.c b/plugins/sixrd-plugin/sixrd/sixrd_dpo.c deleted file mode 100644 index 88a079350a3..00000000000 --- a/plugins/sixrd-plugin/sixrd/sixrd_dpo.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sixrd_dpo.h" -#include - -/** - * pool of all MPLS Label DPOs - */ -sixrd_dpo_t *sixrd_dpo_pool; - -/** - * The register SIXRD DPO type - */ -dpo_type_t sixrd_dpo_type; - -static sixrd_dpo_t * -sixrd_dpo_alloc (void) -{ - sixrd_dpo_t *sd; - - pool_get_aligned(sixrd_dpo_pool, sd, CLIB_CACHE_LINE_BYTES); - memset(sd, 0, sizeof(*sd)); - - return (sd); -} - -static index_t -sixrd_dpo_get_index (sixrd_dpo_t *sd) -{ - return (sd - sixrd_dpo_pool); -} - -void -sixrd_dpo_create (dpo_proto_t dproto, - u32 domain_index, - dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_alloc(); - sd->sd_domain = domain_index; - sd->sd_proto = dproto; - - dpo_set(dpo, - sixrd_dpo_type, - dproto, - sixrd_dpo_get_index(sd)); -} - -u8* -format_sixrd_dpo (u8 *s, va_list *args) -{ - index_t index = va_arg (*args, index_t); - CLIB_UNUSED(u32 indent) = va_arg (*args, u32); - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(index); - - return (format(s, "sixrd:[%d]:%U domain:%d", - index, - format_dpo_proto, sd->sd_proto, - sd->sd_domain)); -} - - -static void -sixrd_dpo_lock (dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(dpo->dpoi_index); - - sd->sd_locks++; -} - -static void -sixrd_dpo_unlock (dpo_id_t *dpo) -{ - sixrd_dpo_t *sd; - - sd = sixrd_dpo_get(dpo->dpoi_index); - - sd->sd_locks--; - - if (0 == sd->sd_locks) - { - pool_put(sixrd_dpo_pool, sd); - } -} - -const static dpo_vft_t sd_vft = { - .dv_lock = sixrd_dpo_lock, - .dv_unlock = sixrd_dpo_unlock, - .dv_format = format_sixrd_dpo, -}; - -const static char* const sixrd_ip4_nodes[] = -{ - "ip4-sixrd", - NULL, -}; -const static char* const sixrd_ip6_nodes[] = -{ - "ip6-sixrd", - NULL, -}; - -const static char* const * const sixrd_nodes[DPO_PROTO_NUM] = -{ - [DPO_PROTO_IP4] = sixrd_ip4_nodes, - [DPO_PROTO_IP6] = sixrd_ip6_nodes, - [DPO_PROTO_MPLS] = NULL, -}; - -void -sixrd_dpo_module_init (void) -{ - sixrd_dpo_type = dpo_register_new_type(&sd_vft, sixrd_nodes); -} diff --git a/plugins/sixrd-plugin/sixrd/sixrd_dpo.h b/plugins/sixrd-plugin/sixrd/sixrd_dpo.h deleted file mode 100644 index 17142288451..00000000000 --- a/plugins/sixrd-plugin/sixrd/sixrd_dpo.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SIXRD_DPO_H__ -#define __SIXRD_DPO_H__ - -#include -#include - -/** - * A representation of a 6RD DPO - */ -typedef struct sixrd_dpo_t -{ - /** - * The dat-plane protocol - */ - dpo_proto_t sd_proto; - - /** - * the SIXRD domain index - */ - u32 sd_domain; - - /** - * Number of locks/users of the label - */ - u16 sd_locks; -} sixrd_dpo_t; - -extern void sixrd_dpo_create (dpo_proto_t dproto, - u32 domain_index, - dpo_id_t *dpo); - -/* - * Encapsulation violation for fast data-path access - */ -extern sixrd_dpo_t *sixrd_dpo_pool; -extern dpo_type_t sixrd_dpo_type; - -static inline sixrd_dpo_t * -sixrd_dpo_get (index_t index) -{ - return (pool_elt_at_index(sixrd_dpo_pool, index)); -} - -extern void sixrd_dpo_module_init(void); - -#endif diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000000..e691a5393d3 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,101 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################### +# Global Defines +############################################################################### + +AUTOMAKE_OPTIONS = foreign subdir-objects +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = -Wall + +SUBDIRS = . +SUFFIXES = .api.h .api .api.json +API_FILES = +noinst_HEADERS = +dist_bin_SCRIPTS = +lib_LTLIBRARIES = +BUILT_SOURCES = + +############################################################################### +# DPDK +############################################################################### + +if WITH_DPDK +if ENABLE_DPDK_SHARED +DPDK_LD_FLAGS = -Wl,--whole-archive,-ldpdk,--no-whole-archive +else +DPDK_LD_FLAGS = -Wl,--whole-archive,-l:libdpdk.a,--no-whole-archive +endif +if WITH_DPDK_CRYPTO +DPDK_LD_ADD = -L$(AESNI_MULTI_BUFFER_LIB_PATH) -lIPSec_MB +endif +if WITH_DPDK_MLX5_PMD +DPDK_LD_FLAGS += -libverbs -lmlx5 -lnuma +endif +else +DPDK_LD_FLAGS = +DPDK_LD_ADD = +endif + +############################################################################### +# Components +############################################################################### + +include vppinfra.am +include vppapigen.am + +if ENABLE_PERFTOOL +include perftool.am +endif + +if ENABLE_G2 +include g2.am +endif + +if ENABLE_SVM +include svm.am +endif + +if ENABLE_VLIB +include vlib.am +endif + +if ENABLE_SVM +if ENABLE_VLIB +include vlib-api.am +include vnet.am +include vpp.am +include vpp-api-test.am + +SUBDIRS += vpp-api/python plugins + +############################################################################### +# API +############################################################################### + +include suffix-rules.mk + +# Set the suffix list +apidir = $(prefix)/share/vpp/api/core + +api_DATA = \ + $(patsubst %.api,%.api.json,$(API_FILES)) + +BUILT_SOURCES += \ + $(patsubst %.api,%.api.json,$(API_FILES)) \ + $(patsubst %.api,%.api.h,$(API_FILES)) + +endif # if ENABLE_VLIB +endif # if ENABLE_SVM diff --git a/src/configure.ac b/src/configure.ac new file mode 100644 index 00000000000..f8e4d94f81d --- /dev/null +++ b/src/configure.ac @@ -0,0 +1,195 @@ +AC_INIT([vpp], [17.04], [vpp-dev@fd.io]) +LT_INIT +AC_CONFIG_AUX_DIR([.]) +AM_INIT_AUTOMAKE([subdir-objects]) +AM_SILENT_RULES([yes]) +AC_CONFIG_FILES([Makefile plugins/Makefile vpp-api/python/Makefile]) + +AC_PROG_CC +AM_PROG_AS +AM_PROG_LIBTOOL +AC_PROG_YACC + +############################################################################### +# Macros +############################################################################### + +AC_DEFUN([ENABLE_ARG], +[ + AC_ARG_ENABLE($1, + AC_HELP_STRING(patsubst([--enable-$1],[_],[-]), $2), + [enable_$1=yes n_enable_$1=1], + [enable_$1=no n_enable_$1=0]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes") + m4_append([list_of_enabled], [$1], [, ]) +]) + +AC_DEFUN([DISABLE_ARG], +[ + AC_ARG_ENABLE($1, + AC_HELP_STRING(patsubst([--disable-$1],[_],[-]), $2), + [enable_$1=no n_enable_$1=0], + [enable_$1=yes n_enable_$1=1]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1), test "$enable_$1" = "yes") + m4_append([list_of_enabled], [$1], [, ]) +]) + +AC_DEFUN([WITH_ARG], +[ + AC_ARG_WITH($1, + AC_HELP_STRING(patsubst([--with-$1],[_],[-]), $2), + [with_$1=yes n_with_$1=1], + [with_$1=no n_with_$1=0]) + AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes") + m4_append([list_of_with], [$1], [, ]) +]) + +AC_DEFUN([WITHOUT_ARG], +[ + AC_ARG_WITH($1, + AC_HELP_STRING(patsubst([--without-$1],[_],[-]), $2), + [with_$1=no n_with_$1=0], + [with_$1=yes n_with_$1=1]) + AM_CONDITIONAL(m4_toupper(WITH_$1), test "$with_$1" = "yes") + m4_append([list_of_with], [$1], [, ]) +]) + +AC_DEFUN([PLUGIN_ENABLED], +[ + AC_ARG_ENABLE($1_plugin, + AC_HELP_STRING([--disable-$1-plugin], [Do not build $1 plugin]), + [enable_$1_plugin=no], + [enable_$1_plugin=yes ]) + AM_CONDITIONAL(m4_toupper(ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes") + m4_append([list_of_plugins], [$1], [, ]) +]) + +AC_DEFUN([PLUGIN_DISABLED], +[ + AC_ARG_ENABLE($1_plugin, + AC_HELP_STRING([--enable-$1-plugin], [Build $1 plugin]), + [enable_$1_plugin=yes ], + [enable_$1_plugin=no]) + AM_CONDITIONAL(m4_toupper((ENABLE_$1_PLUGIN), test "$enable_$1_plugin" = "yes") + m4_append([list_of_plugins], [$1], [, ]) +]) + +AC_DEFUN([PRINT_VAL], [ AC_MSG_RESULT(AC_HELP_STRING($1,$2)) ]) + +############################################################################### +# configure arguments +############################################################################### + +# --enable-X +ENABLE_ARG(tests, [Enable unit tests]) +ENABLE_ARG(dpdk_shared, [Enable unit tests]) +ENABLE_ARG(perftool, [Enable perftool]) +ENABLE_ARG(g2, [Enable g2]) + +# --disable-X +DISABLE_ARG(vlib, [Disable vlib and dependant libs and binaries]) +DISABLE_ARG(svm, [Disable svm and dependant libs and binaries]) + +# --with-X +WITH_ARG(dpdk, [Use use DPDK]) +WITH_ARG(dpdk_crypto, [Use DPDK cryptodev]) +WITH_ARG(dpdk_mlx5_pmd, [Use DPDK with mlx5 PMD]) + +# --without-X +WITHOUT_ARG(ipsec, [Disable IPSec]) +WITHOUT_ARG(ipv6sr, [Disable IPv6 SR]) +WITHOUT_ARG(apicli, [Disable binary api CLI]) + +AC_ARG_WITH(unix, + AC_HELP_STRING([--with-unix],[Compile unix version of clib]), + [], + [case $host_os in + darwin* | linux*) with_unix=yes;; + *) with_unix=no;; + esac]) + +AM_CONDITIONAL(WITH_UNIX, test "$with_unix" = "yes") + +AC_ARG_WITH(pre-data, + AC_HELP_STRING([--with-pre-data],[Set buffer rewrite space]), + [case $with_pre_data in + 128) ;; + 256) ;; + *) with_pre_data="pre-data-not-set" ;; + esac], [with_pre_data=128]) + +############################################################################### +# Substitutions and defines +############################################################################### + +AC_SUBST(PRE_DATA_SIZE, [$with_pre_data]) +AC_SUBST(APICLI, [-DVPP_API_TEST_BUILTIN=${n_with_apicli}]) + +AC_DEFINE_UNQUOTED(DPDK, [${n_with_dpdk}]) +AC_DEFINE_UNQUOTED(DPDK_SHARED_LIB, [${n_enable_dpdk_shared}]) +AC_DEFINE_UNQUOTED(DPDK_CRYPTO, [${n_with_dpdk_crypto}]) +AC_DEFINE_UNQUOTED(IPSEC, [${n_with_ipsec}]) +AC_DEFINE_UNQUOTED(IPV6SR, [${n_with_ipv6sr}]) + +############################################################################### +# Dependency checks +############################################################################### + +AM_COND_IF([ENABLE_DPDK_SHARED], +[ + AC_CHECK_HEADERS([rte_config.h], + [], + [AC_MSG_ERROR([DPDK header files not found])],) + AC_CHECK_LIB( [dpdk], [rte_eal_init], + [], + [AC_MSG_ERROR([DPDK shared library not found])],) +]) + +AM_COND_IF([ENABLE_G2], +[ + PKG_CHECK_MODULES(g2, gtk+-2.0) +]) + +############################################################################### +# Plugins +############################################################################### + +PLUGIN_ENABLED(sixrd) +PLUGIN_ENABLED(ila) +PLUGIN_ENABLED(flowperpkt) + +############################################################################### +# Output +############################################################################### + +AC_OUTPUT + +AC_MSG_RESULT([==============================================================================]) +PRINT_VAL([version], $PACKAGE $VERSION) +PRINT_VAL([prefix], ${prefix}) +PRINT_VAL([libdir], ${libdir}) +PRINT_VAL([includedir], ${includedir}) +PRINT_VAL([CFLAGS], ${CFLAGS}) +PRINT_VAL([CPPFLAGS], ${CPPFLAGS}) +PRINT_VAL([LDFLAGS], ${LDFLAGS}) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([with:]) +m4_foreach([x], m4_dquote(list_of_with), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${with_], x, [}]))) +]) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([enabled:]) +m4_foreach([x], m4_dquote(list_of_enabled), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [}]))) +]) + +AC_MSG_RESULT([]) +AC_MSG_RESULT([plugins:]) +m4_foreach([x], m4_dquote(list_of_plugins), [ + AC_MSG_RESULT(AC_HELP_STRING(x, m4_join([], [${enable_], x, [_plugin}]))) +]) +AC_MSG_RESULT([==============================================================================]) + + diff --git a/src/examples/vlib/dir.dox b/src/examples/vlib/dir.dox new file mode 100644 index 00000000000..d3ac0ee431b --- /dev/null +++ b/src/examples/vlib/dir.dox @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Doxygen directory documentation */ +/** +@dir +@brief Someone please fix this description +@todo This directory needs a description. +*/ diff --git a/src/examples/vlib/main_stub.c b/src/examples/vlib/main_stub.c new file mode 100644 index 00000000000..4d74bd77aaa --- /dev/null +++ b/src/examples/vlib/main_stub.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + return vlib_unix_main (argc, argv); +} + +static clib_error_t * +main_stub_init (vlib_main_t * vm) +{ + clib_error_t *error; + + if ((error = + unix_physmem_init (vm, /* fail_if_physical_memory_not_present */ 0))) + return error; + + if ((error = vlib_call_init_function (vm, unix_cli_init))) + return error; + + return error; +} + +VLIB_INIT_FUNCTION (main_stub_init); + +#if 0 +/* Node test code. */ +typedef struct +{ + int scalar; + int vector[0]; +} my_frame_t; + +static u8 * +format_my_node_frame (u8 * s, va_list * va) +{ + vlib_frame_t *f = va_arg (*va, vlib_frame_t *); + my_frame_t *g = vlib_frame_args (f); + int i; + + s = format (s, "scalar %d, vector { ", g->scalar); + for (i = 0; i < f->n_vectors; i++) + s = format (s, "%d, ", g->vector[i]); + s = format (s, " }"); + + return s; +} + +static uword +my_func (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + vlib_node_t *node; + my_frame_t *y; + u32 i, n_left = 0; + static int serial; + int verbose; + + node = vlib_get_node (vm, rt->node_index); + + verbose = 0; + + if (verbose && f) + vlib_cli_output (vm, "%v: call frame %p %U", node->name, + f, format_my_node_frame, f); + + if (rt->n_next_nodes > 0) + { + vlib_frame_t *next = vlib_get_next_frame (vm, rt, /* next index */ 0); + n_left = VLIB_FRAME_SIZE - next->n_vectors; + y = vlib_frame_args (next); + y->scalar = serial++; + } + else + y = 0; + + for (i = 0; i < 5; i++) + { + if (y) + { + ASSERT (n_left > 0); + n_left--; + y->vector[i] = y->scalar + i; + } + } + if (y) + vlib_put_next_frame (vm, rt, /* next index */ 0, n_left); + + if (verbose) + vlib_cli_output (vm, "%v: return frame %p", node->name, f); + + return i; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_node1,static) = { + .function = my_func, + .type = VLIB_NODE_TYPE_INPUT, + .name = "my-node1", + .scalar_size = sizeof (my_frame_t), + .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]), + .n_next_nodes = 1, + .next_nodes = { + [0] = "my-node2", + }, +}; +/* *INDENT-ON* */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_node2,static) = { + .function = my_func, + .name = "my-node2", + .scalar_size = sizeof (my_frame_t), + .vector_size = STRUCT_SIZE_OF (my_frame_t, vector[0]), +}; +/* *INDENT-ON* */ + +#endif + +#if 0 + +typedef enum +{ + MY_EVENT_TYPE1, + MY_EVENT_TYPE2, +} my_process_completion_type_t; + +typedef struct +{ + int a; + f64 b; +} my_process_event_data_t; + +static u8 * +format_my_process_event_data (u8 * s, va_list * va) +{ + my_process_event_data_t *d = va_arg (*va, my_process_event_data_t *); + return format (s, "{ a %d b %.6f}", d->a, d->b); +} + +static uword +my_proc (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + vlib_node_t *node; + u32 i; + + node = vlib_get_node (vm, rt->node_index); + + vlib_cli_output (vm, "%v: call frame %p", node->name, f); + + for (i = 0; i < 5; i++) + { + vlib_cli_output (vm, "%v: %d", node->name, i); + vlib_process_suspend (vm, 1e0 /* secs */ ); + } + + vlib_cli_output (vm, "%v: return frame %p", node->name, f); + + if (0) + { + uword n_events_seen, type, *data = 0; + + for (n_events_seen = 0; n_events_seen < 2;) + { + vlib_process_wait_for_event (vm); + type = vlib_process_get_events (vm, &data); + n_events_seen += vec_len (data); + vlib_cli_output (vm, "%U %v: completion #%d type %d data 0x%wx", + format_time_interval, "h:m:s:u", + vlib_time_now (vm), node->name, i, type, data[0]); + _vec_len (data) = 0; + } + + vec_free (data); + } + else + { + uword n_events_seen, i, type; + my_process_event_data_t *data; + for (n_events_seen = 0; n_events_seen < 2;) + { + vlib_process_wait_for_event (vm); + data = vlib_process_get_event_data (vm, &type); + vec_foreach_index (i, data) + { + vlib_cli_output (vm, "%U event type %d data %U", + format_time_interval, "h:m:s:u", + vlib_time_now (vm), type, + format_my_process_event_data, data); + } + n_events_seen += vec_len (data); + vlib_process_put_event_data (vm, data); + } + } + + return i; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_proc_node,static) = { + .function = my_proc, + .type = VLIB_NODE_TYPE_PROCESS, + .name = "my-proc", +}; +/* *INDENT-ON* */ + +static uword +my_proc_input (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + static int i; + + if (i++ < 2) + { + if (0) + vlib_process_signal_event (vm, my_proc_node.index, + i == 1 ? MY_EVENT_TYPE1 : MY_EVENT_TYPE2, + 0x12340000 + i); + else + { + my_process_event_data_t *d; + f64 dt = 5; + d = vlib_process_signal_event_at_time (vm, + i * dt, + my_proc_node.index, + i == + 1 ? MY_EVENT_TYPE1 : + MY_EVENT_TYPE2, + 1 /* elts */ , + sizeof (d[0])); + d->a = i; + d->b = vlib_time_now (vm); + } + } + else + vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (my_proc_input_node,static) = { + .function = my_proc_input, + .type = VLIB_NODE_TYPE_INPUT, + .name = "my-proc-input", +}; +/* *INDENT-ON* */ + +static uword +_unformat_farith (unformat_input_t * i, va_list * args) +{ + u32 prec = va_arg (*args, u32); + f64 *result = va_arg (*args, f64 *); + f64 tmp[2]; + + /* Binary operations in from lowest to highest precedence. */ + char *binops[] = { + "+%U", "-%U", "/%U", "*%U", "^%U", + }; + + if (prec <= ARRAY_LEN (binops) - 1 + && unformat_user (i, _unformat_farith, prec + 1, &tmp[0])) + { + int p; + for (p = prec; p < ARRAY_LEN (binops); p++) + { + if (unformat (i, binops[p], _unformat_farith, prec + 0, &tmp[1])) + { + switch (binops[p][0]) + { + case '+': + result[0] = tmp[0] + tmp[1]; + break; + case '-': + result[0] = tmp[0] - tmp[1]; + break; + case '/': + result[0] = tmp[0] / tmp[1]; + break; + case '*': + result[0] = tmp[0] * tmp[1]; + break; + case '^': + result[0] = pow (tmp[0], tmp[1]); + break; + default: + abort (); + } + return 1; + } + } + result[0] = tmp[0]; + return 1; + } + + else if (unformat (i, "-%U", _unformat_farith, prec + 0, &tmp[0])) + { + result[0] = -tmp[0]; + return 1; + } + + else if (unformat (i, "(%U)", _unformat_farith, 0, &tmp[0])) + { + result[0] = tmp[0]; + return 1; + } + + else if (unformat (i, "%f", result)) + return 1; + + else + return 0; +} + +static uword +unformat_farith (unformat_input_t * i, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + f64 *result = va_arg (*args, f64 *); + return unformat_user (i, _unformat_farith, 0, result); +} + +static uword +unformat_integer (unformat_input_t * i, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + u32 *data = va_arg (*args, u32 *); + return unformat (i, "%d", data); +} + +static VLIB_CLI_PARSE_RULE (my_parse_rule1) = +{ +.name = "decimal_integer",.short_help = + "a decimal integer",.unformat_function = unformat_integer,.data_size = + sizeof (u32),}; + +static VLIB_CLI_PARSE_RULE (my_parse_rule2) = +{ +.name = "float_expression",.short_help = + "floating point expression",.unformat_function = + unformat_farith,.data_size = sizeof (f64),}; + +static clib_error_t * +bar_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + switch (cmd->function_arg) + { + case 2: + { + u32 *d, *e; + d = vlib_cli_get_parse_rule_result (vm, 0); + e = vlib_cli_get_parse_rule_result (vm, 1); + vlib_cli_output (vm, "bar2 %d %d", d[0], e[0]); + break; + } + + case 1: + { + u32 *d = vlib_cli_get_parse_rule_result (vm, 0); + vlib_cli_output (vm, "bar1 %d", d[0]); + break; + } + + case 3: + { + f64 *d = vlib_cli_get_parse_rule_result (vm, 0); + vlib_cli_output (vm, "expr %.6f", d[0]); + } + } + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (bar_command2, static) = { + .path = "bar %decimal_integer", + .short_help = "bar1 command", + .function = bar_command, + .function_arg = 1, +}; +VLIB_CLI_COMMAND (bar_command1, static) = { + .path = "bar %decimal_integer %decimal_integer", + .short_help = "bar2 command", + .function = bar_command, + .function_arg = 2, +}; +VLIB_CLI_COMMAND (bar_command3, static) = { + .path = "zap %float_expression", + .short_help = "bar3 command", + .function = bar_command, + .function_arg = 3, +}; +/* *INDENT-ON* */ + +#endif + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/examples/vlib/mc_test.c b/src/examples/vlib/mc_test.c new file mode 100644 index 00000000000..e84a713cc59 --- /dev/null +++ b/src/examples/vlib/mc_test.c @@ -0,0 +1,384 @@ +/* + * mc_test.c: test program for vlib mc + * + * Copyright (c) 2010 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +typedef struct +{ + u32 min_n_msg_bytes; + u32 max_n_msg_bytes; + u32 tx_serial; + u32 rx_serial; + u32 seed; + u32 verbose; + u32 validate; + u32 window_size; + f64 min_delay, max_delay; + f64 n_packets_to_send; +} mc_test_main_t; + +always_inline u32 +choose_msg_size (mc_test_main_t * tm) +{ + u32 r = tm->min_n_msg_bytes; + if (tm->max_n_msg_bytes > tm->min_n_msg_bytes) + r += + random_u32 (&tm->seed) % (1 + tm->max_n_msg_bytes - + tm->min_n_msg_bytes); + return r; +} + +static mc_test_main_t mc_test_main; + +static void +serialize_test_msg (serialize_main_t * m, va_list * va) +{ + mc_test_main_t *tm = &mc_test_main; + u32 n_bytes = choose_msg_size (tm); + u8 *msg; + int i; + serialize_integer (m, n_bytes, sizeof (n_bytes)); + msg = serialize_get (m, n_bytes); + for (i = 0; i < n_bytes; i++) + msg[i] = i + tm->tx_serial; + tm->tx_serial += n_bytes; +} + +static void +unserialize_test_msg (serialize_main_t * m, va_list * va) +{ + mc_test_main_t *tm = &mc_test_main; + u32 i, n_bytes, dump_msg = tm->verbose; + u8 *p; + unserialize_integer (m, &n_bytes, sizeof (n_bytes)); + p = unserialize_get (m, n_bytes); + if (tm->validate) + for (i = 0; i < n_bytes; i++) + if (p[i] != ((tm->rx_serial + i) & 0xff)) + { + clib_warning ("corrupt msg at offset %d", i); + dump_msg = 1; + break; + } + if (dump_msg) + clib_warning ("got %d bytes, %U", n_bytes, format_hex_bytes, p, n_bytes); + tm->rx_serial += n_bytes; +} + +MC_SERIALIZE_MSG (test_msg, static) = +{ +.name = "test_msg",.serialize = serialize_test_msg,.unserialize = + unserialize_test_msg,}; + +#define SERIALIZE 1 + +#define EVENT_JOIN_STREAM 10 +#define EVENT_SEND_DATA 11 + +static void +test_rx_callback (mc_main_t * mcm, + mc_stream_t * stream, + mc_peer_id_t peer_id, u32 buffer_index) +{ + if (SERIALIZE) + { + return mc_unserialize (mcm, stream, buffer_index); + } + else + { +#if DEBUG > 1 + vlib_main_t *vm = mcm->vlib_main; + vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index); + u8 *dp = vlib_buffer_get_current (b); + + fformat (stdout, "RX from %U %U\n", + stream->transport->format_peer_id, peer_id, + format_hex_bytes, dp, tm->n_msg_bytes); + +#endif + } +} + +static u8 * +test_snapshot_callback (mc_main_t * mcm, + u8 * data_vector, u32 last_global_sequence_processed) +{ + if (SERIALIZE) + { + serialize_main_t m; + + /* Append serialized data to data vector. */ + serialize_open_vector (&m, data_vector); + m.stream.current_buffer_index = vec_len (data_vector); + + return serialize_close_vector (&m); + } + else + return format (data_vector, + "snapshot, last global seq 0x%x", + last_global_sequence_processed); +} + +static void +test_handle_snapshot_callback (mc_main_t * mcm, u8 * data, u32 n_data_bytes) +{ + if (SERIALIZE) + { + serialize_main_t s; + unserialize_open_data (&s, data, n_data_bytes); + } + else + clib_warning ("snapshot `%*s'", n_data_bytes, data); +} + +static mc_socket_main_t mc_socket_main; + +static uword +mc_test_process (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * f) +{ + mc_test_main_t *tm = &mc_test_main; + mc_socket_main_t *msm = &mc_socket_main; + mc_main_t *mcm = &msm->mc_main; + uword event_type, *event_data = 0; + u32 data_serial = 0, stream_index; + f64 delay; + mc_stream_config_t config; + clib_error_t *error; + int i; + char *intfcs[] = { "eth1", "eth0", "ce" }; + + memset (&config, 0, sizeof (config)); + config.name = "test"; + config.window_size = tm->window_size; + config.rx_buffer = test_rx_callback; + config.catchup_snapshot = test_snapshot_callback; + config.catchup = test_handle_snapshot_callback; + stream_index = ~0; + + msm->multicast_tx_ip4_address_host_byte_order = 0xefff0100; + msm->base_multicast_udp_port_host_byte_order = 0xffab; + + error = mc_socket_main_init (&mc_socket_main, intfcs, ARRAY_LEN (intfcs)); + if (error) + { + clib_error_report (error); + exit (1); + } + + mcm->we_can_be_relay_master = 1; + + while (1) + { + vlib_process_wait_for_event (vm); + event_type = vlib_process_get_events (vm, &event_data); + + switch (event_type) + { + case EVENT_JOIN_STREAM: + stream_index = mc_stream_join (mcm, &config); + break; + + case EVENT_SEND_DATA: + { + f64 times[2]; + + if (stream_index == ~0) + stream_index = mc_stream_join (mcm, &config); + + times[0] = vlib_time_now (vm); + for (i = 0; i < event_data[0]; i++) + { + u32 bi; + if (SERIALIZE) + { + mc_serialize_stream (mcm, stream_index, &test_msg, + data_serial); + } + else + { + u8 *mp; + mp = mc_get_vlib_buffer (vm, sizeof (mp[0]), &bi); + mp[0] = data_serial; + mc_stream_send (mcm, stream_index, bi); + } + if (tm->min_delay > 0) + { + delay = + tm->min_delay + + random_f64 (&tm->seed) * (tm->max_delay - + tm->min_delay); + vlib_process_suspend (vm, delay); + } + data_serial++; + } + times[1] = vlib_time_now (vm); + clib_warning ("done sending %d; %.4e per sec", + event_data[0], + (f64) event_data[0] / (times[1] - times[0])); + break; + } + + default: + clib_warning ("bug"); + break; + } + + if (event_data) + _vec_len (event_data) = 0; + } +} + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (mc_test_process_node, static) = +{ +.function = mc_test_process,.type = VLIB_NODE_TYPE_PROCESS,.name = + "mc-test-process",}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_test_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + f64 npkts = 10; + + if (unformat (input, "join")) + { + vlib_cli_output (vm, "Join stream...\n"); + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_JOIN_STREAM, 0); + return 0; + } + else if (unformat (input, "send %f", &npkts) || unformat (input, "send")) + { + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_SEND_DATA, (uword) npkts); + vlib_cli_output (vm, "Send %.0f pkts...\n", npkts); + + return 0; + } + else + return unformat_parse_error (input); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_mc_command, static) = +{ +.path = "test mc",.short_help = "Test mc command",.function = + mc_test_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_show_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + mc_main_t *mcm = &mc_socket_main.mc_main; + vlib_cli_output (vm, "%U", format_mc_main, mcm); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (show_mc_command, static) = +{ +.path = "show mc",.short_help = "Show mc command",.function = + mc_show_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_clear_command (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + mc_main_t *mcm = &mc_socket_main.mc_main; + mc_clear_stream_stats (mcm); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (clear_mc_command, static) = +{ +.path = "clear mc",.short_help = "Clear mc command",.function = + mc_clear_command,}; +/* *INDENT-ON* */ + +static clib_error_t * +mc_config (vlib_main_t * vm, unformat_input_t * input) +{ + mc_test_main_t *tm = &mc_test_main; + mc_socket_main_t *msm = &mc_socket_main; + clib_error_t *error = 0; + + tm->min_n_msg_bytes = 4; + tm->max_n_msg_bytes = 4; + tm->window_size = 8; + tm->seed = getpid (); + tm->verbose = 0; + tm->validate = 1; + tm->min_delay = 10e-6; + tm->max_delay = 10e-3; + tm->n_packets_to_send = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "interface %s", &msm->multicast_interface_name)) + ; + + else if (unformat (input, "n-bytes %d", &tm->max_n_msg_bytes)) + tm->min_n_msg_bytes = tm->max_n_msg_bytes; + else if (unformat (input, "max-n-bytes %d", &tm->max_n_msg_bytes)) + ; + else if (unformat (input, "min-n-bytes %d", &tm->min_n_msg_bytes)) + ; + else if (unformat (input, "seed %d", &tm->seed)) + ; + else if (unformat (input, "window %d", &tm->window_size)) + ; + else if (unformat (input, "verbose")) + tm->verbose = 1; + else if (unformat (input, "no-validate")) + tm->validate = 0; + else if (unformat (input, "min-delay %f", &tm->min_delay)) + ; + else if (unformat (input, "max-delay %f", &tm->max_delay)) + ; + else if (unformat (input, "no-delay")) + tm->min_delay = tm->max_delay = 0; + else if (unformat (input, "n-packets %f", &tm->n_packets_to_send)) + ; + + else + return clib_error_return (0, "unknown input `%U'", + format_unformat_error, input); + } + + if (tm->n_packets_to_send > 0) + vlib_process_signal_event (vm, mc_test_process_node.index, + EVENT_SEND_DATA, + (uword) tm->n_packets_to_send); + + return error; +} + +VLIB_CONFIG_FUNCTION (mc_config, "mc"); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/examples/vlib/plex_test.c b/src/examples/vlib/plex_test.c new file mode 100644 index 00000000000..ce0c8ef1141 --- /dev/null +++ b/src/examples/vlib/plex_test.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +static u8 * +format_value_v4_address (u8 * s, va_list * args) +{ + vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); + u32 a = v->value.as_uword; + + s = format (s, "%d.%d.%d.%d", + (a >> 24) & 0xFF, + (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a >> 0) & 0xFF); + + return s; +} + +static vlib_parse_match_t +v4_address_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, + vlib_lex_token_t * t, vlib_parse_value_t * valuep) +{ + u32 digit; + u32 value = 0; + int i; + + if (vec_len (pm->tokens) - (t - pm->tokens) < 7) + return VLIB_PARSE_MATCH_FAIL; + + /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ + + for (i = 0; i < 7; i++) + { + if ((i & 1) == 0) + { + if (t[i].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + if (t[i].value.as_uword > 0xff) + return VLIB_PARSE_MATCH_FAIL; + digit = t[i].value.as_uword; + value = (value << 8) | digit; + } + else + { + if (t[i].token != VLIB_LEX_dot) + return VLIB_PARSE_MATCH_FAIL; + } + } + /* note: caller advances by 1 */ + pm->current_token_index += 6; + valuep->value.as_uword = value; + return VLIB_PARSE_MATCH_VALUE; +} + +PARSE_TYPE_INIT (v4_address, v4_address_match, 0, format_value_v4_address) + static u8 *format_value_v4_address_and_mask (u8 * s, va_list * args) +{ + vlib_parse_value_t *v = va_arg (*args, vlib_parse_value_t *); + u32 *a = v->value.as_pointer; + + s = format (s, "%d.%d.%d.%d", + (a[0] >> 24) & 0xFF, + (a[0] >> 16) & 0xFF, (a[0] >> 8) & 0xFF, (a[0] >> 0) & 0xFF); + s = format (s, "/%d", a[1]); + + return s; +} + +static vlib_parse_match_t +v4_address_and_mask_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, + vlib_lex_token_t * t, vlib_parse_value_t * valuep) +{ + u32 digit; + u32 address = 0; + u32 *rv = 0; + int i; + + if (vec_len (pm->tokens) - (t - pm->tokens) < 9) + return VLIB_PARSE_MATCH_FAIL; + + /* NUMBER DOT NUMBER DOT NUMBER DOT NUMBER */ + + for (i = 0; i < 7; i++) + { + if ((i & 1) == 0) + { + if (t[i].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + if (t[i].value.as_uword > 0xff) + return VLIB_PARSE_MATCH_FAIL; + digit = t[i].value.as_uword; + address = (address << 8) | digit; + } + else + { + if (t[i].token != VLIB_LEX_dot) + return VLIB_PARSE_MATCH_FAIL; + } + } + + if (t[7].token != VLIB_LEX_slash || t[8].token != VLIB_LEX_number) + return VLIB_PARSE_MATCH_FAIL; + + vec_add1 (rv, address); + vec_add1 (rv, t[8].value.as_uword); + + /* note: caller advances by 1 */ + pm->current_token_index += 8; + valuep->value.as_pointer = rv; + return VLIB_PARSE_MATCH_VALUE; +} + +void +v4_address_and_mask_cleanup (vlib_parse_value_t * valuep) +{ + u32 *trash = valuep->value.as_pointer; + vec_free (trash); +} + +PARSE_TYPE_INIT (v4_address_and_mask, v4_address_and_mask_match, + v4_address_and_mask_cleanup, + format_value_v4_address_and_mask) + vlib_lex_main_t vlib_lex_main; + + + + vlib_parse_match_t eval_factor0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, + vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_factor1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_factor2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + word a; + int index = vec_len (pm->parse_value) - 1; + + a = pm->parse_value[index].value.as_word; + + pm->parse_value[index].value.as_word = -a; + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a * b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_term2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a / b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp0 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp1 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a + b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_exp2 (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + uword a, b; + int index = vec_len (pm->parse_value) - 2; + + a = pm->parse_value[index].value.as_uword; + b = pm->parse_value[index + 1].value.as_uword; + + pm->parse_value[index].value.as_uword = a - b; + _vec_len (pm->parse_value) -= 1; + clib_warning ("%U", format_vlib_parse_value, pm); + + return VLIB_PARSE_MATCH_RULE; +} + +vlib_parse_match_t +eval_result (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_DONE; +} + +vlib_parse_match_t +noop_match_rule (vlib_parse_main_t * pm, + vlib_parse_item_t * item, vlib_parse_value_t * value) +{ + clib_warning ("%U", format_vlib_parse_value, pm); + return VLIB_PARSE_MATCH_RULE; +} + +#if 0 +PARSE_INIT (t1, "moo", eval0); +PARSE_INIT (t2, "moo cow mumble", eval1); +PARSE_INIT (t3, "moo cow", eval2); +PARSE_INIT (t4, "moo cow mumble grunch", eval3); +#endif + +#if 0 +PARSE_INIT (r1, "eval ", eval_result); + +PARSE_INIT (r2, " = ", eval_exp0); +PARSE_INIT (r3, " = ", eval_exp1); +PARSE_INIT (r4, " = ", eval_exp2); +PARSE_INIT (r5, " = ", noop_match_rule); +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_TYPE_INIT (exp2, rule_match, 0, 0); + +PARSE_INIT (r6, " = ", eval_term0); +PARSE_INIT (r7, " = ", eval_term1); +PARSE_INIT (r8, " = ", eval_term2); +PARSE_INIT (r9, " = ", noop_match_rule); +PARSE_TYPE_INIT (term, rule_match, 0, 0); +PARSE_TYPE_INIT (term2, rule_match, 0, 0); + +PARSE_INIT (r11, " = ", eval_factor1); +PARSE_INIT (r10, " = ", eval_factor0); +PARSE_INIT (r12, " = ", eval_factor2); + +PARSE_TYPE_INIT (factor, rule_match, 0, 0); +#endif + +PARSE_INIT (r1, "eval ", eval_result); + +#if 1 +PARSE_INIT (r2, " = ", eval_exp0); +PARSE_INIT (r3, " = ", eval_exp1); +PARSE_INIT (r4, " = ", eval_exp2); +PARSE_INIT (r5, " = ", noop_match_rule); +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_TYPE_INIT (exp2, rule_match, 0, 0); + +PARSE_INIT (r6, " = ", eval_term0); +PARSE_INIT (r7, " = ", eval_term1); +PARSE_INIT (r8, " = ", eval_term2); +PARSE_INIT (r9, " = ", noop_match_rule); +PARSE_TYPE_INIT (term, rule_match, 0, 0); +PARSE_TYPE_INIT (term2, rule_match, 0, 0); + +PARSE_INIT (r11, " = ", eval_factor1); +PARSE_INIT (r10, " = ", eval_factor0); +PARSE_INIT (r12, " = ", eval_factor2); + +PARSE_TYPE_INIT (factor, rule_match, 0, 0); +#endif + +#if 0 +PARSE_TYPE_INIT (exp, rule_match, 0, 0); +PARSE_INIT (r6, " = a b", eval_term0); +PARSE_INIT (r7, " = c d", eval_term1); +PARSE_INIT (r9, " = ", noop_match_rule); +#endif + +#if 0 +#define foreach_rule_evaluator \ +_(0) \ +_(1) \ +_(2) \ +_(3) + +#define _(n) \ +vlib_parse_match_t eval##n (vlib_parse_main_t *pm, \ + vlib_parse_item_t *item, \ + vlib_parse_value_t *value) \ +{ \ + clib_warning ("%U", format_vlib_parse_value, pm); \ + return VLIB_PARSE_MATCH_DONE; \ +} +foreach_rule_evaluator +#undef _ +PARSE_INIT (r1, "eval ", eval_result); + +PARSE_INIT (r2, " = cow", eval0); +PARSE_INIT (r4, " = ", eval1); +PARSE_TYPE_INIT (moo, rule_match, 0, 0); +#endif + + +clib_error_t * +test_init (vlib_main_t * vm) +{ + clib_error_t *error; + + if ((error = vlib_call_init_function (vm, parse_init))) + return error; + + return 0; +} + +VLIB_INIT_FUNCTION (test_init); + +clib_error_t * +vlib_stdlex_init (vlib_main_t * vm) +{ + vlib_lex_main_t *lm = &vlib_lex_main; + u16 top_index; + u16 slash_index, slash_star_index, slash_slash_index, slash_star_star_index; + u16 slash_token; + u16 word_index; + u16 zero_index, octal_index, decimal_index, hex_index, binary_index; + + top_index = vlib_lex_add_table ("top"); + +#define foreach_top_level_single_character_token \ + _('(', lpar) \ + _(')', rpar) \ + _(';', semi) \ + _('[', lbrack) \ + _(']', rbrack) \ + _('{', lcurly) \ + _('}', rcurly) \ + _('+', plus) \ + _('-', minus) \ + _('*', star) \ + _('%', percent) \ + _('@', atsign) \ + _(',', comma) \ + _('.', dot) \ + _('?', qmark) + +#define _(c,t) \ + vlib_lex_set_action_range(top_index,c,c,VLIB_LEX_RETURN,vlib_lex_add_token(lm, #t), top_index); + foreach_top_level_single_character_token; +#undef _ + + /* Numbers */ + zero_index = vlib_lex_add_table ("zero"); + octal_index = vlib_lex_add_table ("octal"); + decimal_index = vlib_lex_add_table ("decimal"); + hex_index = vlib_lex_add_table ("hex"); + binary_index = vlib_lex_add_table ("binary"); + + /* Support 0x 0b 0t and 0123 [octal] */ + vlib_lex_set_action_range (top_index, '0', '0', VLIB_LEX_START_NUMBER, 10, + zero_index); + vlib_lex_set_action_range (top_index, '1', '9', VLIB_LEX_START_NUMBER, 10, + decimal_index); + + vlib_lex_set_action_range (zero_index, 0, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + + vlib_lex_set_action_range (zero_index, 'x', 'x', VLIB_LEX_IGNORE, ~0, + hex_index); + vlib_lex_set_action_range (zero_index, 'b', 'b', VLIB_LEX_IGNORE, ~0, + binary_index); + vlib_lex_set_action_range (zero_index, 't', 't', VLIB_LEX_IGNORE, ~0, + decimal_index); + vlib_lex_set_action_range (zero_index, '0', '7', VLIB_LEX_START_NUMBER, 8, + octal_index); + + /* Octal */ + vlib_lex_set_action_range (octal_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + vlib_lex_set_action_range (octal_index, '0', '7', VLIB_LEX_ADD_TO_NUMBER, 8, + octal_index); + + /* Decimal */ + vlib_lex_set_action_range (decimal_index, 0, 0x7f, + VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, + top_index); + vlib_lex_set_action_range (decimal_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, + 10, decimal_index); + + /* Hex */ + vlib_lex_set_action_range (hex_index, 0, 0x7f, VLIB_LEX_RETURN_AND_RESCAN, + VLIB_LEX_number, top_index); + vlib_lex_set_action_range (hex_index, '0', '9', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + vlib_lex_set_action_range (hex_index, 'a', 'f', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + vlib_lex_set_action_range (hex_index, 'A', 'F', VLIB_LEX_ADD_TO_NUMBER, 16, + hex_index); + + /* Binary */ + vlib_lex_set_action_range (binary_index, 0, 0x7f, + VLIB_LEX_RETURN_AND_RESCAN, VLIB_LEX_number, + top_index); + vlib_lex_set_action_range (binary_index, '0', '1', VLIB_LEX_ADD_TO_NUMBER, + 2, binary_index); + + /* c/c++ comment syntax is the worst... */ + + slash_index = vlib_lex_add_table ("slash"); + slash_star_index = vlib_lex_add_table ("slash_star"); + slash_star_star_index = vlib_lex_add_table ("slash_star_star"); + slash_slash_index = vlib_lex_add_table ("slash_slash"); + slash_token = vlib_lex_add_token (lm, "slash"); + + /* Top level: see a slash, ignore, go to slash table */ + vlib_lex_set_action_range (top_index, '/', '/', VLIB_LEX_IGNORE, ~0, + slash_index); + + /* default for slash table: return SLASH, go to top table */ + vlib_lex_set_action_range (slash_index, 1, 0x7F, VLIB_LEX_RETURN_AND_RESCAN, + slash_token, top_index); + /* see slash-slash, go to s-s table */ + vlib_lex_set_action_range (slash_index, '/', '/', VLIB_LEX_IGNORE, ~0, + slash_slash_index); + /* see slash-star, go to s-* table */ + vlib_lex_set_action_range (slash_index, '*', '*', VLIB_LEX_IGNORE, ~0, + slash_star_index); + + /* EOL in s-s table, ignore, go to top table */ + vlib_lex_set_action_range (slash_slash_index, '\n', '\n', VLIB_LEX_IGNORE, + ~0, top_index); + + /* slash-star blah blah star */ + vlib_lex_set_action_range (slash_star_index, '*', '*', VLIB_LEX_IGNORE, ~0, + slash_star_star_index); + + /* slash star blah blah star slash */ + vlib_lex_set_action_range (slash_star_star_index, '/', '/', VLIB_LEX_IGNORE, + ~0, top_index); + + /* LT, =, GT */ + vlib_lex_set_action_range (top_index, '<', '<', VLIB_LEX_RETURN, + VLIB_LEX_lt, top_index); + vlib_lex_set_action_range (top_index, '=', '=', VLIB_LEX_RETURN, + VLIB_LEX_equals, top_index); + vlib_lex_set_action_range (top_index, '>', '>', VLIB_LEX_RETURN, + VLIB_LEX_gt, top_index); + + /* words, key and otherwise */ + word_index = vlib_lex_add_table ("word"); + + vlib_lex_set_action_range (top_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (top_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + + vlib_lex_set_action_range (word_index, 0, 0x7f, VLIB_LEX_KEYWORD_CHECK, ~0, + top_index); + + vlib_lex_set_action_range (word_index, 'a', 'z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, 'A', 'Z', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, '_', '_', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + vlib_lex_set_action_range (word_index, '0', '9', VLIB_LEX_ADD_TO_TOKEN, ~0, + word_index); + + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/g2.am b/src/g2.am new file mode 100644 index 00000000000..e79657335fe --- /dev/null +++ b/src/g2.am @@ -0,0 +1,32 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +bin_PROGRAMS += g2 + +g2_SOURCES = \ + tools/g2/clib.c \ + tools/g2/cpel.c \ + tools/g2/cpel.h \ + tools/g2/events.c \ + tools/g2/g2.h \ + tools/g2/main.c \ + tools/g2/menu1.c \ + tools/g2/pointsel.c \ + tools/g2/props.c \ + tools/g2/props.h \ + tools/g2/g2version.c \ + tools/g2/view1.c + +g2_LDADD = $(g2_LIBS) libvppinfra.la -lpthread -lm + +# vi:syntax=automake diff --git a/src/perftool.am b/src/perftool.am new file mode 100644 index 00000000000..09f1681a7e3 --- /dev/null +++ b/src/perftool.am @@ -0,0 +1,41 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +bin_PROGRAMS += c2cpel cpelatency cpeldump cpelinreg cpelstate + +lib_LTLIBRARIES += libcperf.la + +libcperf_la_SOURCES = \ + tools/perftool/delsvec.c \ + tools/perftool/linreg.c \ + tools/perftool/props.c \ + tools/perftool/cpel_util.c + +PERFTOOL_LIBS = libcperf.la libvppinfra.la -lm + +c2cpel_SOURCES = tools/perftool/c2cpel.c +c2cpel_LDADD = $(PERFTOOL_LIBS) + +cpelatency_SOURCES = tools/perftool/cpelatency.c +cpelatency_LDADD = $(PERFTOOL_LIBS) + +cpeldump_SOURCES = tools/perftool/cpeldump.c +cpeldump_LDADD = $(PERFTOOL_LIBS) + +cpelinreg_SOURCES = tools/perftool/cpelinreg.c +cpelinreg_LDADD = $(PERFTOOL_LIBS) + +cpelstate_SOURCES = tools/perftool/cpelstate.c +cpelstate_LDADD = $(PERFTOOL_LIBS) + +# vi:syntax=automake diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am new file mode 100644 index 00000000000..ffc4b3abddc --- /dev/null +++ b/src/plugins/Makefile.am @@ -0,0 +1,60 @@ + +# Copyright (c) +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AUTOMAKE_OPTIONS = foreign subdir-objects + +AM_CFLAGS = -Wall -I${top_srcdir} -I${top_builddir} +AM_LDFLAGS = -module -shared -avoid-version +SUFFIXES = .api.h .api .api.json +API_FILES = +BUILT_SOURCES = +vppplugins_LTLIBRARIES = +vppapitestplugins_LTLIBRARIES = +noinst_HEADERS = + +vppapitestpluginsdir = ${libdir}/vpp_api_test_plugins +vpppluginsdir = ${libdir}/vpp_plugins + +if ENABLE_FLOWPERPKT_PLUGIN +include flowperpkt.am +endif + +if ENABLE_ILA_PLUGIN +include ila.am +endif + +if ENABLE_SIXRD_PLUGIN +include sixrd.am +endif + +include ../suffix-rules.mk + +# Remove *.la files +install-data-hook: + @-(cd $(vpppluginsdir) && $(RM) $(vppplugins_LTLIBRARIES)) + @-(cd $(vppapitestpluginsdir) && $(RM) $(vppapitestplugins_LTLIBRARIES)) + +############################################################################### +# API +############################################################################### + +apidir = $(prefix)/share/vpp/api/plugins + +api_DATA = \ + $(patsubst %.api,%.api.json,$(API_FILES)) + +BUILT_SOURCES += \ + $(patsubst %.api,%.api.json,$(API_FILES)) \ + $(patsubst %.api,%.api.h,$(API_FILES)) + diff --git a/src/plugins/flowperpkt.am b/src/plugins/flowperpkt.am new file mode 100644 index 00000000000..a400603a71f --- /dev/null +++ b/src/plugins/flowperpkt.am @@ -0,0 +1,38 @@ + +# Copyright (c) +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +vppplugins_LTLIBRARIES += flowperpkt_plugin.la +vppapitestplugins_LTLIBRARIES += flowperpkt_test_plugin.la + +flowperpkt_plugin_la_SOURCES = flowperpkt/flowperpkt.c \ + flowperpkt/l2_node.c \ + flowperpkt/node.c \ + flowperpkt/flowperpkt_plugin.api.h + +BUILT_SOURCES += \ + flowperpkt/flowperpkt.api.h \ + flowperpkt/flowperpkt.api.json + +noinst_HEADERS += \ + flowperpkt/flowperpkt_all_api_h.h \ + flowperpkt/flowperpkt_msg_enum.h \ + flowperpkt/flowperpkt.api.h + +flowperpkt_test_plugin_la_SOURCES = \ + flowperpkt/flowperpkt_test.c \ + flowperpkt/flowperpkt_plugin.api.h + +API_FILES += flowperpkt/flowperpkt.api + +# vi:syntax=automake diff --git a/src/plugins/flowperpkt/flowperpkt.api b/src/plugins/flowperpkt/flowperpkt.api new file mode 100644 index 00000000000..fa878f21ed3 --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.api @@ -0,0 +1,42 @@ +/* Define a simple enable-disable binary API to control the feature */ + +/** \file + This file defines the vpp control-plane API messages + used to control the flowperpkt plugin +*/ + +/** \brief Enable / disable per-packet IPFIX recording on an interface + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add address if non-zero, else delete + @param is_ipv6 - if non-zero the address is ipv6, else ipv4 + @param sw_if_index - index of the interface +*/ +manual_print define flowperpkt_tx_interface_add_del +{ + /* Client identifier, set from api_main.my_client_index */ + u32 client_index; + + /* Arbitrary context, so client can match reply to request */ + u32 context; + + /* Enable / disable the feature */ + u8 is_add; + u8 which; /* 0 = ipv4, 1 = l2, 2 = ipv6 (not yet implemented) */ + + /* Interface handle */ + u32 sw_if_index; +}; + +/** \brief Reply to enable/disable per-packet IPFIX recording messages + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ +define flowperpkt_tx_interface_add_del_reply +{ + /* From the request */ + u32 context; + + /* Return value, zero means all OK */ + i32 retval; +}; diff --git a/src/plugins/flowperpkt/flowperpkt.c b/src/plugins/flowperpkt/flowperpkt.c new file mode 100644 index 00000000000..fb71d5b0ffc --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.c @@ -0,0 +1,671 @@ +/* + * flowperpkt.c - per-packet data capture flow report plugin + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Per-packet IPFIX flow record generator plugin + * + * This file implements vpp plugin registration mechanics, + * debug CLI, and binary API handling. + */ + +#include +#include +#include + +#include +#include +#include + +/* define message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* define generated endian-swappers */ +#define vl_endianfun +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) +#define vl_printfun +#include +#undef vl_printfun + +flowperpkt_main_t flowperpkt_main; + +/* Get the API version number */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +/* Define the per-interface configurable features */ +/* *INDENT-OFF* */ +VNET_FEATURE_INIT (flow_perpacket_ipv4, static) = +{ + .arc_name = "ip4-output", + .node_name = "flowperpkt-ipv4", + .runs_before = VNET_FEATURES ("interface-output"), +}; + +VNET_FEATURE_INIT (flow_perpacket_l2, static) = +{ + .arc_name = "interface-output", + .node_name = "flowperpkt-l2", + .runs_before = VNET_FEATURES ("interface-tx"), +}; +/* *INDENT-ON* */ + +/* + * A handy macro to set up a message reply. + * Assumes that the following variables are available: + * mp - pointer to request message + * rmp - pointer to reply message type + * rv - return value + */ +#define REPLY_MACRO(t) \ +do { \ + unix_shared_memory_queue_t * q = \ + vl_api_client_index_to_input_queue (mp->client_index); \ + if (!q) \ + return; \ + \ + rmp = vl_msg_api_alloc (sizeof (*rmp)); \ + rmp->_vl_msg_id = ntohs((t)+fm->msg_id_base); \ + rmp->context = mp->context; \ + rmp->retval = ntohl(rv); \ + \ + vl_msg_api_send_shmem (q, (u8 *)&rmp); \ +} while(0); + +/* Macro to finish up custom dump fns */ +#define FINISH \ + vec_add1 (s, 0); \ + vl_print (handle, (char *)s); \ + vec_free (s); \ + return handle; + +#define VALIDATE_SW_IF_INDEX(mp) \ + do { u32 __sw_if_index = ntohl(mp->sw_if_index); \ + vnet_main_t *__vnm = vnet_get_main(); \ + if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \ + __sw_if_index)) { \ + rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; \ + goto bad_sw_if_index; \ + } \ +} while(0); + +#define BAD_SW_IF_INDEX_LABEL \ +do { \ +bad_sw_if_index: \ + ; \ +} while (0); + +/** + * @brief Create an IPFIX template packet rewrite string + * @param frm flow_report_main_t * + * @param fr flow_report_t * + * @param collector_address ip4_address_t * the IPFIX collector address + * @param src_address ip4_address_t * the source address we should use + * @param collector_port u16 the collector port we should use, host byte order + * @returns u8 * vector containing the indicated IPFIX template packet + */ +static inline u8 * +flowperpkt_template_rewrite_inline (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port, int variant) +{ + ip4_header_t *ip; + udp_header_t *udp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + ipfix_template_header_t *t; + ipfix_field_specifier_t *f; + ipfix_field_specifier_t *first_field; + u8 *rewrite = 0; + ip4_ipfix_template_packet_t *tp; + u32 field_count = 0; + flow_report_stream_t *stream; + flowperpkt_main_t *fm = &flowperpkt_main; + + stream = &frm->streams[fr->stream_index]; + + if (variant == FLOW_VARIANT_IPV4) + { + /* + * ip4 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceIpv4Address, TLV type 8, u32 + * destinationIPv4Address, TLV type 12, u32 + * ipClassOfService, TLV type 5, u8 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } + else if (variant == FLOW_VARIANT_L2) + { + /* + * L2 Supported Fields: + * + * ingressInterface, TLV type 10, u32 + * egressInterface, TLV type 14, u32 + * sourceMacAddress, TLV type 56, u8[6] we hope + * destinationMacAddress, TLV type 57, u8[6] we hope + * ethernetType, TLV type 256, u16 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * warning: wireshark doesn't really understand this TLV + * dataLinkFrameSize, TLV type 312, u16 + * warning: wireshark doesn't understand this TLV at all + */ + + /* Currently 7 fields */ + field_count += 7; + + /* allocate rewrite space */ + vec_validate_aligned + (rewrite, + sizeof (ip4_ipfix_template_packet_t) + + field_count * sizeof (ipfix_field_specifier_t) - 1, + CLIB_CACHE_LINE_BYTES); + } + + tp = (ip4_ipfix_template_packet_t *) rewrite; + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + t = (ipfix_template_header_t *) (s + 1); + first_field = f = (ipfix_field_specifier_t *) (t + 1); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->src_address.as_u32 = src_address->as_u32; + ip->dst_address.as_u32 = collector_address->as_u32; + udp->src_port = clib_host_to_net_u16 (stream->src_port); + udp->dst_port = clib_host_to_net_u16 (collector_port); + udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip)); + + /* FIXUP: message header export_time */ + /* FIXUP: message header sequence_number */ + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* Add TLVs to the template */ + if (variant == FLOW_VARIANT_IPV4) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ipClassOfService, + 1); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + else if (variant == FLOW_VARIANT_L2) + { + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , ingressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , egressInterface, + 4); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress, + 6); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6); + f++; + f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType, + 2); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds, + 8); + f++; + f->e_id_length = + ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize, + 2); + f++; + } + + /* Extend in the obvious way, right here... */ + + /* Back to the template packet... */ + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + + ASSERT (f - first_field); + /* Field count in this template */ + t->id_count = ipfix_id_count (fr->template_id, f - first_field); + + if (variant == FLOW_VARIANT_IPV4) + fm->ipv4_report_id = fr->template_id; + else if (variant == FLOW_VARIANT_L2) + fm->l2_report_id = fr->template_id; + + /* set length in octets */ + s->set_id_length = + ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s); + + /* message length in octets */ + h->version_length = version_length ((u8 *) f - (u8 *) h); + + ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip); + ip->checksum = ip4_header_checksum (ip); + + return rewrite; +} + +u8 * +flowperpkt_template_rewrite_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_IPV4); +} + +u8 * +flowperpkt_template_rewrite_l2 (flow_report_main_t * frm, + flow_report_t * fr, + ip4_address_t * collector_address, + ip4_address_t * src_address, + u16 collector_port) +{ + return flowperpkt_template_rewrite_inline + (frm, fr, collector_address, src_address, collector_port, + FLOW_VARIANT_L2); +} + + +/** + * @brief Flush accumulated data + * @param frm flow_report_main_t * + * @param fr flow_report_t * + * @param f vlib_frame_t * + * + * Notes: + * This function must simply return the incoming frame, or no template packets + * will be sent. + */ +vlib_frame_t * +flowperpkt_data_callback_ipv4 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, + u32 node_index) +{ + flowperpkt_flush_callback_ipv4 (); + return f; +} + +vlib_frame_t * +flowperpkt_data_callback_l2 (flow_report_main_t * frm, + flow_report_t * fr, + vlib_frame_t * f, u32 * to_next, u32 node_index) +{ + flowperpkt_flush_callback_l2 (); + return f; +} + +/** + * @brief configure / deconfigure the IPFIX flow-per-packet + * @param fm flowperpkt_main_t * fm + * @param sw_if_index u32 the desired interface + * @param is_add int 1 to enable the feature, 0 to disable it + * @returns 0 if successful, non-zero otherwise + */ + +static int flowperpkt_tx_interface_add_del_feature + (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add) +{ + flow_report_main_t *frm = &flow_report_main; + vnet_flow_report_add_del_args_t _a, *a = &_a; + int rv; + + if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created) + { + memset (a, 0, sizeof (*a)); + a->rewrite_callback = flowperpkt_template_rewrite_ipv4; + a->flow_data_callback = flowperpkt_data_callback_ipv4; + a->is_add = 1; + a->domain_id = 1; /*$$$$ config parameter */ + a->src_port = 4739; /*$$$$ config parameter */ + fm->ipv4_report_created = 1; + + rv = vnet_flow_report_add_del (frm, a); + if (rv) + { + clib_warning ("vnet_flow_report_add_del returned %d", rv); + return -1; + } + } + else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created) + { + memset (a, 0, sizeof (*a)); + a->rewrite_callback = flowperpkt_template_rewrite_l2; + a->flow_data_callback = flowperpkt_data_callback_l2; + a->is_add = 1; + a->domain_id = 1; /*$$$$ config parameter */ + a->src_port = 4739; /*$$$$ config parameter */ + fm->l2_report_created = 1; + + rv = vnet_flow_report_add_del (frm, a); + if (rv) + { + clib_warning ("vnet_flow_report_add_del returned %d", rv); + return -1; + } + } + + if (which == FLOW_VARIANT_IPV4) + vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4", + sw_if_index, is_add, 0, 0); + else if (which == FLOW_VARIANT_L2) + vnet_feature_enable_disable ("interface-output", "flowperpkt-l2", + sw_if_index, is_add, 0, 0); + + return 0; +} + +/** + * @brief API message handler + * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message + */ +void vl_api_flowperpkt_tx_interface_add_del_t_handler + (vl_api_flowperpkt_tx_interface_add_del_t * mp) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + vl_api_flowperpkt_tx_interface_add_del_reply_t *rmp; + u32 sw_if_index = ntohl (mp->sw_if_index); + int rv = 0; + + VALIDATE_SW_IF_INDEX (mp); + + if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2) + { + rv = VNET_API_ERROR_UNIMPLEMENTED; + goto out; + } + + rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which, + mp->is_add); +out: + BAD_SW_IF_INDEX_LABEL; + + REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY); +} + +/** + * @brief API message custom-dump function + * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message + * @param handle void * print function handle + * @returns u8 * output string + */ +static void *vl_api_flowperpkt_tx_interface_add_del_t_print + (vl_api_flowperpkt_tx_interface_add_del_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del "); + s = format (s, "sw_if_index %d is_add %d which %d ", + clib_host_to_net_u32 (mp->sw_if_index), + (int) mp->is_add, (int) mp->which); + FINISH; +} + +/* List of message types that this plugin understands */ +#define foreach_flowperpkt_plugin_api_msg \ +_(FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del) + +/** + * @brief plugin-api required function + * @param vm vlib_main_t * vlib main data structure pointer + * @param h vlib_plugin_handoff_t * handoff structure + * @param from_early_init int notused + * + * Notes: + * This routine exists to convince the vlib plugin framework that + * we haven't accidentally copied a random .dll into the plugin directory. + * + * Also collects global variable pointers passed from the vpp engine + */ +clib_error_t * +vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, + int from_early_init) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + clib_error_t *error = 0; + + fm->vlib_main = vm; + fm->vnet_main = h->vnet_main; + + return error; +} + +static clib_error_t * +flowperpkt_tx_interface_add_del_feature_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + u32 sw_if_index = ~0; + int is_add = 1; + u8 which = FLOW_VARIANT_IPV4; + + int rv; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "disable")) + is_add = 0; + else if (unformat (input, "%U", unformat_vnet_sw_interface, + fm->vnet_main, &sw_if_index)); + else if (unformat (input, "l2")) + which = FLOW_VARIANT_L2; + else + break; + } + + if (sw_if_index == ~0) + return clib_error_return (0, "Please specify an interface..."); + + rv = + flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add); + switch (rv) + { + case 0: + break; + + case VNET_API_ERROR_INVALID_SW_IF_INDEX: + return clib_error_return + (0, "Invalid interface, only works on physical ports"); + break; + + case VNET_API_ERROR_UNIMPLEMENTED: + return clib_error_return (0, "ip6 not supported"); + break; + + default: + return clib_error_return (0, "flowperpkt_enable_disable returned %d", + rv); + } + return 0; +} + +/*? + * 'flowperpkt feature add-del' commands to enable/disable + * per-packet IPFIX flow record generation on an interface + * + * @cliexpar + * @parblock + * To enable per-packet IPFIX flow-record generation on an interface: + * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0} + * + * To disable per-packet IPFIX flow-record generation on an interface: + * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0 disable} + * @cliexend + * @endparblock +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (flowperpkt_enable_disable_command, static) = { + .path = "flowperpkt feature add-del", + .short_help = + "flowperpkt feature add-del [disable]", + .function = flowperpkt_tx_interface_add_del_feature_command_fn, +}; +/* *INDENT-ON* */ + +/** + * @brief Set up the API message handling tables + * @param vm vlib_main_t * vlib main data structure pointer + * @returns 0 to indicate all is well + */ +static clib_error_t * +flowperpkt_plugin_api_hookup (vlib_main_t * vm) +{ + flowperpkt_main_t *fm = &flowperpkt_main; +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + fm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_flowperpkt_plugin_api_msg; +#undef _ + + return 0; +} + +#define vl_msg_name_crc_list +#include +#undef vl_msg_name_crc_list + +static void +setup_message_id_table (flowperpkt_main_t * fm, api_main_t * am) +{ +#define _(id,n,crc) \ + vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base); + foreach_vl_msg_name_crc_flowperpkt; +#undef _ +} + +/** + * @brief Set up the API message handling tables + * @param vm vlib_main_t * vlib main data structure pointer + * @returns 0 to indicate all is well, or a clib_error_t + */ +static clib_error_t * +flowperpkt_init (vlib_main_t * vm) +{ + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_thread_main_t *tm = &vlib_thread_main; + clib_error_t *error = 0; + u32 num_threads; + u8 *name; + + /* Construct the API name */ + name = format (0, "flowperpkt_%08x%c", api_version, 0); + + /* Ask for a correctly-sized block of API message decode slots */ + fm->msg_id_base = vl_msg_api_get_msg_ids + ((char *) name, VL_MSG_FIRST_AVAILABLE); + + /* Hook up message handlers */ + error = flowperpkt_plugin_api_hookup (vm); + + /* Add our API messages to the global name_crc hash table */ + setup_message_id_table (fm, &api_main); + + vec_free (name); + + /* Decide how many worker threads we have */ + num_threads = 1 /* main thread */ + tm->n_eal_threads; + + /* Allocate per worker thread vectors */ + vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1); + vec_validate (fm->l2_buffers_per_worker, num_threads - 1); + vec_validate (fm->ipv4_frames_per_worker, num_threads - 1); + vec_validate (fm->l2_frames_per_worker, num_threads - 1); + vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1); + vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1); + + /* Set up time reference pair */ + fm->vlib_time_0 = vlib_time_now (vm); + fm->nanosecond_time_0 = unix_time_now_nsec (); + + return error; +} + +VLIB_INIT_FUNCTION (flowperpkt_init); + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/flowperpkt.h b/src/plugins/flowperpkt/flowperpkt.h new file mode 100644 index 00000000000..20f6939dda5 --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt.h @@ -0,0 +1,90 @@ +/* + * flowperpkt.h - skeleton vpp engine plug-in header file + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_flowperpkt_h__ +#define __included_flowperpkt_h__ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * @file + * @brief flow-per-packet plugin header file + */ +typedef struct +{ + /** API message ID base */ + u16 msg_id_base; + + /** Have the reports [templates] been created? */ + int ipv4_report_created; + int l2_report_created; + + /** stream/template IDs */ + u16 ipv4_report_id; + u16 l2_report_id; + + /** ipfix buffers under construction, per-worker thread */ + vlib_buffer_t **ipv4_buffers_per_worker; + vlib_buffer_t **l2_buffers_per_worker; + + /** frames containing ipfix buffers, per-worker thread */ + vlib_frame_t **ipv4_frames_per_worker; + vlib_frame_t **l2_frames_per_worker; + + /** next record offset, per worker thread */ + u16 *ipv4_next_record_offset_per_worker; + u16 *l2_next_record_offset_per_worker; + + /** Time reference pair */ + u64 nanosecond_time_0; + f64 vlib_time_0; + + /** convenience vlib_main_t pointer */ + vlib_main_t *vlib_main; + /** convenience vnet_main_t pointer */ + vnet_main_t *vnet_main; +} flowperpkt_main_t; + +typedef enum +{ + FLOW_VARIANT_IPV4, + FLOW_VARIANT_L2, + FLOW_N_VARIANTS, +} flowperpkt_variant_t; + +extern flowperpkt_main_t flowperpkt_main; + +extern vlib_node_registration_t flowperpkt_ipv4_node; + +void flowperpkt_flush_callback_ipv4 (void); +void flowperpkt_flush_callback_l2 (void); + +#endif /* __included_flowperpkt_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/flowperpkt_all_api_h.h b/src/plugins/flowperpkt/flowperpkt_all_api_h.h new file mode 100644 index 00000000000..329c375abca --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_all_api_h.h @@ -0,0 +1,18 @@ +/* + * flowperpkt_all_api_h.h - plug-in api #include file + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Include the generated file, see BUILT_SOURCES in Makefile.am */ +#include diff --git a/src/plugins/flowperpkt/flowperpkt_msg_enum.h b/src/plugins/flowperpkt/flowperpkt_msg_enum.h new file mode 100644 index 00000000000..3177e77a63b --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_msg_enum.h @@ -0,0 +1,31 @@ +/* + * flowperpkt_msg_enum.h - vpp engine plug-in message enumeration + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef included_flowperpkt_msg_enum_h +#define included_flowperpkt_msg_enum_h + +#include + +#define vl_msg_id(n,h) n, +typedef enum +{ +#include + /* We'll want to know how many messages IDs we need... */ + VL_MSG_FIRST_AVAILABLE, +} vl_msg_id_t; +#undef vl_msg_id + +#endif /* included_flowperpkt_msg_enum_h */ diff --git a/src/plugins/flowperpkt/flowperpkt_plugin_doc.md b/src/plugins/flowperpkt/flowperpkt_plugin_doc.md new file mode 100644 index 00000000000..ed76c45c2dc --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_plugin_doc.md @@ -0,0 +1,13 @@ +Per-packet IPFIX flow record plugin {#flowperpkt_plugin_doc} +=================================== + +## Introduction + +This plugin generates one ipfix record entry per packet transmitted +on interfaces which have the feature enabled + +## Sample configuration + +set ipfix exporter collector 192.168.6.2 src 192.168.6.1 template-interval 20 port 4739 path-mtu 1500 + +flowperpkt feature add-del GigabitEthernet2/3/0 diff --git a/src/plugins/flowperpkt/flowperpkt_test.c b/src/plugins/flowperpkt/flowperpkt_test.c new file mode 100644 index 00000000000..716818ffe0a --- /dev/null +++ b/src/plugins/flowperpkt/flowperpkt_test.c @@ -0,0 +1,234 @@ +/* + * flowperpkt.c - skeleton vpp-api-test plug-in + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +/** + * @file vpp_api_test plugin + */ + +uword unformat_sw_if_index (unformat_input_t * input, va_list * args); + +/* Declare message IDs */ +#include + +/* define message structures */ +#define vl_typedefs +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +/* Get the API version number. */ +#define vl_api_version(n,v) static u32 api_version=(v); +#include +#undef vl_api_version + +typedef struct +{ + /** API message ID base */ + u16 msg_id_base; + /** vat_main_t pointer */ + vat_main_t *vat_main; +} flowperpkt_test_main_t; + +flowperpkt_test_main_t flowperpkt_test_main; + +#define foreach_standard_reply_retval_handler \ +_(flowperpkt_tx_interface_add_del_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = flowperpkt_test_main.vat_main; \ + i32 retval = ntohl(mp->retval); \ + if (vam->async_mode) { \ + vam->async_errors += (retval < 0); \ + } else { \ + vam->retval = retval; \ + vam->result_ready = 1; \ + } \ + } +foreach_standard_reply_retval_handler; +#undef _ + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ +#define foreach_vpe_api_reply_msg \ +_(FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY, \ + flowperpkt_tx_interface_add_del_reply) + + +/* M: construct, but don't yet send a message */ + +#define M(T,t) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc(sizeof(*mp)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +#define M2(T,t,n) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc(sizeof(*mp)+(n)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T + sm->msg_id_base); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +/* S: send a message */ +#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp)) + +/* W: wait for results, with timeout */ +#define W \ +do { \ + timeout = vat_time_now (vam) + 1.0; \ + \ + while (vat_time_now (vam) < timeout) { \ + if (vam->result_ready == 1) { \ + return (vam->retval); \ + } \ + } \ + return -99; \ +} while(0); + +static int +api_flowperpkt_tx_interface_add_del (vat_main_t * vam) +{ + flowperpkt_test_main_t *sm = &flowperpkt_test_main; + unformat_input_t *i = vam->input; + f64 timeout; + int enable_disable = 1; + u8 which = 0; /* ipv4 by default */ + u32 sw_if_index = ~0; + vl_api_flowperpkt_tx_interface_add_del_t *mp; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "disable")) + enable_disable = 0; + else if (unformat (i, "l2")) + which = 1; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name / explicit sw_if_index number \n"); + return -99; + } + + /* Construct the API message */ + M (FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = enable_disable; + mp->which = which; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +/* + * List of messages that the api test plugin sends, + * and that the data plane plugin processes + */ +#define foreach_vpe_api_msg \ +_(flowperpkt_tx_interface_add_del, " [disable]") + +void +vat_api_hookup (vat_main_t * vam) +{ + flowperpkt_test_main_t *sm = &flowperpkt_test_main; + /* Hook up handlers for replies from the data plane plug-in */ +#define _(N,n) \ + vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base), \ + #n, \ + vl_api_##n##_t_handler, \ + vl_noop_handler, \ + vl_api_##n##_t_endian, \ + vl_api_##n##_t_print, \ + sizeof(vl_api_##n##_t), 1); + foreach_vpe_api_reply_msg; +#undef _ + + /* API messages we can send */ +#define _(n,h) hash_set_mem (vam->function_by_name, #n, api_##n); + foreach_vpe_api_msg; +#undef _ + + /* Help strings */ +#define _(n,h) hash_set_mem (vam->help_by_name, #n, h); + foreach_vpe_api_msg; +#undef _ +} + +clib_error_t * +vat_plugin_register (vat_main_t * vam) +{ + flowperpkt_test_main_t *sm = &flowperpkt_test_main; + u8 *name; + + sm->vat_main = vam; + + /* Ask the vpp engine for the first assigned message-id */ + name = format (0, "flowperpkt_%08x%c", api_version, 0); + sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name); + + /* Don't attempt to hook up API messages if the data plane plugin is AWOL */ + if (sm->msg_id_base != (u16) ~ 0) + vat_api_hookup (vam); + + vec_free (name); + + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/l2_node.c b/src/plugins/flowperpkt/l2_node.c new file mode 100644 index 00000000000..1c2f681e1e1 --- /dev/null +++ b/src/plugins/flowperpkt/l2_node.c @@ -0,0 +1,561 @@ +/* + * l2_node.c - l2 ipfix-per-packet graph node + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +/** + * @file l2 flow record generator graph node + */ + +typedef struct +{ + /** interface handle */ + u32 rx_sw_if_index; + u32 tx_sw_if_index; + /** src and dst L2 addresses */ + u8 src_mac[6]; + u8 dst_mac[6]; + /** Ethertype */ + u16 ethertype; + /** packet timestamp */ + u64 timestamp; + /** size of the buffer */ + u16 buffer_size; +} flowperpkt_l2_trace_t; + +/* packet trace format function */ +static u8 * +format_flowperpkt_l2_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + flowperpkt_l2_trace_t *t = va_arg (*args, flowperpkt_l2_trace_t *); + + s = format (s, + "FLOWPERPKT-L2: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U ethertype %0x2, timestamp %lld, size %d", + t->rx_sw_if_index, t->tx_sw_if_index, + format_ethernet_address, &t->src_mac, + format_ethernet_address, &t->dst_mac, + t->ethertype, t->timestamp, t->buffer_size); + return s; +} + +vlib_node_registration_t flowperpkt_l2_node; + +/* No counters at the moment */ +#define foreach_flowperpkt_l2_error + +typedef enum +{ +#define _(sym,str) FLOWPERPKT_ERROR_##sym, + foreach_flowperpkt_l2_error +#undef _ + FLOWPERPKT_N_ERROR, +} flowperpkt_l2_error_t; + +static char *flowperpkt_l2_error_strings[] = { +#define _(sym,string) string, + foreach_flowperpkt_l2_error +#undef _ +}; + +typedef enum +{ + FLOWPERPKT_L2_NEXT_DROP, + FLOWPERPKT_L2_NEXT_IP4_LOOKUP, + FLOWPERPKT_L2_N_NEXT, +} flowperpkt_l2_next_t; + +/** + * @brief add an entry to the flow record under construction + * @param vm vlib_main_t * current worker thread main structure pointer + * @param fm flowperpkt_main_t * flow-per-packet main structure pointer + * @param sw_if_index u32 interface handle + * @param tos u8 ToS bits from the packet + * @param timestamp u64 timestamp, nanoseconds since 1/1/70 + * @param length u16 ip length of the packet + * @param do_flush int 1 = flush all cached records, 0 = construct a record + */ + +static inline void +add_to_flow_record_l2 (vlib_main_t * vm, + vlib_node_runtime_t * node, + flowperpkt_main_t * fm, + u32 rx_sw_if_index, u32 tx_sw_if_index, + u8 * src_mac, u8 * dst_mac, + u16 ethertype, u64 timestamp, u16 length, int do_flush) +{ + u32 my_cpu_number = vm->cpu_index; + flow_report_main_t *frm = &flow_report_main; + ip4_header_t *ip; + udp_header_t *udp; + ip4_ipfix_template_packet_t *tp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + vlib_frame_t *f; + vlib_buffer_t *b0; + u16 offset; + u32 bi0; + vlib_buffer_free_list_t *fl; + + /* Find or allocate a buffer */ + b0 = fm->l2_buffers_per_worker[my_cpu_number]; + + /* Need to allocate a buffer? */ + if (PREDICT_FALSE (b0 == 0)) + { + /* Nothing to flush */ + if (do_flush) + return; + + /* $$$$ drop counter? */ + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + return; + + /* Initialize the buffer */ + b0 = fm->l2_buffers_per_worker[my_cpu_number] = + vlib_get_buffer (vm, bi0); + fl = + vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); + vlib_buffer_init_for_free_list (b0, fl); + VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); + offset = 0; + } + else + { + /* use the current buffer */ + bi0 = vlib_get_buffer_index (vm, b0); + offset = fm->l2_next_record_offset_per_worker[my_cpu_number]; + } + + /* Find or allocate a frame */ + f = fm->l2_frames_per_worker[my_cpu_number]; + if (PREDICT_FALSE (f == 0)) + { + u32 *to_next; + f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + fm->l2_frames_per_worker[my_cpu_number] = f; + + /* Enqueue the buffer */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi0; + f->n_vectors = 1; + } + + /* Fresh packet, construct header */ + if (PREDICT_FALSE (offset == 0)) + { + flow_report_stream_t *stream; + + stream = &frm->streams[0]; + + b0->current_data = 0; + b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + + sizeof (*s); + b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; + + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->flags_and_fragment_offset = 0; + ip->src_address.as_u32 = frm->src_address.as_u32; + ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; + udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->checksum = 0; + + /* FIXUP: message header export_time */ + h->export_time = (u32) + (((f64) frm->unix_time_0) + + (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); + h->export_time = clib_host_to_net_u32 (h->export_time); + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* FIXUP: message header sequence_number */ + h->sequence_number = stream->sequence_number++; + h->sequence_number = clib_host_to_net_u32 (h->sequence_number); + + offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); + } + + /* Add data, unless we're flushing stale data */ + if (PREDICT_TRUE (do_flush == 0)) + { + + /* Add data */ + /* Ingress interface */ + { + u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); + clib_memcpy (b0->data + offset, &ingress_interface, + sizeof (ingress_interface)); + offset += sizeof (ingress_interface); + } + /* Egress interface */ + { + u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); + clib_memcpy (b0->data + offset, &egress_interface, + sizeof (egress_interface)); + offset += sizeof (egress_interface); + } + /* src mac address */ + { + clib_memcpy (b0->data + offset, src_mac, 6); + offset += 6; + } + /* dst mac address */ + { + clib_memcpy (b0->data + offset, dst_mac, 6); + offset += 6; + } + + /* ethertype */ + b0->data[offset++] = ethertype >> 8; + b0->data[offset++] = ethertype & 0xFF; + + /* Timestamp */ + clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); + offset += sizeof (f64); + + /* pkt size */ + { + u16 pkt_size = clib_host_to_net_u16 (length); + clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); + offset += sizeof (pkt_size); + } + + b0->current_length += + /* 2*sw_if_index + 2*mac + ethertype + timestamp + length = 32 */ + 2 * sizeof (u32) + 12 + sizeof (u16) + sizeof (f64) + sizeof (u16); + + } + /* Time to flush the buffer? */ + if (PREDICT_FALSE + (do_flush || (offset + 2 * sizeof (u32) + 12 + sizeof (u16) + + +sizeof (f64) + sizeof (u16)) > frm->path_mtu)) + { + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + s->set_id_length = ipfix_set_id_length (fm->l2_report_id, + b0->current_length - + (sizeof (*ip) + sizeof (*udp) + + sizeof (*h))); + h->version_length = version_length (b0->current_length - + (sizeof (*ip) + sizeof (*udp))); + + ip->length = clib_host_to_net_u16 (b0->current_length); + + ip->checksum = ip4_header_checksum (ip); + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + if (frm->udp_checksum) + { + /* RFC 7011 section 10.3.2. */ + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + } + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) + { + vlib_trace_buffer (vm, node, FLOWPERPKT_L2_NEXT_IP4_LOOKUP, b0, + 0 /* follow chain */ ); + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + memset (t, 0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->buffer_size = b0->current_length; + } + + vlib_put_frame_to_node (vm, ip4_lookup_node.index, + fm->l2_frames_per_worker[my_cpu_number]); + fm->l2_frames_per_worker[my_cpu_number] = 0; + fm->l2_buffers_per_worker[my_cpu_number] = 0; + offset = 0; + } + + fm->l2_next_record_offset_per_worker[my_cpu_number] = offset; +} + +void +flowperpkt_flush_callback_l2 (void) +{ + vlib_main_t *vm = vlib_get_main (); + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_node_runtime_t *node; + node = vlib_node_get_runtime (vm, flowperpkt_l2_node.index); + + add_to_flow_record_l2 (vm, node, fm, 0 /* rx_sw_if_index */ , + 0 /* tx_sw_if_index */ , + 0 /* src mac */ , + 0 /* dst mac */ , + 0 /* ethertype */ , + 0ULL /* timestamp */ , + 0 /* length */ , + 1 /* do_flush */ ); +} + + +static uword +flowperpkt_l2_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + flowperpkt_l2_next_t next_index; + flowperpkt_main_t *fm = &flowperpkt_main; + u64 now; + + now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); + now += fm->nanosecond_time_0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = FLOWPERPKT_L2_NEXT_DROP; + u32 next1 = FLOWPERPKT_L2_NEXT_DROP; + ethernet_header_t *eh0, *eh1; + u16 len0, len1; + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], + &next1, b1); + + eh0 = vlib_buffer_get_current (b0); + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + eh0->src_address, + eh0->dst_address, + eh0->type, now, len0, 0 /* flush */ ); + + eh1 = vlib_buffer_get_current (b0); + len1 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b1)->sw_if_index[VLIB_RX], + vnet_buffer (b1)->sw_if_index[VLIB_TX], + eh1->src_address, + eh1->dst_address, + eh1->type, now, len1, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh0->src_address, 6); + clib_memcpy (t->dst_mac, eh0->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh0->type); + t->timestamp = now; + t->buffer_size = len0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh1->src_address, 6); + clib_memcpy (t->dst_mac, eh1->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh1->type); + t->timestamp = now; + t->buffer_size = len1; + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = FLOWPERPKT_L2_NEXT_DROP; + ethernet_header_t *eh0; + u16 len0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + + eh0 = vlib_buffer_get_current (b0); + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_l2 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + eh0->src_address, + eh0->dst_address, + eh0->type, now, len0, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + flowperpkt_l2_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + clib_memcpy (t->src_mac, eh0->src_address, 6); + clib_memcpy (t->dst_mac, eh0->dst_address, 6); + t->ethertype = clib_net_to_host_u16 (eh0->type); + t->timestamp = now; + t->buffer_size = len0; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + return frame->n_vectors; +} + +/** + * @brief IPFIX l2 flow-per-packet graph node + * @node flowperpkt-l2 + * + * This is the IPFIX flow-record-per-packet node. + * + * @param vm vlib_main_t corresponding to the current thread. + * @param node vlib_node_runtime_t data for this node. + * @param frame vlib_frame_t whose contents should be dispatched. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * Uses: + * - vnet_buffer(b)->ip.save_rewrite_length + * - tells the node the length of the rewrite which was applied in + * ip4/6_rewrite_inline, allows the code to find the IP header without + * having to parse L2 headers, or make stupid assumptions about their + * length. + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - Used to suppress flow record generation for flow record packets. + * + * Sets: + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - To suppress flow record generation for flow record packets + * + * Next Index: + * - Next configured output feature on the interface, usually + * "interface-output." Generated flow records head for ip4-lookup + */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (flowperpkt_l2_node) = { + .function = flowperpkt_l2_node_fn, + .name = "flowperpkt-l2", + .vector_size = sizeof (u32), + .format_trace = format_flowperpkt_l2_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(flowperpkt_l2_error_strings), + .error_strings = flowperpkt_l2_error_strings, + + .n_next_nodes = FLOWPERPKT_L2_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [FLOWPERPKT_L2_NEXT_DROP] = "error-drop", + [FLOWPERPKT_L2_NEXT_IP4_LOOKUP] = "ip4-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/flowperpkt/node.c b/src/plugins/flowperpkt/node.c new file mode 100644 index 00000000000..f77f087dc78 --- /dev/null +++ b/src/plugins/flowperpkt/node.c @@ -0,0 +1,574 @@ +/* + * node.c - ipv4 ipfix-per-packet graph node + * + * Copyright (c) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +/** + * @file ipv4 flow record generator graph node + */ + +typedef struct +{ + /** interface handle */ + u32 rx_sw_if_index; + u32 tx_sw_if_index; + u32 src_address; + u32 dst_address; + /** ToS bits */ + u8 tos; + /** packet timestamp */ + u64 timestamp; + /** size of the buffer */ + u16 buffer_size; +} flowperpkt_ipv4_trace_t; + +/* packet trace format function */ +static u8 * +format_flowperpkt_ipv4_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + flowperpkt_ipv4_trace_t *t = va_arg (*args, flowperpkt_ipv4_trace_t *); + + s = format (s, + "FLOWPERPKT-V4: rx_sw_if_index %d, tx_sw_if_index %d, src %U dst %U tos %0x2, timestamp %lld, size %d", + t->rx_sw_if_index, t->tx_sw_if_index, + format_ip4_address, &t->src_address, + format_ip4_address, &t->dst_address, + t->tos, t->timestamp, t->buffer_size); + return s; +} + +vlib_node_registration_t flowperpkt_ipv4_node; + +/* No counters at the moment */ +#define foreach_flowperpkt_ipv4_error + +typedef enum +{ +#define _(sym,str) FLOWPERPKT_ERROR_##sym, + foreach_flowperpkt_ipv4_error +#undef _ + FLOWPERPKT_N_ERROR, +} flowperpkt_ipv4_error_t; + +static char *flowperpkt_ipv4_error_strings[] = { +#define _(sym,string) string, + foreach_flowperpkt_ipv4_error +#undef _ +}; + +typedef enum +{ + FLOWPERPKT_IPV4_NEXT_DROP, + FLOWPERPKT_IPV4_NEXT_LOOKUP, + FLOWPERPKT_IPV4_N_NEXT, +} flowperpkt_ipv4_next_t; + +/** + * @brief add an entry to the flow record under construction + * @param vm vlib_main_t * current worker thread main structure pointer + * @param fm flowperpkt_main_t * flow-per-packet main structure pointer + * @param sw_if_index u32 interface handle + * @param tos u8 ToS bits from the packet + * @param timestamp u64 timestamp, nanoseconds since 1/1/70 + * @param length u16 ip length of the packet + * @param do_flush int 1 = flush all cached records, 0 = construct a record + */ + +static inline void +add_to_flow_record_ipv4 (vlib_main_t * vm, + vlib_node_runtime_t * node, + flowperpkt_main_t * fm, + u32 rx_sw_if_index, u32 tx_sw_if_index, + u32 src_address, u32 dst_address, + u8 tos, u64 timestamp, u16 length, int do_flush) +{ + u32 my_cpu_number = vm->cpu_index; + flow_report_main_t *frm = &flow_report_main; + ip4_header_t *ip; + udp_header_t *udp; + ip4_ipfix_template_packet_t *tp; + ipfix_message_header_t *h; + ipfix_set_header_t *s; + vlib_frame_t *f; + vlib_buffer_t *b0; + u16 offset; + u32 bi0; + vlib_buffer_free_list_t *fl; + + /* Find or allocate a buffer */ + b0 = fm->ipv4_buffers_per_worker[my_cpu_number]; + + /* Need to allocate a buffer? */ + if (PREDICT_FALSE (b0 == 0)) + { + /* Nothing to flush */ + if (do_flush) + return; + + /* $$$$ drop counter? */ + if (vlib_buffer_alloc (vm, &bi0, 1) != 1) + return; + + /* Initialize the buffer */ + b0 = fm->ipv4_buffers_per_worker[my_cpu_number] = + vlib_get_buffer (vm, bi0); + fl = + vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX); + vlib_buffer_init_for_free_list (b0, fl); + VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0); + offset = 0; + } + else + { + /* use the current buffer */ + bi0 = vlib_get_buffer_index (vm, b0); + offset = fm->ipv4_next_record_offset_per_worker[my_cpu_number]; + } + + /* Find or allocate a frame */ + f = fm->ipv4_frames_per_worker[my_cpu_number]; + if (PREDICT_FALSE (f == 0)) + { + u32 *to_next; + f = vlib_get_frame_to_node (vm, ip4_lookup_node.index); + fm->ipv4_frames_per_worker[my_cpu_number] = f; + + /* Enqueue the buffer */ + to_next = vlib_frame_vector_args (f); + to_next[0] = bi0; + f->n_vectors = 1; + } + + /* Fresh packet, construct header */ + if (PREDICT_FALSE (offset == 0)) + { + flow_report_stream_t *stream; + + stream = &frm->streams[0]; + + b0->current_data = 0; + b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) + + sizeof (*s); + b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VLIB_BUFFER_FLOW_REPORT); + vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index; + + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + ip->ip_version_and_header_length = 0x45; + ip->ttl = 254; + ip->protocol = IP_PROTOCOL_UDP; + ip->flags_and_fragment_offset = 0; + ip->src_address.as_u32 = frm->src_address.as_u32; + ip->dst_address.as_u32 = frm->ipfix_collector.as_u32; + udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipfix); + udp->checksum = 0; + + /* FIXUP: message header export_time */ + h->export_time = (u32) + (((f64) frm->unix_time_0) + + (vlib_time_now (frm->vlib_main) - frm->vlib_time_0)); + h->export_time = clib_host_to_net_u32 (h->export_time); + h->domain_id = clib_host_to_net_u32 (stream->domain_id); + + /* FIXUP: message header sequence_number */ + h->sequence_number = stream->sequence_number++; + h->sequence_number = clib_host_to_net_u32 (h->sequence_number); + + offset = (u32) (((u8 *) (s + 1)) - (u8 *) tp); + } + + /* Add data, unless we're flushing stale data */ + if (PREDICT_TRUE (do_flush == 0)) + { + + /* Add data */ + /* Ingress interface */ + { + u32 ingress_interface = clib_host_to_net_u32 (rx_sw_if_index); + clib_memcpy (b0->data + offset, &ingress_interface, + sizeof (ingress_interface)); + offset += sizeof (ingress_interface); + } + /* Egress interface */ + { + u32 egress_interface = clib_host_to_net_u32 (tx_sw_if_index); + clib_memcpy (b0->data + offset, &egress_interface, + sizeof (egress_interface)); + offset += sizeof (egress_interface); + } + /* ip4 src address */ + { + clib_memcpy (b0->data + offset, &src_address, sizeof (src_address)); + offset += sizeof (src_address); + } + /* ip4 dst address */ + { + clib_memcpy (b0->data + offset, &dst_address, sizeof (dst_address)); + offset += sizeof (dst_address); + } + + /* ToS */ + b0->data[offset++] = tos; + + /* Timestamp */ + clib_memcpy (b0->data + offset, ×tamp, sizeof (f64)); + offset += sizeof (f64); + + /* pkt size */ + { + u16 pkt_size = clib_host_to_net_u16 (length); + clib_memcpy (b0->data + offset, &pkt_size, sizeof (pkt_size)); + offset += sizeof (pkt_size); + } + + b0->current_length += + /* sw_if_index + tos + timestamp + length = 15 */ + 4 * sizeof (u32) + sizeof (u8) + sizeof (f64) + sizeof (u16); + + } + /* Time to flush the buffer? */ + if (PREDICT_FALSE + (do_flush || (offset + 4 * sizeof (u32) + sizeof (u8) + + sizeof (f64) + sizeof (u16)) > frm->path_mtu)) + { + tp = vlib_buffer_get_current (b0); + ip = (ip4_header_t *) & tp->ip4; + udp = (udp_header_t *) (ip + 1); + h = (ipfix_message_header_t *) (udp + 1); + s = (ipfix_set_header_t *) (h + 1); + + s->set_id_length = ipfix_set_id_length (fm->ipv4_report_id, + b0->current_length - + (sizeof (*ip) + sizeof (*udp) + + sizeof (*h))); + h->version_length = version_length (b0->current_length - + (sizeof (*ip) + sizeof (*udp))); + + ip->length = clib_host_to_net_u16 (b0->current_length); + + ip->checksum = ip4_header_checksum (ip); + udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip)); + + if (frm->udp_checksum) + { + /* RFC 7011 section 10.3.2. */ + udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip); + if (udp->checksum == 0) + udp->checksum = 0xffff; + } + + ASSERT (ip->checksum == ip4_header_checksum (ip)); + + if (PREDICT_FALSE (vlib_get_trace_count (vm, node) > 0)) + { + vlib_trace_buffer (vm, node, FLOWPERPKT_IPV4_NEXT_LOOKUP, b0, + 0 /* follow chain */ ); + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = 0; + t->dst_address = 0; + t->tos = 0; + t->timestamp = 0; + t->buffer_size = b0->current_length; + } + + vlib_put_frame_to_node (vm, ip4_lookup_node.index, + fm->ipv4_frames_per_worker[my_cpu_number]); + fm->ipv4_frames_per_worker[my_cpu_number] = 0; + fm->ipv4_buffers_per_worker[my_cpu_number] = 0; + offset = 0; + } + + fm->ipv4_next_record_offset_per_worker[my_cpu_number] = offset; +} + +void +flowperpkt_flush_callback_ipv4 (void) +{ + vlib_main_t *vm = vlib_get_main (); + flowperpkt_main_t *fm = &flowperpkt_main; + vlib_node_runtime_t *node; + node = vlib_node_get_runtime (vm, flowperpkt_ipv4_node.index); + + add_to_flow_record_ipv4 (vm, node, fm, 0 /* rx_sw_if_index */ , + 0 /* tx_sw_if_index */ , + 0 /* src_address */ , + 0 /* dst_address */ , + 0 /* ToS */ , + 0ULL /* timestamp */ , + 0 /* length */ , + 1 /* do_flush */ ); +} + + +static uword +flowperpkt_ipv4_node_fn (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, *to_next; + flowperpkt_ipv4_next_t next_index; + flowperpkt_main_t *fm = &flowperpkt_main; + u64 now; + + now = (u64) ((vlib_time_now (vm) - fm->vlib_time_0) * 1e9); + now += fm->nanosecond_time_0; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + u32 n_left_to_next; + + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 next0 = FLOWPERPKT_IPV4_NEXT_DROP; + u32 next1 = FLOWPERPKT_IPV4_NEXT_DROP; + ip4_header_t *ip0, *ip1; + u16 len0, len1; + u32 bi0, bi1; + vlib_buffer_t *b0, *b1; + + /* Prefetch next iteration. */ + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + + CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE); + CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE); + } + + /* speculatively enqueue b0 and b1 to the current next frame */ + to_next[0] = bi0 = from[0]; + to_next[1] = bi1 = from[1]; + from += 2; + to_next += 2; + n_left_from -= 2; + n_left_to_next -= 2; + + b0 = vlib_get_buffer (vm, bi0); + b1 = vlib_get_buffer (vm, bi1); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_TX], + &next1, b1); + + ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + + vnet_buffer (b0)->ip.save_rewrite_length); + + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + ip0->src_address.as_u32, + ip0->dst_address.as_u32, + ip0->tos, now, len0, 0 /* flush */ ); + + ip1 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b1) + + vnet_buffer (b1)->ip.save_rewrite_length); + len1 = vlib_buffer_length_in_chain (vm, b1); + + if (PREDICT_TRUE ((b1->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b1)->sw_if_index[VLIB_RX], + vnet_buffer (b1)->sw_if_index[VLIB_TX], + ip1->src_address.as_u32, + ip1->dst_address.as_u32, + ip1->tos, now, len1, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE))) + { + if (b0->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = ip0->src_address.as_u32; + t->dst_address = ip0->dst_address.as_u32; + t->tos = ip0->tos; + t->timestamp = now; + t->buffer_size = len0; + } + if (b1->flags & VLIB_BUFFER_IS_TRACED) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b1, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_TX]; + t->src_address = ip1->src_address.as_u32; + t->dst_address = ip1->dst_address.as_u32; + t->tos = ip1->tos; + t->timestamp = now; + t->buffer_size = len1; + } + } + + /* verify speculative enqueues, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, + to_next, n_left_to_next, + bi0, bi1, next0, next1); + } + + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 bi0; + vlib_buffer_t *b0; + u32 next0 = FLOWPERPKT_IPV4_NEXT_DROP; + ip4_header_t *ip0; + u16 len0; + + /* speculatively enqueue b0 to the current next frame */ + bi0 = from[0]; + to_next[0] = bi0; + from += 1; + to_next += 1; + n_left_from -= 1; + n_left_to_next -= 1; + + b0 = vlib_get_buffer (vm, bi0); + + vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_TX], + &next0, b0); + + ip0 = (ip4_header_t *) ((u8 *) vlib_buffer_get_current (b0) + + vnet_buffer (b0)->ip.save_rewrite_length); + /* + * egressInterface, TLV type 14, u32 + * ipClassOfService, TLV type 5, u8 + * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64) + * Implementation: f64 nanoseconds since VPP started + * dataLinkFrameSize, TLV type 312, u16 + */ + len0 = vlib_buffer_length_in_chain (vm, b0); + + if (PREDICT_TRUE ((b0->flags & VLIB_BUFFER_FLOW_REPORT) == 0)) + add_to_flow_record_ipv4 (vm, node, fm, + vnet_buffer (b0)->sw_if_index[VLIB_RX], + vnet_buffer (b0)->sw_if_index[VLIB_TX], + ip0->src_address.as_u32, + ip0->dst_address.as_u32, + ip0->tos, now, len0, 0 /* flush */ ); + + if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) + && (b0->flags & VLIB_BUFFER_IS_TRACED))) + { + flowperpkt_ipv4_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + t->rx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + t->tx_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX]; + t->src_address = ip0->src_address.as_u32; + t->dst_address = ip0->dst_address.as_u32; + t->tos = ip0->tos; + t->timestamp = now; + t->buffer_size = len0; + } + + /* verify speculative enqueue, maybe switch current next frame */ + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, + to_next, n_left_to_next, + bi0, next0); + } + + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + return frame->n_vectors; +} + +/** + * @brief IPFIX ipv4 flow-per-packet graph node + * @node flowperpkt-ipv4 + * + * This is the IPFIX flow-record-per-packet node. + * + * @param vm vlib_main_t corresponding to the current thread. + * @param node vlib_node_runtime_t data for this node. + * @param frame vlib_frame_t whose contents should be dispatched. + * + * @par Graph mechanics: buffer metadata, next index usage + * + * Uses: + * - vnet_buffer(b)->ip.save_rewrite_length + * - tells the node the length of the rewrite which was applied in + * ip4/6_rewrite_inline, allows the code to find the IP header without + * having to parse L2 headers, or make stupid assumptions about their + * length. + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - Used to suppress flow record generation for flow record packets. + * + * Sets: + * - vnet_buffer(b)->flags & VLIB_BUFFER_FLOW_REPORT + * - To suppress flow record generation for flow record packets + * + * Next Index: + * - Next configured output feature on the interface, usually + * "interface-output." Generated flow records head for ip4-lookup + */ + +/* *INDENT-OFF* */ +VLIB_REGISTER_NODE (flowperpkt_ipv4_node) = { + .function = flowperpkt_ipv4_node_fn, + .name = "flowperpkt-ipv4", + .vector_size = sizeof (u32), + .format_trace = format_flowperpkt_ipv4_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = ARRAY_LEN(flowperpkt_ipv4_error_strings), + .error_strings = flowperpkt_ipv4_error_strings, + + .n_next_nodes = FLOWPERPKT_IPV4_N_NEXT, + + /* edit / add dispositions here */ + .next_nodes = { + [FLOWPERPKT_IPV4_NEXT_DROP] = "error-drop", + /* Used only to trace ipfix data packets */ + [FLOWPERPKT_IPV4_NEXT_LOOKUP] = "ip4-lookup", + }, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/plugins/ila.am b/src/plugins/ila.am new file mode 100644 index 00000000000..d900f3eb307 --- /dev/null +++ b/src/plugins/ila.am @@ -0,0 +1,20 @@ +# Copyright (c) 2016 Cisco Systems, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +vppplugins_LTLIBRARIES += ila_plugin.la + +ila_plugin_la_SOURCES = ila/ila.c + +noinst_HEADERS += ila/ila.h + +# vi:syntax=automake diff --git a/src/plugins/ila/ila.c b/src/plugins/ila/ila.c new file mode 100644 index 00000000000..336f4cf560c --- /dev/null +++ b/src/plugins/ila/ila.c @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +static ila_main_t ila_main; + +#define ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS (64 * 1024) +#define ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE (32<<20) + +#define foreach_ila_error \ + _(NONE, "valid ILA packets") + +typedef enum { +#define _(sym,str) ILA_ERROR_##sym, + foreach_ila_error +#undef _ + ILA_N_ERROR, +} ila_error_t; + +static char *ila_error_strings[] = { +#define _(sym,string) string, + foreach_ila_error +#undef _ +}; + +typedef enum { + ILA_ILA2SIR_NEXT_DROP, + ILA_ILA2SIR_N_NEXT, +} ila_ila2sir_next_t; + +typedef struct { + u32 ila_index; + ip6_address_t initial_dst; + u32 adj_index; +} ila_ila2sir_trace_t; + +static ila_entry_t ila_sir2ila_default_entry = { + .csum_mode = ILA_CSUM_MODE_NO_ACTION, + .type = ILA_TYPE_IID, + .dir = ILA_DIR_ILA2SIR, //Will pass the packet with no +}; + +/** + * @brief Dynamically registered DPO Type for ILA + */ +static dpo_type_t ila_dpo_type; + +/** + * @brief Dynamically registered FIB node type for ILA + */ +static fib_node_type_t ila_fib_node_type; + +u8 * +format_half_ip6_address (u8 * s, va_list * va) +{ + u64 v = clib_net_to_host_u64 (va_arg (*va, u64)); + + return format (s, "%04x:%04x:%04x:%04x", + v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff); + +} + +u8 * +format_ila_direction (u8 * s, va_list * args) +{ + ila_direction_t t = va_arg (*args, ila_direction_t); +#define _(i,n,st) \ + if (t == ILA_DIR_##i) \ + return format(s, st); + ila_foreach_direction +#undef _ + return format (s, "invalid_ila_direction"); +} + +static u8 * +format_csum_mode (u8 * s, va_list * va) +{ + ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t); + char *txt; + + switch (csum_mode) + { +#define _(i,n,st) \ + case ILA_CSUM_MODE_##i: \ + txt = st; \ + break; + ila_csum_foreach_type +#undef _ + default: + txt = "invalid_ila_csum_mode"; + break; + } + return format (s, txt); +} + +u8 * +format_ila_type (u8 * s, va_list * args) +{ + ila_type_t t = va_arg (*args, ila_type_t); +#define _(i,n,st) \ + if (t == ILA_TYPE_##i) \ + return format(s, st); + ila_foreach_type +#undef _ + return format (s, "invalid_ila_type"); +} + +static u8 * +format_ila_entry (u8 * s, va_list * va) +{ + vnet_main_t *vnm = va_arg (*va, vnet_main_t *); + ila_entry_t *e = va_arg (*va, ila_entry_t *); + + if (!e) + { + return format (s, "%-15s%=40s%=40s%+16s%+18s%+11s", "Type", "SIR Address", + "ILA Address", "Checksum Mode", "Direction", "Next DPO"); + } + else if (vnm) + { + if (ip6_address_is_zero(&e->next_hop)) + { + return format (s, "%-15U%=40U%=40U%18U%11U%s", + format_ila_type, e->type, + format_ip6_address, &e->sir_address, + format_ip6_address, &e->ila_address, + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + "n/a"); + } + else + { + return format (s, "%-15U%=40U%=40U%18U%11U%U", + format_ila_type, e->type, + format_ip6_address, &e->sir_address, + format_ip6_address, &e->ila_address, + format_csum_mode, e->csum_mode, + format_ila_direction, e->dir, + format_dpo_id, &e->ila_dpo, 0); + } + } + + return NULL; +} + +u8 * +format_ila_ila2sir_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *); + return format (s, + "ILA -> SIR adj index: %d entry index: %d initial_dst: %U", + t->adj_index, t->ila_index, format_ip6_address, + &t->initial_dst); +} + +static uword +unformat_ila_direction (unformat_input_t * input, va_list * args) +{ + ila_direction_t *result = va_arg (*args, ila_direction_t *); +#define _(i,n,s) \ + if (unformat(input, s)) \ + { \ + *result = ILA_DIR_##i; \ + return 1;\ + } + + ila_foreach_direction +#undef _ + return 0; +} + +static uword +unformat_ila_type (unformat_input_t * input, va_list * args) +{ + ila_type_t *result = va_arg (*args, ila_type_t *); +#define _(i,n,s) \ + if (unformat(input, s)) \ + { \ + *result = ILA_TYPE_##i; \ + return 1;\ + } + + ila_foreach_type +#undef _ + return 0; +} + +static uword +unformat_ila_csum_mode (unformat_input_t * input, va_list * args) +{ + ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *); + if (unformat (input, "none") || unformat (input, "no-action")) + { + *result = ILA_CSUM_MODE_NO_ACTION; + return 1; + } + if (unformat (input, "neutral-map")) + { + *result = ILA_CSUM_MODE_NEUTRAL_MAP; + return 1; + } + if (unformat (input, "adjust-transport")) + { + *result = ILA_CSUM_MODE_ADJUST_TRANSPORT; + return 1; + } + return 0; +} + +static uword +unformat_half_ip6_address (unformat_input_t * input, va_list * args) +{ + u64 *result = va_arg (*args, u64 *); + u32 a[4]; + + if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3])) + return 0; + + if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF) + return 0; + + *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) | + (((u64) a[1]) << 32) | + (((u64) a[2]) << 16) | (((u64) a[3]))); + + return 1; +} + +static vlib_node_registration_t ila_ila2sir_node; + +static uword +ila_ila2sir (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + ila_main_t *ilm = &ila_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 pi0, pi1; + vlib_buffer_t *p0, *p1; + ila_entry_t *ie0, *ie1; + ip6_header_t *ip60, *ip61; + ip6_address_t *sir_address0, *sir_address1; + + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); + CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); + } + + pi0 = to_next[0] = from[0]; + pi1 = to_next[1] = from[1]; + from += 2; + n_left_from -= 2; + to_next += 2; + n_left_to_next -= 2; + + p0 = vlib_get_buffer (vm, pi0); + p1 = vlib_get_buffer (vm, pi1); + ip60 = vlib_buffer_get_current (p0); + ip61 = vlib_buffer_get_current (p1); + sir_address0 = &ip60->dst_address; + sir_address1 = &ip61->dst_address; + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + ie1 = pool_elt_at_index (ilm->entries, + vnet_buffer (p1)->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = ie0 - ilm->entries; + tr->initial_dst = ip60->dst_address; + tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + } + + if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p1, sizeof (*tr)); + tr->ila_index = ie1 - ilm->entries; + tr->initial_dst = ip61->dst_address; + tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX]; + } + + sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; + sir_address1 = (ie1->dir != ILA_DIR_SIR2ILA) ? &ie1->sir_address : sir_address1; + ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; + ip61->dst_address.as_u64[0] = sir_address1->as_u64[0]; + ip61->dst_address.as_u64[1] = sir_address1->as_u64[1]; + + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; + vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_dpo.dpoi_index; + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, pi0, pi1, + ie0->ila_dpo.dpoi_next_node, + ie1->ila_dpo.dpoi_next_node); + } + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 pi0; + vlib_buffer_t *p0; + ila_entry_t *ie0; + ip6_header_t *ip60; + ip6_address_t *sir_address0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, pi0); + ip60 = vlib_buffer_get_current (p0); + sir_address0 = &ip60->dst_address; + ie0 = pool_elt_at_index (ilm->entries, + vnet_buffer (p0)->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_ila2sir_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX]; + } + + sir_address0 = (ie0->dir != ILA_DIR_SIR2ILA) ? &ie0->sir_address : sir_address0; + ip60->dst_address.as_u64[0] = sir_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = sir_address0->as_u64[1]; + vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_dpo.dpoi_index; + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, pi0, + ie0->ila_dpo.dpoi_next_node); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/** *INDENT-OFF* */ +VLIB_REGISTER_NODE (ila_ila2sir_node, static) = +{ + .function = ila_ila2sir, + .name = "ila-to-sir", + .vector_size = sizeof (u32), + .format_trace = format_ila_ila2sir_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_ILA2SIR_N_NEXT, + .next_nodes = + { + [ILA_ILA2SIR_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ + +typedef enum +{ + ILA_SIR2ILA_NEXT_DROP, + ILA_SIR2ILA_N_NEXT, +} ila_sir2ila_next_t; + +typedef struct +{ + u32 ila_index; + ip6_address_t initial_dst; +} ila_sir2ila_trace_t; + +u8 * +format_ila_sir2ila_trace (u8 * s, va_list * args) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); + ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *); + + return format (s, "SIR -> ILA entry index: %d initial_dst: %U", + t->ila_index, format_ip6_address, &t->initial_dst); +} + +static vlib_node_registration_t ila_sir2ila_node; + +static uword +ila_sir2ila (vlib_main_t * vm, + vlib_node_runtime_t * node, vlib_frame_t * frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + ila_main_t *ilm = &ila_main; + + from = vlib_frame_vector_args (frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) + { + vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from >= 4 && n_left_to_next >= 2) + { + u32 pi0, pi1; + vlib_buffer_t *p0, *p1; + ip6_header_t *ip60, *ip61; + u32 next0 = ILA_SIR2ILA_NEXT_DROP; + u32 next1 = ILA_SIR2ILA_NEXT_DROP; + BVT (clib_bihash_kv) kv0, value0; + BVT (clib_bihash_kv) kv1, value1; + ila_entry_t *ie0 = &ila_sir2ila_default_entry; + ila_entry_t *ie1 = &ila_sir2ila_default_entry; + ip6_address_t *ila_address0, *ila_address1; + + { + vlib_buffer_t *p2, *p3; + + p2 = vlib_get_buffer (vm, from[2]); + p3 = vlib_get_buffer (vm, from[3]); + + vlib_prefetch_buffer_header (p2, LOAD); + vlib_prefetch_buffer_header (p3, LOAD); + CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD); + CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD); + } + + pi0 = to_next[0] = from[0]; + pi1 = to_next[1] = from[1]; + from += 2; + n_left_from -= 2; + to_next += 2; + n_left_to_next -= 2; + + p0 = vlib_get_buffer (vm, pi0); + p1 = vlib_get_buffer (vm, pi1); + ip60 = vlib_buffer_get_current (p0); + ip61 = vlib_buffer_get_current (p1); + ila_address0 = &ip60->dst_address; + ila_address1 = &ip61->dst_address; + kv0.key[0] = ip60->dst_address.as_u64[0]; + kv0.key[1] = ip60->dst_address.as_u64[1]; + kv0.key[2] = 0; + kv1.key[0] = ip61->dst_address.as_u64[0]; + kv1.key[1] = ip61->dst_address.as_u64[1]; + kv1.key[2] = 0; + + if (PREDICT_TRUE((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { + ie0 = &ilm->entries[value0.value]; + ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; + } + + if ((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv1, &value1)) == 0) { + ie1 = &ilm->entries[value1.value]; + ila_address1 = (ie1->dir != ILA_DIR_ILA2SIR) ? &ie1->ila_address : ila_address1; + } + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = + (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + } + + if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p1, sizeof (*tr)); + tr->ila_index = + (ie1 != &ila_sir2ila_default_entry) ? (ie1 - ilm->entries) : ~0; + tr->initial_dst = ip61->dst_address; + } + + ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; + ip61->dst_address.as_u64[0] = ila_address1->as_u64[0]; + ip61->dst_address.as_u64[1] = ila_address1->as_u64[1]; + + vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); + vnet_feature_next (vnet_buffer (p1)->sw_if_index[VLIB_RX], &next1, p1); + + vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, + n_left_to_next, pi0, pi1, next0, + next1); + } + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) + { + u32 pi0; + vlib_buffer_t *p0; + ip6_header_t *ip60; + u32 next0 = ILA_SIR2ILA_NEXT_DROP; + BVT (clib_bihash_kv) kv0, value0; + ila_entry_t *ie0 = &ila_sir2ila_default_entry; + ip6_address_t *ila_address0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next += 1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer (vm, pi0); + ip60 = vlib_buffer_get_current (p0); + ila_address0 = &ip60->dst_address; + + kv0.key[0] = ip60->dst_address.as_u64[0]; + kv0.key[1] = ip60->dst_address.as_u64[1]; + kv0.key[2] = 0; + + if (PREDICT_TRUE((BV (clib_bihash_search) + (&ilm->id_to_entry_table, &kv0, &value0)) == 0)) { + ie0 = &ilm->entries[value0.value]; + ila_address0 = (ie0->dir != ILA_DIR_ILA2SIR) ? &ie0->ila_address : ila_address0; + } + + if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED)) + { + ila_sir2ila_trace_t *tr = + vlib_add_trace (vm, node, p0, sizeof (*tr)); + tr->ila_index = + (ie0 != &ila_sir2ila_default_entry) ? (ie0 - ilm->entries) : ~0; + tr->initial_dst = ip60->dst_address; + } + + //This operation should do everything for any type (except vnid4 obviously) + ip60->dst_address.as_u64[0] = ila_address0->as_u64[0]; + ip60->dst_address.as_u64[1] = ila_address0->as_u64[1]; + + vnet_feature_next (vnet_buffer (p0)->sw_if_index[VLIB_RX], &next0, p0); + + vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, + n_left_to_next, pi0, next0); + } + vlib_put_next_frame (vm, node, next_index, n_left_to_next); + } + + return frame->n_vectors; +} + +/** *INDENT-OFF* */ +VLIB_REGISTER_NODE (ila_sir2ila_node, static) = +{ + .function = ila_sir2ila,.name = "sir-to-ila", + .vector_size = sizeof (u32), + .format_trace = format_ila_sir2ila_trace, + .n_errors = ILA_N_ERROR, + .error_strings = ila_error_strings, + .n_next_nodes = ILA_SIR2ILA_N_NEXT, + .next_nodes = + { + [ILA_SIR2ILA_NEXT_DROP] = "error-drop" + }, +}; +/** *INDENT-ON* */ + +/** *INDENT-OFF* */ +VNET_FEATURE_INIT (ila_sir2ila, static) = +{ + .arc_name = "ip6-unicast", + .node_name = "sir-to-ila", + .runs_before = VNET_FEATURES ("ip6-lookup"), +}; +/** *INDENT-ON* */ + +static void +ila_entry_stack (ila_entry_t *ie) +{ + /* + * restack on the next-hop's FIB entry + */ + dpo_stack(ila_dpo_type, + DPO_PROTO_IP6, + &ie->ila_dpo, + fib_entry_contribute_ip_forwarding( + ie->next_hop_fib_entry_index)); +} + +int +ila_add_del_entry (ila_add_del_entry_args_t * args) +{ + ila_main_t *ilm = &ila_main; + BVT (clib_bihash_kv) kv, value; + + //Sanity check + if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID) + { + if ((args->sir_address.as_u8[8] >> 5) != args->type) + { + clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)", + args->sir_address.as_u8[8] >> 1, args->type); + return -1; + } + if (args->sir_address.as_u8[8] & 0x10) + { + clib_warning ("Checksum bit should not be set in SIR address"); + return -1; + } + } + else if (args->type == ILA_TYPE_VNIDM) + { + if (args->sir_address.as_u8[0] != 0xff || + (args->sir_address.as_u8[1] & 0xf0) != 0xf0) + { + clib_warning ("SIR multicast address must start with fff"); + return -1; + } + if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] || + args->sir_address.as_u16[3] || args->sir_address.as_u16[4] || + args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0)) + { + clib_warning ("SIR multicast address must start with fff"); + return -1; + } + } + + if (!args->is_del) + { + ila_entry_t *e; + pool_get (ilm->entries, e); + e->type = args->type; + e->sir_address = args->sir_address; + e->next_hop = args->next_hop_address; + e->csum_mode = args->csum_mode; + e->dir = args->dir; + + //Construct ILA address + switch (e->type) + { + case ILA_TYPE_IID: + e->ila_address = e->sir_address; + break; + case ILA_TYPE_LUID: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u64[1] = args->sir_address.as_u64[1]; + break; + case ILA_TYPE_VNID6: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1); + e->ila_address.as_u32[2] |= args->vnid; + e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; + break; + case ILA_TYPE_VNIDM: + e->ila_address.as_u64[0] = args->locator; + e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1); + e->ila_address.as_u32[2] |= args->vnid; + e->ila_address.as_u32[3] = args->sir_address.as_u32[3]; + e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4; + break; + case ILA_TYPE_VNID4: + clib_warning ("ILA type '%U' is not supported", format_ila_type, + e->type); + return -1; + } + + //Modify ILA checksum if necessary + if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP) + { + ip_csum_t csum = e->ila_address.as_u16[7]; + int i; + for (i = 0; i < 4; i++) + { + csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]); + csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]); + } + csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000)); + e->ila_address.as_u16[7] = ip_csum_fold (csum); + e->ila_address.as_u8[8] |= 0x10; + } + + //Create entry with the sir address + kv.key[0] = e->sir_address.as_u64[0]; + kv.key[1] = e->sir_address.as_u64[1]; + kv.key[2] = 0; + kv.value = e - ilm->entries; + BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, + 1 /* is_add */ ); + + if (!ip6_address_is_zero(&e->next_hop)) + { + /* + * become a child of the FIB netry for the next-hop + * so we are informed when its forwarding changes + */ + fib_prefix_t next_hop = { + .fp_addr = { + .ip6 = e->next_hop, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + e->next_hop_fib_entry_index = + fib_table_entry_special_add(0, + &next_hop, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + e->next_hop_child_index = + fib_entry_child_add(e->next_hop_fib_entry_index, + ila_fib_node_type, + e - ilm->entries); + + /* + * Create a route that results in the ILA entry + */ + dpo_id_t dpo = DPO_INVALID; + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + dpo_set(&dpo, ila_dpo_type, DPO_PROTO_IP6, e - ilm->entries); + + fib_table_entry_special_dpo_add(0, + &pfx, + FIB_SOURCE_PLUGIN_HI, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo); + dpo_reset(&dpo); + + /* + * finally stack the ILA entry so it will forward to the next-hop + */ + ila_entry_stack (e); + } + } + else + { + ila_entry_t *e; + kv.key[0] = args->sir_address.as_u64[0]; + kv.key[1] = args->sir_address.as_u64[1]; + kv.key[2] = 0; + + if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) < + 0)) + { + return -1; + } + + e = &ilm->entries[value.value]; + + if (!ip6_address_is_zero(&e->next_hop)) + { + fib_prefix_t pfx = { + .fp_addr = { + .ip6 = e->ila_address, + }, + .fp_len = 128, + .fp_proto = FIB_PROTOCOL_IP6, + }; + + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_PLUGIN_HI); + /* + * remove this ILA entry as child of the FIB netry for the next-hop + */ + fib_entry_child_remove(e->next_hop_fib_entry_index, + e->next_hop_child_index); + fib_table_entry_delete_index(e->next_hop_fib_entry_index, + FIB_SOURCE_RR); + e->next_hop_fib_entry_index = FIB_NODE_INDEX_INVALID; + } + dpo_reset (&e->ila_dpo); + + BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv, + 0 /* is_add */ ); + pool_put (ilm->entries, e); + } + return 0; +} + +int +ila_interface (u32 sw_if_index, u8 disable) +{ + vnet_feature_enable_disable ("ip4-unicast", "sir-to-ila", sw_if_index, + !disable, 0, 0); + return 0; +} + +clib_error_t * +vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, + int from_early_init) +{ + clib_error_t *error = 0; + + return error; +} + +u8 *format_ila_dpo (u8 * s, va_list * va) +{ + index_t index = va_arg (*va, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*va, u32); + ila_main_t *ilm = &ila_main; + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + return format(s, "ILA: idx:%d sir:%U", + index, + format_ip6_address, &ie->sir_address); +} + +/** + * @brief no-op lock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_lock (dpo_id_t *dpo) +{ +} + +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_dpo_unlock (dpo_id_t *dpo) +{ +} + +const static dpo_vft_t ila_vft = { + .dv_lock = ila_dpo_lock, + .dv_unlock = ila_dpo_unlock, + .dv_format = format_ila_dpo, +}; +const static char* const ila_ip6_nodes[] = +{ + "ila-to-sir", + NULL, +}; +const static char* const * const ila_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP6] = ila_ip6_nodes, +}; + +static fib_node_t * +ila_fib_node_get_node (fib_node_index_t index) +{ + ila_main_t *ilm = &ila_main; + ila_entry_t *ie = pool_elt_at_index (ilm->entries, index); + + return (&ie->ila_fib_node); +} + +/** + * @brief no-op unlock function. + * The lifetime of the ILA entry is managed by the control plane + */ +static void +ila_fib_node_last_lock_gone (fib_node_t *node) +{ +} + +static ila_entry_t * +ila_entry_from_fib_node (fib_node_t *node) +{ + return ((ila_entry_t*)(((char*)node) - + STRUCT_OFFSET_OF(ila_entry_t, ila_fib_node))); +} + +/** + * @brief + * Callback function invoked when the forwarding changes for the ILA next-hop + */ +static fib_node_back_walk_rc_t +ila_fib_node_back_walk_notify (fib_node_t *node, + fib_node_back_walk_ctx_t *ctx) +{ + ila_entry_stack(ila_entry_from_fib_node(node)); + + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/* + * ILA's FIB graph node virtual function table + */ +static const fib_node_vft_t ila_fib_node_vft = { + .fnv_get = ila_fib_node_get_node, + .fnv_last_lock = ila_fib_node_last_lock_gone, + .fnv_back_walk = ila_fib_node_back_walk_notify, +}; + +clib_error_t * +ila_init (vlib_main_t * vm) +{ + ila_main_t *ilm = &ila_main; + ilm->entries = NULL; + + ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS; + ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets); + ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE; + + BV (clib_bihash_init) (&ilm->id_to_entry_table, + "ila id to entry index table", + ilm->lookup_table_nbuckets, ilm->lookup_table_size); + + ila_dpo_type = dpo_register_new_type(&ila_vft, ila_nodes); + ila_fib_node_type = fib_node_register_new_type(&ila_fib_node_vft); + + return NULL; +} + +VLIB_INIT_FUNCTION (ila_init); + +static clib_error_t * +ila_entry_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ila_add_del_entry_args_t args = { 0 }; + u8 next_hop_set = 0; + int ret; + + args.type = ILA_TYPE_IID; + args.csum_mode = ILA_CSUM_MODE_NO_ACTION; + args.local_adj_index = ~0; + args.dir = ILA_DIR_BIDIR; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "type %U", unformat_ila_type, &args.type)) + ; + else if (unformat + (line_input, "sir-address %U", unformat_ip6_address, + &args.sir_address)) + ; + else if (unformat + (line_input, "locator %U", unformat_half_ip6_address, + &args.locator)) + ; + else if (unformat + (line_input, "csum-mode %U", unformat_ila_csum_mode, + &args.csum_mode)) + ; + else if (unformat (line_input, "vnid %x", &args.vnid)) + ; + else if (unformat + (line_input, "next-hop %U", unformat_ip6_address, + &args.next_hop_address)) + ; + else if (unformat + (line_input, "direction %U", unformat_ila_direction, &args.dir)) + next_hop_set = 1; + else if (unformat (line_input, "del")) + args.is_del = 1; + else + return clib_error_return (0, "parse error: '%U'", + format_unformat_error, line_input); + } + + unformat_free (line_input); + + if (!next_hop_set) + return clib_error_return (0, "Specified a next hop"); + + if ((ret = ila_add_del_entry (&args))) + return clib_error_return (0, "ila_add_del_entry returned error %d", ret); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_entry_command, static) = +{ + .path = "ila entry", + .short_help = "ila entry [type ] [sir-address
] [locator ] [vnid ]" + " [adj-index ] [next-hop ] [direction (bidir|sir2ila|ila2sir)]" + " [csum-mode (no-action|neutral-map|transport-adjust)] [del]", + .function = ila_entry_command_fn, +}; + +static clib_error_t * +ila_interface_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index = ~0; + u8 disable = 0; + + if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + { + return clib_error_return (0, "Invalid interface name"); + } + + if (unformat (input, "disable")) + { + disable = 1; + } + + int ret; + if ((ret = ila_interface (sw_if_index, disable))) + return clib_error_return (0, "ila_interface returned error %d", ret); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_interface_command, static) = +{ + .path = "ila interface", + .short_help = "ila interface [disable]", + .function = ila_interface_command_fn, +}; + +static clib_error_t * +ila_show_entries_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + vnet_main_t *vnm = vnet_get_main (); + ila_main_t *ilm = &ila_main; + ila_entry_t *e; + + vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, NULL); + pool_foreach (e, ilm->entries, + ({ + vlib_cli_output (vm, " %U\n", format_ila_entry, vnm, e); + })); + + return NULL; +} + +VLIB_CLI_COMMAND (ila_show_entries_command, static) = +{ + .path = "show ila entries", + .short_help = "show ila entries", + .function = ila_show_entries_command_fn, +}; diff --git a/src/plugins/ila/ila.h b/src/plugins/ila/ila.h new file mode 100644 index 00000000000..26620983823 --- /dev/null +++ b/src/plugins/ila/ila.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ILA_H +#define ILA_H + +#include +#include +#include + +#include +#include + +#define ila_foreach_type \ + _(IID, 0, "iid") \ + _(LUID, 1, "luid") \ + _(VNID4, 2, "vnid-ip4") \ + _(VNID6, 3, "vnid-ip6") \ + _(VNIDM, 4, "vnid-multicast") + +typedef enum { +#define _(i,n,s) ILA_TYPE_##i = n, + ila_foreach_type +#undef _ +} ila_type_t; + +#define ila_csum_foreach_type \ +_(NO_ACTION, 0, "no-action") \ +_(NEUTRAL_MAP, 1, "neutral-map") \ +_(ADJUST_TRANSPORT, 2, "adjust-transport") + +typedef enum { +#define _(i,n,s) ILA_CSUM_MODE_##i = n, + ila_csum_foreach_type +#undef _ + ILA_CSUM_N_TYPES +} ila_csum_mode_t; + +#define ila_foreach_direction \ +_(BIDIR, 0, "bidir") \ +_(SIR2ILA, 1, "sir2ila") \ +_(ILA2SIR, 2, "ila2sir") + +typedef enum { +#define _(i,n,s) ILA_DIR_##i = n, + ila_foreach_direction +#undef _ +} ila_direction_t; + +typedef struct { + /** + * Fib Node base class + */ + fib_node_t ila_fib_node; + ila_type_t type; + ip6_address_t sir_address; + ip6_address_t ila_address; + ip6_address_t next_hop; + ila_csum_mode_t csum_mode; + ila_direction_t dir; + + /** + * The FIB entry index for the next-hop + */ + fib_node_index_t next_hop_fib_entry_index; + + /** + * The child index on the FIB entry + */ + u32 next_hop_child_index; + + /** + * The next DPO in the grpah to follow + */ + dpo_id_t ila_dpo; +} ila_entry_t; + +typedef struct { + ila_entry_t *entries; //Pool of ILA entries + + u64 lookup_table_nbuckets; + u64 lookup_table_size; + clib_bihash_24_8_t id_to_entry_table; + + u32 ip6_lookup_next_index; +} ila_main_t; + + +typedef struct { + ila_type_t type; + ip6_address_t sir_address; + ip6_address_t next_hop_address; + u64 locator; + u32 vnid; + u32 local_adj_index; + ila_csum_mode_t csum_mode; + ila_direction_t dir; + u8 is_del; +} ila_add_del_entry_args_t; + +int ila_add_del_entry (ila_add_del_entry_args_t * args); +int ila_interface (u32 sw_if_index, u8 disable); + +#endif //ILA_H diff --git a/src/plugins/sixrd.am b/src/plugins/sixrd.am new file mode 100644 index 00000000000..0de4508831e --- /dev/null +++ b/src/plugins/sixrd.am @@ -0,0 +1,26 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +libsixrd_plugin_la_SOURCES = \ + sixrd/sixrd.c \ + sixrd/sixrd_dpo.c \ + sixrd/ip4_sixrd.c \ + sixrd/ip6_sixrd.c + +noinst_HEADERS += \ + sixrd/sixrd.h \ + sixrd/sixrd_dpo.h + +vppplugins_LTLIBRARIES += libsixrd_plugin.la + +# vi:syntax=automake diff --git a/src/plugins/sixrd/ip4_sixrd.c b/src/plugins/sixrd/ip4_sixrd.c new file mode 100644 index 00000000000..2fb8015d994 --- /dev/null +++ b/src/plugins/sixrd/ip4_sixrd.c @@ -0,0 +1,127 @@ +/*--------------------------------------------------------------------------- + * Copyright (c) 2009-2014 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *--------------------------------------------------------------------------- + */ +#include "sixrd.h" + +static vlib_node_registration_t ip4_sixrd_node; + +typedef enum { + IP4_SIXRD_NEXT_IP6_LOOKUP, + IP4_SIXRD_NEXT_DROP, + IP4_SIXRD_N_NEXT, +} ip4_sixrd_next_t; + +/* + * ip4_sixrd_sec_check + */ +static_always_inline void +ip4_sixrd_sec_check (sixrd_domain_t *d, ip4_address_t sa4, ip6_address_t sa6, u8 *error) +{ + u32 a = sixrd_get_addr(d, sa6.as_u64[0]); + clib_warning("Security check: %U %U", format_ip4_address, &a, format_ip4_address, &sa4); + if (PREDICT_FALSE(sixrd_get_addr(d, sa6.as_u64[0]) != sa4.as_u32)) + *error = SIXRD_ERROR_SEC_CHECK; +} + +/* + * ip4_sixrd + */ +static uword +ip4_sixrd (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip4_sixrd_node.index); + u32 decap = 0; + + from = vlib_frame_vector_args(frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + while (n_left_from > 0) { + vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); + + /* Single loop */ + while (n_left_from > 0 && n_left_to_next > 0) { + u32 pi0; + vlib_buffer_t *p0; + u8 error0 = SIXRD_ERROR_NONE; + sixrd_domain_t *d0 = 0; + ip4_header_t *ip40; + ip6_header_t *ip60; + u32 sixrd_domain_index0 = ~0; + u32 next0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next +=1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer(vm, pi0); + ip40 = vlib_buffer_get_current(p0); + + /* Throw away anything that isn't IP in IP. */ + if (PREDICT_TRUE(ip40->protocol == IP_PROTOCOL_IPV6 && clib_net_to_host_u16(ip40->length) >= 60)) { + vlib_buffer_advance(p0, sizeof(ip4_header_t)); + ip60 = vlib_buffer_get_current(p0); + d0 = ip4_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], (ip6_address_t *)&ip60->src_address, + &sixrd_domain_index0, &error0); + } else { + error0 = SIXRD_ERROR_BAD_PROTOCOL; + } + if (d0) { + /* SIXRD inbound security check */ + ip4_sixrd_sec_check(d0, ip40->src_address, ip60->src_address, &error0); + } + + next0 = error0 == SIXRD_ERROR_NONE ? IP4_SIXRD_NEXT_IP6_LOOKUP : IP4_SIXRD_NEXT_DROP; + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { + sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); + tr->sixrd_domain_index = sixrd_domain_index0; + } + + p0->error = error_node->errors[error0]; + if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) decap++; + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); + + } + vlib_put_next_frame(vm, node, next_index, n_left_to_next); + } + vlib_node_increment_counter(vm, ip4_sixrd_node.index, SIXRD_ERROR_DECAPSULATED, decap); + + return frame->n_vectors; +} + +static char *sixrd_error_strings[] = { +#define _(sym,string) string, + foreach_sixrd_error +#undef _ +}; + +VLIB_REGISTER_NODE(ip4_sixrd_node,static) = { + .function = ip4_sixrd, + .name = "ip4-sixrd", + .vector_size = sizeof(u32), + .format_trace = format_sixrd_trace, + .n_errors = SIXRD_N_ERROR, + .error_strings = sixrd_error_strings, + .n_next_nodes = IP4_SIXRD_N_NEXT, + .next_nodes = { + [IP4_SIXRD_NEXT_IP6_LOOKUP] = "ip6-lookup", + [IP4_SIXRD_NEXT_DROP] = "error-drop", + }, +}; diff --git a/src/plugins/sixrd/ip6_sixrd.c b/src/plugins/sixrd/ip6_sixrd.c new file mode 100644 index 00000000000..36f3fab320b --- /dev/null +++ b/src/plugins/sixrd/ip6_sixrd.c @@ -0,0 +1,129 @@ +/*--------------------------------------------------------------------------- + * Copyright (c) 2009-2014 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *--------------------------------------------------------------------------- + */ +/* + * Defines used for testing various optimisation schemes + */ +#define SIXRD_ENCAP_DUAL 0 + +#include "sixrd.h" + +static vlib_node_registration_t ip6_sixrd_node; + +typedef enum { + IP6_SIXRD_NEXT_IP4_LOOKUP, + IP6_SIXRD_NEXT_DROP, + IP6_SIXRD_N_NEXT, +} ip6_sixrd_next_t; + +/* + * ip6_sixrd + */ +static uword +ip6_sixrd (vlib_main_t *vm, + vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + u32 n_left_from, *from, next_index, *to_next, n_left_to_next; + vlib_node_runtime_t *error_node = vlib_node_get_runtime(vm, ip6_sixrd_node.index); + u32 encap = 0; + from = vlib_frame_vector_args(frame); + n_left_from = frame->n_vectors; + next_index = node->cached_next_index; + + while (n_left_from > 0) { + vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next); + + while (n_left_from > 0 && n_left_to_next > 0) { + u32 pi0; + vlib_buffer_t *p0; + sixrd_domain_t *d0; + u8 error0 = SIXRD_ERROR_NONE; + ip6_header_t *ip60; + ip4_header_t *ip4h0; + u32 next0 = IP6_SIXRD_NEXT_IP4_LOOKUP; + u32 sixrd_domain_index0 = ~0; + + pi0 = to_next[0] = from[0]; + from += 1; + n_left_from -= 1; + to_next +=1; + n_left_to_next -= 1; + + p0 = vlib_get_buffer(vm, pi0); + ip60 = vlib_buffer_get_current(p0); + // p0->current_length = clib_net_to_host_u16(ip40->length); + d0 = ip6_sixrd_get_domain(vnet_buffer(p0)->ip.adj_index[VLIB_TX], &sixrd_domain_index0); + ASSERT(d0); + + /* SIXRD calc */ + u64 dal60 = clib_net_to_host_u64(ip60->dst_address.as_u64[0]); + u32 da40 = sixrd_get_addr(d0, dal60); + u16 len = clib_net_to_host_u16(ip60->payload_length) + 60; + if (da40 == 0) error0 = SIXRD_ERROR_UNKNOWN; + + /* construct ipv4 header */ + vlib_buffer_advance(p0, - (sizeof(ip4_header_t))); + ip4h0 = vlib_buffer_get_current(p0); + vnet_buffer(p0)->sw_if_index[VLIB_TX] = (u32)~0; + ip4h0->ip_version_and_header_length = 0x45; + ip4h0->tos = 0; + ip4h0->length = clib_host_to_net_u16(len); + ip4h0->fragment_id = 0; + ip4h0->flags_and_fragment_offset = 0; + ip4h0->ttl = 0x40; + ip4h0->protocol = IP_PROTOCOL_IPV6; + ip4h0->src_address = d0->ip4_src; + ip4h0->dst_address.as_u32 = clib_host_to_net_u32(da40); + ip4h0->checksum = ip4_header_checksum(ip4h0); + + next0 = error0 == SIXRD_ERROR_NONE ? IP6_SIXRD_NEXT_IP4_LOOKUP : IP6_SIXRD_NEXT_DROP; + + if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED)) { + sixrd_trace_t *tr = vlib_add_trace(vm, node, p0, sizeof(*tr)); + tr->sixrd_domain_index = sixrd_domain_index0; + } + + p0->error = error_node->errors[error0]; + if (PREDICT_TRUE(error0 == SIXRD_ERROR_NONE)) encap++; + + vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, pi0, next0); + } + vlib_put_next_frame(vm, node, next_index, n_left_to_next); + } + vlib_node_increment_counter(vm, ip6_sixrd_node.index, SIXRD_ERROR_ENCAPSULATED, encap); + + return frame->n_vectors; +} + +static char *sixrd_error_strings[] = { +#define _(sym,string) string, + foreach_sixrd_error +#undef _ +}; + +VLIB_REGISTER_NODE(ip6_sixrd_node,static) = { + .function = ip6_sixrd, + .name = "ip6-sixrd", + .vector_size = sizeof(u32), + .format_trace = format_sixrd_trace, + .n_errors = SIXRD_N_ERROR, + .error_strings = sixrd_error_strings, + .n_next_nodes = IP6_SIXRD_N_NEXT, + .next_nodes = { + [IP6_SIXRD_NEXT_IP4_LOOKUP] = "ip4-lookup", + [IP6_SIXRD_NEXT_DROP] = "error-drop", + }, +}; diff --git a/src/plugins/sixrd/sixrd.c b/src/plugins/sixrd/sixrd.c new file mode 100644 index 00000000000..66e631a2b6a --- /dev/null +++ b/src/plugins/sixrd/sixrd.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sixrd.h" +#include + +#include +#include +#include + +/* + * This code supports the following sixrd modes: + * + * 32 EA bits (Complete IPv4 address is embedded): + * ea_bits_len = 32 + * IPv4 suffix is embedded: + * ea_bits_len = < 32 + * No embedded address bits (1:1 mode): + * ea_bits_len = 0 + */ + +int +sixrd_create_domain (ip6_address_t *ip6_prefix, + u8 ip6_prefix_len, + ip4_address_t *ip4_prefix, + u8 ip4_prefix_len, + ip4_address_t *ip4_src, + u32 *sixrd_domain_index, + u16 mtu) +{ + dpo_id_t dpo_v6 = DPO_INVALID, dpo_v4 = DPO_INVALID; + sixrd_main_t *mm = &sixrd_main; + fib_node_index_t fei; + sixrd_domain_t *d; + + /* Get domain index */ + pool_get_aligned(mm->domains, d, CLIB_CACHE_LINE_BYTES); + memset(d, 0, sizeof (*d)); + *sixrd_domain_index = d - mm->domains; + + /* Init domain struct */ + d->ip4_prefix.as_u32 = ip4_prefix->as_u32; + d->ip4_prefix_len = ip4_prefix_len; + d->ip6_prefix = *ip6_prefix; + d->ip6_prefix_len = ip6_prefix_len; + d->ip4_src = *ip4_src; + d->mtu = mtu; + + if (ip4_prefix_len < 32) + d->shift = 64 - ip6_prefix_len + (32 - ip4_prefix_len); + + /* Create IPv6 route/adjacency */ + fib_prefix_t pfx6 = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = d->ip6_prefix_len, + .fp_addr = { + .ip6 = d->ip6_prefix, + }, + }; + sixrd_dpo_create(DPO_PROTO_IP6, + *sixrd_domain_index, + &dpo_v6); + fib_table_entry_special_dpo_add(0, &pfx6, + FIB_SOURCE_SIXRD, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo_v6); + dpo_reset (&dpo_v6); + + /* + * Multiple SIXRD domains may share same source IPv4 TEP + * In this case the route will exist and be SixRD sourced. + * Find the adj (if any) already contributed and modify it + */ + fib_prefix_t pfx4 = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = { + .ip4 = d->ip4_src, + }, + }; + fei = fib_table_lookup_exact_match(0, &pfx4); + + if (FIB_NODE_INDEX_INVALID != fei) + { + dpo_id_t dpo = DPO_INVALID; + + if (fib_entry_get_dpo_for_source (fei, FIB_SOURCE_SIXRD, &dpo)) + { + /* + * modify the existing adj to indicate it's shared + * skip to route add. + * It is locked to pair with the unlock below. + */ + const dpo_id_t *sd_dpo; + sixrd_dpo_t *sd; + + ASSERT(DPO_LOAD_BALANCE == dpo.dpoi_type); + + sd_dpo = load_balance_get_bucket(dpo.dpoi_index, 0); + sd = sixrd_dpo_get (sd_dpo->dpoi_index); + + sd->sd_domain = ~0; + dpo_copy (&dpo_v4, sd_dpo); + dpo_reset (&dpo); + + goto route_add; + } + } + /* first time addition of the route */ + sixrd_dpo_create(DPO_PROTO_IP4, + *sixrd_domain_index, + &dpo_v4); + +route_add: + /* + * Create ip4 route. This is a reference counted add. If the prefix + * already exists and is SixRD sourced, it is now SixRD source n+1 times + * and will need to be removed n+1 times. + */ + fib_table_entry_special_dpo_add(0, &pfx4, + FIB_SOURCE_SIXRD, + FIB_ENTRY_FLAG_EXCLUSIVE, + &dpo_v4); + dpo_reset (&dpo_v4); + + return 0; +} + +/* + * sixrd_delete_domain + */ +int +sixrd_delete_domain (u32 sixrd_domain_index) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + + if (pool_is_free_index(mm->domains, sixrd_domain_index)) { + clib_warning("SIXRD domain delete: domain does not exist: %d", + sixrd_domain_index); + return -1; + } + + d = pool_elt_at_index(mm->domains, sixrd_domain_index); + + fib_prefix_t pfx = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = { + .ip4 = d->ip4_src, + }, + }; + fib_table_entry_special_remove(0, &pfx, FIB_SOURCE_SIXRD); + + fib_prefix_t pfx6 = { + .fp_proto = FIB_PROTOCOL_IP6, + .fp_len = d->ip6_prefix_len, + .fp_addr = { + .ip6 = d->ip6_prefix, + }, + }; + fib_table_entry_special_remove(0, &pfx6, FIB_SOURCE_SIXRD); + + pool_put(mm->domains, d); + + return 0; +} + +static clib_error_t * +sixrd_add_domain_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + ip4_address_t ip4_prefix; + ip6_address_t ip6_prefix; + ip4_address_t ip4_src; + u32 ip6_prefix_len=0, ip4_prefix_len=0, sixrd_domain_index; + u32 num_m_args = 0; + /* Optional arguments */ + u32 mtu = 0; + + /* Get a line of input. */ + if (!unformat_user(input, unformat_line_input, line_input)) + return 0; + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { + if (unformat(line_input, "ip6-pfx %U/%d", unformat_ip6_address, &ip6_prefix, &ip6_prefix_len)) + num_m_args++; + else if (unformat(line_input, "ip4-pfx %U/%d", unformat_ip4_address, &ip4_prefix, &ip4_prefix_len)) + num_m_args++; + else if (unformat(line_input, "ip4-src %U", unformat_ip4_address, &ip4_src)) + num_m_args++; + else if (unformat(line_input, "mtu %d", &mtu)) + num_m_args++; + else + return clib_error_return(0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free(line_input); + + if (num_m_args < 3) + return clib_error_return(0, "mandatory argument(s) missing"); + + sixrd_create_domain(&ip6_prefix, ip6_prefix_len, &ip4_prefix, ip4_prefix_len, + &ip4_src, &sixrd_domain_index, mtu); + + return 0; +} + +static clib_error_t * +sixrd_del_domain_command_fn (vlib_main_t *vm, + unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u32 num_m_args = 0; + u32 sixrd_domain_index; + + /* Get a line of input. */ + if (! unformat_user(input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input(line_input) != UNFORMAT_END_OF_INPUT) { + if (unformat(line_input, "index %d", &sixrd_domain_index)) + num_m_args++; + else + return clib_error_return(0, "unknown input `%U'", + format_unformat_error, input); + } + unformat_free(line_input); + + if (num_m_args != 1) + return clib_error_return(0, "mandatory argument(s) missing"); + + sixrd_delete_domain(sixrd_domain_index); + + return 0; +} + +static u8 * +format_sixrd_domain (u8 *s, va_list *args) +{ + sixrd_domain_t *d = va_arg(*args, sixrd_domain_t *); + sixrd_main_t *mm = &sixrd_main; + + s = format(s, + "[%d] ip6-pfx %U/%d ip4-pfx %U/%d ip4-src %U mtu %d", + d - mm->domains, + format_ip6_address, &d->ip6_prefix, d->ip6_prefix_len, + format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len, + format_ip4_address, &d->ip4_src, d->mtu); + + return s; +} + +static clib_error_t * +show_sixrd_domain_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + + if (pool_elts(mm->domains) == 0) + vlib_cli_output(vm, "No SIXRD domains are configured..."); + + pool_foreach(d, mm->domains, ({vlib_cli_output(vm, "%U", format_sixrd_domain, d);})); + + return 0; + +} + +static clib_error_t * +show_sixrd_stats_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_domain_t *d; + int domains = 0, domaincount = 0; + if (pool_elts (mm->domains) == 0) + vlib_cli_output (vm, "No SIXRD domains are configured..."); + + pool_foreach(d, mm->domains, ({ + domains += sizeof(*d); + domaincount++; + })); + + vlib_cli_output(vm, "SIXRD domains structure: %d\n", sizeof (sixrd_domain_t)); + vlib_cli_output(vm, "SIXRD domains: %d (%d bytes)\n", domaincount, domains); + + return 0; +} + +/* + * packet trace format function + */ +u8 * +format_sixrd_trace (u8 *s, va_list *args) +{ + CLIB_UNUSED(vlib_main_t *vm) = va_arg (*args, vlib_main_t *); + CLIB_UNUSED(vlib_node_t *node) = va_arg (*args, vlib_node_t *); + sixrd_trace_t *t = va_arg (*args, sixrd_trace_t *); + u32 sixrd_domain_index = t->sixrd_domain_index; + + s = format(s, "SIXRD domain index: %d", sixrd_domain_index); + + return s; +} + +VLIB_CLI_COMMAND(sixrd_add_domain_command, static) = { + .path = "sixrd add domain", + .short_help = + "sixrd add domain ip6-pfx ip4-pfx ip4-src ", + .function = sixrd_add_domain_command_fn, +}; + +VLIB_CLI_COMMAND(sixrd_del_command, static) = { + .path = "sixrd del domain", + .short_help = + "sixrd del domain index ", + .function = sixrd_del_domain_command_fn, +}; + +VLIB_CLI_COMMAND(show_sixrd_domain_command, static) = { + .path = "show sixrd domain", + .function = show_sixrd_domain_command_fn, +}; + +VLIB_CLI_COMMAND(show_sixrd_stats_command, static) = { + .path = "show sixrd stats", + .function = show_sixrd_stats_command_fn, +}; + +/* + * This routine exists to convince the vlib plugin framework that + * we haven't accidentally copied a random .dll into the plugin directory. + * + * Also collects global variable pointers passed from the vpp engine + */ +clib_error_t * +vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h, + int from_early_init) +{ + clib_error_t * error = 0; + sixrd_main_t *mm = &sixrd_main; + + mm->vnet_main = vnet_get_main(); + mm->vlib_main = vm; + + return error; +} + +static clib_error_t * sixrd_init (vlib_main_t * vm) +{ + sixrd_dpo_module_init (); + + return (NULL); +} + +VLIB_INIT_FUNCTION (sixrd_init); diff --git a/src/plugins/sixrd/sixrd.h b/src/plugins/sixrd/sixrd.h new file mode 100644 index 00000000000..56714c9e3bd --- /dev/null +++ b/src/plugins/sixrd/sixrd.h @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------- + * Copyright (c) 2009-2014 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *--------------------------------------------------------------------------- + */ +#include +#include +#include +#include +#include + +#include "sixrd_dpo.h" + +int sixrd_create_domain(ip6_address_t *ip6_prefix, u8 ip6_prefix_len, + ip4_address_t *ip4_prefix, u8 ip4_prefix_len, + ip4_address_t *ip4_src, u32 *sixrd_domain_index, u16 mtu); +int sixrd_delete_domain(u32 sixrd_domain_index); +u8 *format_sixrd_trace(u8 *s, va_list *args); + +typedef struct { + ip6_address_t ip6_prefix; + ip4_address_t ip4_prefix; + ip4_address_t ip4_src; + u8 ip6_prefix_len; + u8 ip4_prefix_len; + + /* helpers */ + u8 shift; + + u16 mtu; +} sixrd_domain_t; + +typedef struct { + /* pool of SIXRD domains */ + sixrd_domain_t *domains; + + /* convenience */ + vlib_main_t *vlib_main; + vnet_main_t *vnet_main; +} sixrd_main_t; + +#define foreach_sixrd_error \ + /* Must be first. */ \ + _(NONE, "valid SIXRD packets") \ + _(BAD_PROTOCOL, "bad protocol") \ + _(WRONG_ICMP_TYPE, "wrong icmp type") \ + _(SEC_CHECK, "security check failed") \ + _(ICMP, "unable to translate ICMP") \ + _(UNKNOWN, "unknown") \ + _(NO_DOMAIN, "no domain") \ + _(ENCAPSULATED, "encapsulated") \ + _(DECAPSULATED, "decapsulated") \ + _(TRANSLATED_4TO6, "translated 4 to 6") \ + _(TRANSLATED_6TO4, "translated 6 to 4") \ + _(FRAGMENT, "fragment handling error") \ + _(FRAGMENT_QUEUED, "dropped, missing first fragment") \ + _(FRAGMENTED, "packets requiring fragmentation") \ + _(FRAGMENT_PARTS, "fragment parts") \ + _(MALFORMED, "malformed packet") + +typedef enum { +#define _(sym,str) SIXRD_ERROR_##sym, + foreach_sixrd_error +#undef _ + SIXRD_N_ERROR, + } sixrd_error_t; + +typedef struct { + u32 sixrd_domain_index; +} sixrd_trace_t; + +sixrd_main_t sixrd_main; + +/* + * sixrd_get_addr + */ +static_always_inline u32 +sixrd_get_addr (sixrd_domain_t *d, u64 dal) +{ + + /* 1:1 mode */ + if (d->ip4_prefix_len == 32) return (d->ip4_prefix.as_u32); + + /* Grab 32 - ip4_prefix_len bits out of IPv6 address from offset ip6_prefix_len */ + return (d->ip4_prefix.as_u32 | (u32)(dal >> d->shift)); +} + +/* + * Get the SIXRD domain from an IPv6 lookup adjacency. + */ +static_always_inline sixrd_domain_t * +ip6_sixrd_get_domain (u32 sdi, u32 *sixrd_domain_index) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(sdi); + + ASSERT(sd); + *sixrd_domain_index = sd->sd_domain; + return pool_elt_at_index(mm->domains, *sixrd_domain_index); +} + +/* + * Get the SIXRD domain from an IPv4 lookup adjacency. + * If the IPv4 address is not shared, no lookup is required. + * The IPv6 address is used otherwise. + */ +static_always_inline sixrd_domain_t * +ip4_sixrd_get_domain (u32 sdi, ip6_address_t *addr, + u32 *sixrd_domain_index, u8 *error) +{ + sixrd_main_t *mm = &sixrd_main; + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(sdi); + *sixrd_domain_index = sd->sd_domain; + if (*sixrd_domain_index != ~0) + return pool_elt_at_index(mm->domains, *sixrd_domain_index); + + u32 lbi = ip6_fib_table_fwding_lookup(&ip6_main, 0, addr); + const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0); + if (PREDICT_TRUE(dpo->dpoi_type == sixrd_dpo_type)) + { + sd = sixrd_dpo_get(dpo->dpoi_index); + *sixrd_domain_index = sd->sd_domain; + return pool_elt_at_index(mm->domains, *sixrd_domain_index); + } + *error = SIXRD_ERROR_NO_DOMAIN; + return NULL; +} diff --git a/src/plugins/sixrd/sixrd_dpo.c b/src/plugins/sixrd/sixrd_dpo.c new file mode 100644 index 00000000000..88a079350a3 --- /dev/null +++ b/src/plugins/sixrd/sixrd_dpo.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sixrd_dpo.h" +#include + +/** + * pool of all MPLS Label DPOs + */ +sixrd_dpo_t *sixrd_dpo_pool; + +/** + * The register SIXRD DPO type + */ +dpo_type_t sixrd_dpo_type; + +static sixrd_dpo_t * +sixrd_dpo_alloc (void) +{ + sixrd_dpo_t *sd; + + pool_get_aligned(sixrd_dpo_pool, sd, CLIB_CACHE_LINE_BYTES); + memset(sd, 0, sizeof(*sd)); + + return (sd); +} + +static index_t +sixrd_dpo_get_index (sixrd_dpo_t *sd) +{ + return (sd - sixrd_dpo_pool); +} + +void +sixrd_dpo_create (dpo_proto_t dproto, + u32 domain_index, + dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_alloc(); + sd->sd_domain = domain_index; + sd->sd_proto = dproto; + + dpo_set(dpo, + sixrd_dpo_type, + dproto, + sixrd_dpo_get_index(sd)); +} + +u8* +format_sixrd_dpo (u8 *s, va_list *args) +{ + index_t index = va_arg (*args, index_t); + CLIB_UNUSED(u32 indent) = va_arg (*args, u32); + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(index); + + return (format(s, "sixrd:[%d]:%U domain:%d", + index, + format_dpo_proto, sd->sd_proto, + sd->sd_domain)); +} + + +static void +sixrd_dpo_lock (dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(dpo->dpoi_index); + + sd->sd_locks++; +} + +static void +sixrd_dpo_unlock (dpo_id_t *dpo) +{ + sixrd_dpo_t *sd; + + sd = sixrd_dpo_get(dpo->dpoi_index); + + sd->sd_locks--; + + if (0 == sd->sd_locks) + { + pool_put(sixrd_dpo_pool, sd); + } +} + +const static dpo_vft_t sd_vft = { + .dv_lock = sixrd_dpo_lock, + .dv_unlock = sixrd_dpo_unlock, + .dv_format = format_sixrd_dpo, +}; + +const static char* const sixrd_ip4_nodes[] = +{ + "ip4-sixrd", + NULL, +}; +const static char* const sixrd_ip6_nodes[] = +{ + "ip6-sixrd", + NULL, +}; + +const static char* const * const sixrd_nodes[DPO_PROTO_NUM] = +{ + [DPO_PROTO_IP4] = sixrd_ip4_nodes, + [DPO_PROTO_IP6] = sixrd_ip6_nodes, + [DPO_PROTO_MPLS] = NULL, +}; + +void +sixrd_dpo_module_init (void) +{ + sixrd_dpo_type = dpo_register_new_type(&sd_vft, sixrd_nodes); +} diff --git a/src/plugins/sixrd/sixrd_dpo.h b/src/plugins/sixrd/sixrd_dpo.h new file mode 100644 index 00000000000..17142288451 --- /dev/null +++ b/src/plugins/sixrd/sixrd_dpo.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SIXRD_DPO_H__ +#define __SIXRD_DPO_H__ + +#include +#include + +/** + * A representation of a 6RD DPO + */ +typedef struct sixrd_dpo_t +{ + /** + * The dat-plane protocol + */ + dpo_proto_t sd_proto; + + /** + * the SIXRD domain index + */ + u32 sd_domain; + + /** + * Number of locks/users of the label + */ + u16 sd_locks; +} sixrd_dpo_t; + +extern void sixrd_dpo_create (dpo_proto_t dproto, + u32 domain_index, + dpo_id_t *dpo); + +/* + * Encapsulation violation for fast data-path access + */ +extern sixrd_dpo_t *sixrd_dpo_pool; +extern dpo_type_t sixrd_dpo_type; + +static inline sixrd_dpo_t * +sixrd_dpo_get (index_t index) +{ + return (pool_elt_at_index(sixrd_dpo_pool, index)); +} + +extern void sixrd_dpo_module_init(void); + +#endif diff --git a/src/scripts/vnet/arp4 b/src/scripts/vnet/arp4 new file mode 100644 index 00000000000..acb20da33c8 --- /dev/null +++ b/src/scripts/vnet/arp4 @@ -0,0 +1,21 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + +trace add pg-input 100 +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 diff --git a/src/scripts/vnet/arp4-mpls b/src/scripts/vnet/arp4-mpls new file mode 100644 index 00000000000..d3d39f3b921 --- /dev/null +++ b/src/scripts/vnet/arp4-mpls @@ -0,0 +1,24 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.2.2.2 + ICMP echo_request + incrementing 100 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +trace add pg-input 100 diff --git a/src/scripts/vnet/arp6 b/src/scripts/vnet/arp6 new file mode 100644 index 00000000000..e6a98935309 --- /dev/null +++ b/src/scripts/vnet/arp6 @@ -0,0 +1,21 @@ +packet-generator new { + name x + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + ICMP6: 2000::2 -> 2001::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 2000::1/64 +set int ip address loop1 2001::1/64 diff --git a/src/scripts/vnet/bvi b/src/scripts/vnet/bvi new file mode 100644 index 00000000000..2174da0db63 --- /dev/null +++ b/src/scripts/vnet/bvi @@ -0,0 +1,76 @@ + + +set int state tuntap-0 down +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 + +set int state GigabitEthernet2/1/0 up +cre sub GigabitEthernet2/1/0 1 dot1q 7 +set int state GigabitEthernet2/1/0.1 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up + + +loop create +set int l2 bridge loop0 0 bvi +set int ip table loop0 0 +set int state loop0 up + + +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +set int l2 tag-rewrite GigabitEthernet2/1/0.1 pop 1 +set int l2 tag-rewrite GigabitEthernet2/2/0.1 pop 1 + +l2fib add 00:22:44:06:08:0a 0 GigabitEthernet2/1/0.1 static +l2fib add 00:02:04:06:08:0a 0 GigabitEthernet2/2/0.1 static + + +ip route table 0 8.0.0.1/32 via loop0 +set ip arp loop0 8.0.0.1 00:02:04:06:08:0a + + +ip route add 1.2.3.3/32 via GigabitEthernet2/1/0 IP4: 00:15:17:61:73:47 -> 00:15:17:61:73:46 + +cle er +cle int +cle run + +packet-generator new { + name bvi_to_l2 + limit 100 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 1.2.3.3 -> 8.0.0.1 mpls_unicast + } +} + +packet-generator new { + name l2_to_bvi + limit 50 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP4: 0050.56b7.7c83 -> dead.0000.0000 vlan 9 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name l2_to_bvi_via_flood + limit 25 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP4: 0050.56b7.7c83 -> ffff.ffff.ffff vlan 9 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + diff --git a/src/scripts/vnet/dhcp/dhcpd.conf b/src/scripts/vnet/dhcp/dhcpd.conf new file mode 100644 index 00000000000..d4cb3ed718a --- /dev/null +++ b/src/scripts/vnet/dhcp/dhcpd.conf @@ -0,0 +1,8 @@ +# add at the bottom + +subnet 192.168.0.0 netmask 255.255.0.0 { + range 192.168.1.10 192.168.1.254; + option routers 192.168.1.1; + default-lease-time 15; + max-lease-time 15; +} diff --git a/src/scripts/vnet/dhcp/left-ping-target.sh b/src/scripts/vnet/dhcp/left-ping-target.sh new file mode 100644 index 00000000000..2edc2a50eaa --- /dev/null +++ b/src/scripts/vnet/dhcp/left-ping-target.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# to obtain dhcp address from leftpeer +dhclient -d -v eth1 diff --git a/src/scripts/vnet/dhcp/leftpeer.conf b/src/scripts/vnet/dhcp/leftpeer.conf new file mode 100644 index 00000000000..458eecf0caf --- /dev/null +++ b/src/scripts/vnet/dhcp/leftpeer.conf @@ -0,0 +1,17 @@ +set int ip table GigabitEthernet2/2/0 12 +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +set int ip table GigabitEthernet2/7/0 11 +set int ip address GigabitEthernet2/7/0 192.168.2.1/24 +set int state GigabitEthernet2/7/0 up + +comment { set dhcp proxy server 1.2.3.4 src-address 1.2.3.5 add-option-82 rx-fib-id 0 server-fib-id 0 } + +comment { set dhcp proxy server 192.168.2.2 src-address 192.168.2.1 add-option-82 rx-fib-id 12 server-fib-id 11 } + +ip route add 0.0.0.0/24 table 11 via local +ip route add 255.255.255.255/24 table 11 via local + +ip route add 0.0.0.0/24 table 12 via local +ip route add 255.255.255.255/24 table 12 via local diff --git a/src/scripts/vnet/icmp b/src/scripts/vnet/icmp new file mode 100644 index 00000000000..1e054e2df4a --- /dev/null +++ b/src/scripts/vnet/icmp @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vnet/icmp6 b/src/scripts/vnet/icmp6 new file mode 100644 index 00000000000..2a65acba256 --- /dev/null +++ b/src/scripts/vnet/icmp6 @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + ICMP6: ::1 -> ::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route ::1/128 via local +ip route ::2/128 via local diff --git a/src/scripts/vnet/ige b/src/scripts/vnet/ige new file mode 100644 index 00000000000..80d045af36d --- /dev/null +++ b/src/scripts/vnet/ige @@ -0,0 +1,19 @@ +packet-generator new { + name x + limit 1 + node ip4-lookup + size 50-50 + data { + ICMP: 1.0.0.1 -> 1.0.0.3 ttl 1 + incrementing 30 + } +} + +comment { tr add pg-input 100 } +set int ip address GigabitEthernet4/0/0 1.0.0.1/24 +set int ip address GigabitEthernet4/0/1 1.0.0.2/24 +set int state GigabitEthernet4/0/0 up +set int state GigabitEthernet4/0/1 up + +ip route add 1.0.0.3/32 via GigabitEthernet4/0/1 IP4: 00:15:17:61:73:47 -> 00:15:17:61:73:46 +tr add ige-input 10 diff --git a/src/scripts/vnet/ip6 b/src/scripts/vnet/ip6 new file mode 100644 index 00000000000..4f9f3ee5474 --- /dev/null +++ b/src/scripts/vnet/ip6 @@ -0,0 +1,15 @@ +packet-generator new { + name x + limit 1 + node ethernet-input + size 64-64 + no-recycle + data { + IP6: 1.2.3 -> 4.5.6 + ICMP: ::1 -> ::2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 diff --git a/src/scripts/vnet/ip6-hbh b/src/scripts/vnet/ip6-hbh new file mode 100644 index 00000000000..0c6de47f100 --- /dev/null +++ b/src/scripts/vnet/ip6-hbh @@ -0,0 +1,84 @@ +tap connect tap0 +set int state tap-0 up +set int ip address tap-0 1::1/64 +packet-generator new { + name hbh1 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3B00010403040506 + incrementing 100 + } +} +packet-generator new { + name hbh2 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3B00C10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh3 + limit 1 + node ip6-input + size 48-48 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3BffC10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh4 + limit 1 + node ip6-input + size 64-64 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + hex 0x3BffC10403040506 + incrementing 100 + } +} + +packet-generator new { + name hbh5 + limit 1 + node ip6-input + size 56-56 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + length 16 + hex 0x3B010104030405060106030405060708 + incrementing 100 + } +} + +packet-generator new { + name hbh6 + limit 1 + node ip6-input + size 56-56 + no-recycle + data { + IP6_HOP_BY_HOP_OPTIONS: 1::2 -> 1::2 + length 16 + hex 0x3a00050200000100 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 diff --git a/src/scripts/vnet/ixge b/src/scripts/vnet/ixge new file mode 100644 index 00000000000..6722b5369cd --- /dev/null +++ b/src/scripts/vnet/ixge @@ -0,0 +1,15 @@ +packet-generator new { + name x + limit 1 + node ip4-lookup + size 50-50 + data { + ICMP: 1.0.0.1 -> 1.0.0.3 ttl 1 + incrementing 30 + } +} + +comment { tr add pg-input 100 } +set int ip address TenGigabitEthernet5/0/0 33.0.1.1/8 +set int state TenGigabitEthernet5/0/0 up + diff --git a/src/scripts/vnet/l2efpfilter b/src/scripts/vnet/l2efpfilter new file mode 100644 index 00000000000..307b4436e81 --- /dev/null +++ b/src/scripts/vnet/l2efpfilter @@ -0,0 +1,83 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/1/0.2 0 +set int l2 bridge GigabitEthernet2/1/0.3 0 +set int l2 bridge GigabitEthernet2/2/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.100 0 + +set int l2 tag-rewrite GigabitEthernet2/2/0.1 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 translate 1-1 dot1q 100 +set int l2 tag-rewrite GigabitEthernet2/1/0.3 translate 1-1 dot1q 99 + +set int l2 efp-filter GigabitEthernet2/2/0 +set int l2 efp-filter GigabitEthernet2/2/0.1 +set int l2 efp-filter GigabitEthernet2/2/0.100 + + +l2fib add 00:00:00:00:00:11 0 GigabitEthernet2/2/0.1 static +l2fib add 00:00:00:00:00:22 0 GigabitEthernet2/2/0.100 static + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.100 up + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name pre_vtr_fail + limit 10 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:11 vlan 1 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name post_vtr_pass + limit 20 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 2 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + +packet-generator new { + name post_vtr_fail + limit 50 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 3 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} + diff --git a/src/scripts/vnet/l2efpfilter_perf b/src/scripts/vnet/l2efpfilter_perf new file mode 100644 index 00000000000..b2f4b490cb8 --- /dev/null +++ b/src/scripts/vnet/l2efpfilter_perf @@ -0,0 +1,58 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/1/0.1 0 +set int l2 bridge GigabitEthernet2/1/0.2 0 +set int l2 bridge GigabitEthernet2/1/0.3 0 +set int l2 bridge GigabitEthernet2/2/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 +set int l2 bridge GigabitEthernet2/2/0.100 0 + +set int l2 tag-rewrite GigabitEthernet2/2/0.1 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 translate 1-1 dot1q 100 +set int l2 tag-rewrite GigabitEthernet2/1/0.3 translate 1-1 dot1q 99 + +set int l2 efp-filter GigabitEthernet2/2/0 +set int l2 efp-filter GigabitEthernet2/2/0.1 +set int l2 efp-filter GigabitEthernet2/2/0.100 + + +l2fib add 00:00:00:00:00:11 0 GigabitEthernet2/2/0.1 static +l2fib add 00:00:00:00:00:22 0 GigabitEthernet2/2/0.100 static + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.100 up + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name post_vtr_pass + limit 9111003 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 00:00:00:00:00:22 vlan 2 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } +} diff --git a/src/scripts/vnet/l2fib b/src/scripts/vnet/l2fib new file mode 100644 index 00000000000..81ede171ef2 --- /dev/null +++ b/src/scripts/vnet/l2fib @@ -0,0 +1,46 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int acl input GigabitEthernet2/1/0 +set int acl output GigabitEthernet2/1/0 +set int acl input GigabitEthernet2/2/0.1 +set int acl output GigabitEthernet2/2/0.1 + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +set int l2 tag-rewrite GigabitEthernet2/1/0 push dot1q 50 +set int l2 tag-rewrite GigabitEthernet2/2/0.1 pop 1 + + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name new_input_if_index_mac_move + limit 4 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + size 98-98 + data { hex 0x00010203040500020406080a080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + +packet-generator new { + name dmac_hit + limit 7 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + size 98-98 + data { hex 0x00020406080a00224406080a8100000981000011080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} diff --git a/src/scripts/vnet/l2fib_perf b/src/scripts/vnet/l2fib_perf new file mode 100644 index 00000000000..638317ff705 --- /dev/null +++ b/src/scripts/vnet/l2fib_perf @@ -0,0 +1,29 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int l2 bridge GigabitEthernet2/1/0 0 +set int l2 bridge GigabitEthernet2/2/0.1 0 + +l2fib add 00:22:44:06:08:0a 0 GigabitEthernet2/1/0 static +l2fib add 00:02:04:06:08:0a 0 GigabitEthernet2/2/0.1 static + +cle er +cle int +cle run + +packet-generator new { + name perf + limit 9111003 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0.1 + size 98-98 + data { hex 0x00224406080a00020406080a81000009080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + diff --git a/src/scripts/vnet/l2fib_xc b/src/scripts/vnet/l2fib_xc new file mode 100644 index 00000000000..35d7342b3f7 --- /dev/null +++ b/src/scripts/vnet/l2fib_xc @@ -0,0 +1,31 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up + +set int state GigabitEthernet2/2/0 up +cre sub GigabitEthernet2/2/0 1 dot1q 9 +set int state GigabitEthernet2/2/0.1 up +set int state tuntap-0 down + +set int acl input GigabitEthernet2/1/0 +set int acl output GigabitEthernet2/1/0 +set int acl input GigabitEthernet2/2/0.1 +set int acl output GigabitEthernet2/2/0.1 + +set int l2 xc GigabitEthernet2/1/0 GigabitEthernet2/2/0.1 +set int l2 xc GigabitEthernet2/2/0.1 GigabitEthernet2/1/0 + +clear error +clear run +clear int + +packet-generator new { + name xc + limit 11 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + size 98-98 + data { hex 0x00010203040500020406080a080045006402b46b96000100096978676265000500bf436973636f20494f5320536f6674776172652c2040160011000000010101cc000400000000001a00100000000100000000ffffffff } +} + diff --git a/src/scripts/vnet/l2flood b/src/scripts/vnet/l2flood new file mode 100644 index 00000000000..013462cef64 --- /dev/null +++ b/src/scripts/vnet/l2flood @@ -0,0 +1,42 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +loop create +cre sub loop0 1 dot1q 1 +cre sub loop0 2 dot1q 2 +cre sub loop0 3 dot1q 3 +cre sub GigabitEthernet2/1/0 1 dot1q 1 + + +set int l2 bridge loop0.1 7 +set int l2 bridge loop0.2 7 +set int l2 bridge loop0.3 7 +set int l2 bridge GigabitEthernet2/1/0.1 7 + +loop cre +set int l2 bridge loop1 7 bvi + +set int state GigabitEthernet2/1/0.1 up + +trace add pg-input 6 + +clear error +clear run +clear int + +packet-generator new { + name flood + limit 1 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> ffff.ffff.ffff vlan 1 + GRE: 8.0.0.1 -> 1.2.3.3 mpls_unicast + } + +} + diff --git a/src/scripts/vnet/l2tp b/src/scripts/vnet/l2tp new file mode 100644 index 00000000000..337805aa44c --- /dev/null +++ b/src/scripts/vnet/l2tp @@ -0,0 +1,134 @@ + +set int ip address GigabitEthernet2/1/0 1.2.3.4/24 +set int state GigabitEthernet2/1/0 up +set int state tuntap-0 down + + +cre sub GigabitEthernet2/1/0 1 dot1q 1 +cre sub GigabitEthernet2/1/0 2 dot1q 2 +cre sub GigabitEthernet2/1/0 3 dot1q 3 +cre sub GigabitEthernet2/2/0 1 dot1q 1 +cre sub GigabitEthernet2/2/0 100 dot1q 100 + + +set int l2 tag-rewrite GigabitEthernet2/1/0.1 pop 1 +set int l2 tag-rewrite GigabitEthernet2/1/0.2 pop 1 + + +l2tp session add client 11::1 our 22::2 l2-interface GigabitEthernet2/1/0.1 +l2tp session add client 11::1 our 22::3 l2-interface GigabitEthernet2/1/0.2 local-session-id 2 l2-sublayer-present + +ip route 11::1/128 via GigabitEthernet2/2/0 +set ip6 neighbor GigabitEthernet2/2/0 11::1 00:02:04:06:08:0a + +enable ip6 interface GigabitEthernet2/2/0 + +set int ip6 l2tpv3 GigabitEthernet2/2/0 + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/1/0.1 up +set int state GigabitEthernet2/1/0.2 up +set int state GigabitEthernet2/1/0.3 up +set int state GigabitEthernet2/2/0 up + + +trace add pg-input 2 + +clear error +clear run +clear int + +packet-generator new { + name decap + limit 10 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 1 cookie 0xffffffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_bad_sid + limit 30 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 0x999 cookie 0xffffffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_bad_cookie + limit 50 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::2 + L2TP: session_id 1 cookie 0x3333ffffffffffff + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name encap + limit 100 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0000.5555.0002 -> 00:00:dd:dd:00:02 vlan 1 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name decap_sublayer + limit 300 + size 200-200 + no-recycle + node ethernet-input + interface GigabitEthernet2/2/0 + data { + IP6: 00:50:00:00:00:01 -> 00:50:56:b7:29:7a + L2TP: 11::1 -> 22::3 + L2TP: session_id 2 cookie 0xffffffffffffffff l2_sublayer 0 + IP4: 00:55:55:55:00:01 -> 00:dd:dd:dd:00:01 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + +packet-generator new { + name encap_sublayer + limit 700 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0000.5555.0002 -> 00:00:dd:dd:00:02 vlan 2 + UDP: 1.2.3.4 -> 5.6.7.8 + incrementing 8 + } +} + diff --git a/src/scripts/vnet/leftpeer/leftpeer-classify b/src/scripts/vnet/leftpeer/leftpeer-classify new file mode 100755 index 00000000000..74285912aeb --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classify @@ -0,0 +1,8 @@ +classify table mask l2 src l3 ip4 src buckets 2 miss-next local + +comment { classify table mask l3 ip4 src buckets 2 miss-next local } +set ip classify intfc GigabitEthernet2/2/0 table-index 0 +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +classify session hit-next local table-index 0 match l2 src 00:50:56:b7:05:bb l3 ip4 src 192.168.1.2 diff --git a/src/scripts/vnet/leftpeer/leftpeer-classify6 b/src/scripts/vnet/leftpeer/leftpeer-classify6 new file mode 100644 index 00000000000..6579d50d3c5 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classify6 @@ -0,0 +1,5 @@ +classify table mask l3 ip6 src buckets 2 miss-next local +set ip6 classify intfc GigabitEthernet2/2/0 table-index 0 +set int ip address GigabitEthernet2/2/0 db01::1/64 +set int state GigabitEthernet2/2/0 up +classify session hit-next local table-index 0 match l3 ip6 src db01::2 diff --git a/src/scripts/vnet/leftpeer/leftpeer-classifyl2 b/src/scripts/vnet/leftpeer/leftpeer-classifyl2 new file mode 100644 index 00000000000..6be4b1e52cf --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-classifyl2 @@ -0,0 +1,8 @@ +set int ip address GigabitEthernet2/2/0 192.168.1.1/24 +set int state GigabitEthernet2/2/0 up + +classify table mask l3 ip4 src buckets 2 l2-miss-next ethernet + +classify session advance 14 l2-hit-next ip4 table-index 0 match l3 ip4 src 192.168.1.2 + +set int l2 class intfc GigabitEthernet2/2/0 ip4-table 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-dhcp b/src/scripts/vnet/leftpeer/leftpeer-dhcp new file mode 100644 index 00000000000..c13a8f3aa5e --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-dhcp @@ -0,0 +1,23 @@ +loop cre +set int ip table loop0 12 +set int ip address loop0 192.168.1.1/24 +set int state loop0 up + +set int ip table GigabitEthernet2/2/0 12 +comment { set int ip address GigabitEthernet2/2/0 192.168.1.1/24 } +set int unnumbered GigabitEthernet2/2/0 use loop0 +set int state GigabitEthernet2/2/0 up + +set int ip table GigabitEthernet2/7/0 11 +set int ip address GigabitEthernet2/7/0 192.168.2.1/24 +set int state GigabitEthernet2/7/0 up + +uncomment { set dhcp proxy server 1.2.3.4 src-address 1.2.3.5 add-option-82 rx-fib-id 0 server-fib-id 0 } + +uncomment { set dhcp proxy server 192.168.2.2 src-address 192.168.2.1 add-option-82 rx-fib-id 12 server-fib-id 11 } + +ip route add 0.0.0.0/24 table 11 via local +ip route add 255.255.255.255/24 table 11 via local + +ip route add 0.0.0.0/24 table 12 via local +ip route add 255.255.255.255/24 table 12 via local diff --git a/src/scripts/vnet/leftpeer/leftpeer-ioam.conf b/src/scripts/vnet/leftpeer/leftpeer-ioam.conf new file mode 100644 index 00000000000..6c1b502c2f7 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-ioam.conf @@ -0,0 +1,15 @@ +comment { connects to linux ping source eth1 addr db02::2/64 } +set int ip address GigabitEthernet2/2/0 db02::1/64 +set int state GigabitEthernet2/2/0 up + +comment { connects to ioam domain rightpeer eth2 addr db03::3/64 } +set int ip address GigabitEthernet2/3/0 db03::1/64 +set int state GigabitEthernet2/3/0 up + +ioam set rewrite trace-elts 2 pow + +set ip6 neighbor GigabitEthernet2/3/0 db03::3 00:50:56:b7:05:cb + +ip route add db04::0/64 via db03::3 + +ioam set destination db04::0/64 add diff --git a/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf b/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf new file mode 100644 index 00000000000..a75f9b4c8ae --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-l3vxlan.conf @@ -0,0 +1,12 @@ +comment { tunnel to rightpeer 6.0.3.3 on vlan 101 } + +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +vxlan tunnel src 6.0.3.1 peer 6.0.3.3 vni 123 adj 6.0.4.4/24 + diff --git a/src/scripts/vnet/leftpeer/leftpeer-lisp.conf b/src/scripts/vnet/leftpeer/leftpeer-lisp.conf new file mode 100644 index 00000000000..cb3180b711d --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-lisp.conf @@ -0,0 +1,18 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface on vlan 100 } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +lisp gpe tunnel src 6.0.3.1 dst 6.0.3.3 next-ip4 decap-next ip4 iid 1133 +set int ip address lisp_gpe_tunnel0 6.0.4.1/24 +set int state lisp_gpe_tunnel0 up + +lisp gpe tunnel src 6.0.3.3 dst 6.0.3.1 next-ip4 decap-next ip4 iid 3311 +set int stat lisp_gpe_tunnel1 up diff --git a/src/scripts/vnet/leftpeer/leftpeer-mpls.conf b/src/scripts/vnet/leftpeer/leftpeer-mpls.conf new file mode 100644 index 00000000000..74bce81b190 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-mpls.conf @@ -0,0 +1,17 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface on vlan 100 } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.3 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.1 dst 6.0.3.3 intfc 6.0.4.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-sr.conf b/src/scripts/vnet/leftpeer/leftpeer-sr.conf new file mode 100644 index 00000000000..a7b962d3aba --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-sr.conf @@ -0,0 +1,24 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to rightpeer } +set int ip address GigabitEthernet2/3/0 db03::2/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber linux-ping-source } +set int ip address GigabitEthernet2/2/0 db02::2/64 +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db01::1 dst db04::1/128 next db03::1 next db04::1 tag db02::2 clean key Gozzer InPE 1 + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf b/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf new file mode 100644 index 00000000000..d50e8bf49f3 --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer-vxlan.conf @@ -0,0 +1,17 @@ +comment { tunnel to rightpeer 6.0.3.3 on vlan 101 } + +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +comment { tunnel to thirdpeer 6.0.5.5 on vlan 105 } +set int ip address GigabitEthernet2/7/0 6.0.5.1/24 +set int state GigabitEthernet2/7/0 up + +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +vxlan tunnel src 6.0.3.1 peer 6.0.3.3 peer 6.0.3.5 vni 123 +vxlan l2 GigabitEthernet2/2/0 vni 123 + diff --git a/src/scripts/vnet/leftpeer/leftpeer.script b/src/scripts/vnet/leftpeer/leftpeer.script new file mode 100644 index 00000000000..f08c809012c --- /dev/null +++ b/src/scripts/vnet/leftpeer/leftpeer.script @@ -0,0 +1,9 @@ +l2tp_set_lookup_key lookup_v6_src + +sw_interface_add_del_address GigabitEthernet2/3/0 db03::2/64 +sw_interface_set_flags GigabitEthernet2/3/0 admin-up + +comment sw_interface_add_del_address GigabitEthernet2/2/0 db02::2/64 +sw_interface_set_flags GigabitEthernet2/2/0 admin-up + +l2tp_session_add_del client_address db03::1 our_address db03::2 GigabitEthernet2/2/0 local_session_id 1 remote_session_id 3 local_cookie 11 remote_cookie 33 diff --git a/src/scripts/vnet/lfib/ip4-to-mpls b/src/scripts/vnet/lfib/ip4-to-mpls new file mode 100644 index 00000000000..85753797751 --- /dev/null +++ b/src/scripts/vnet/lfib/ip4-to-mpls @@ -0,0 +1,26 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.2.2.2 + ICMP echo_request + incrementing 100 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-pop-to-mpls b/src/scripts/vnet/lfib/mpls-pop-to-mpls new file mode 100644 index 00000000000..2818ac133e1 --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-pop-to-mpls @@ -0,0 +1,28 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 72-72 + no-recycle + data { + hex 0x0001e0ff0001f1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +mpls local-label add 30 non-eos mpls-lookup-in-table 0 +mpls local-label add 31 2.2.2.2/32 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-to-ip4 b/src/scripts/vnet/lfib/mpls-to-ip4 new file mode 100644 index 00000000000..24e235e01db --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-to-ip4 @@ -0,0 +1,27 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020202020208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 + +mpls local-label add 30 eos ip4-lookup-in-table 0 + +trace add pg-input 100 diff --git a/src/scripts/vnet/lfib/mpls-to-mpls b/src/scripts/vnet/lfib/mpls-to-mpls new file mode 100644 index 00000000000..497dbab324f --- /dev/null +++ b/src/scripts/vnet/lfib/mpls-to-mpls @@ -0,0 +1,26 @@ +packet-generator new { + name x + limit 1 + node mpls-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + +set ip arp static loop1 2.0.0.2 dead.beef.babe +set int mpls loop1 enable + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 out-label 33 +mpls local-label add 30 2.2.2.2/32 + +trace add pg-input 100 diff --git a/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf b/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf new file mode 100644 index 00000000000..dd37b942062 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/leftpeer.conf @@ -0,0 +1,17 @@ +comment { vpe_phase2 configuration } + +comment { local client facing interface } +comment { configure lc2 eth1 at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.4.1 +mpls decap add label 30 fib 1 + +create mpls ethernet tunnel dst 00:50:56:b7:05:cb adj 6.0.4.1/24 tx-intfc GigabitEthernet2/3/0 fib-id 1 diff --git a/src/scripts/vnet/mpls-o-ethernet/pg b/src/scripts/vnet/mpls-o-ethernet/pg new file mode 100644 index 00000000000..ba5397f7648 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/pg @@ -0,0 +1,10 @@ +packet-generator new { + name x + limit 1 + node mpls-ethernet-input + size 68-68 + no-recycle + data { + hex 0x0001e1ff4500004000000000400177ba010000020200000208007a6e000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627 + } +} \ No newline at end of file diff --git a/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf b/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf new file mode 100644 index 00000000000..7709ce4d584 --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/rightpeer.conf @@ -0,0 +1,15 @@ +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.2.1 +mpls decap add label 30 fib 1 + +create mpls ethernet tunnel dst 00:50:56:b7:05:bf adj 6.0.2.1/24 tx-intfc GigabitEthernet2/3/0 fib-id 1 diff --git a/src/scripts/vnet/mpls-o-ethernet/single.conf b/src/scripts/vnet/mpls-o-ethernet/single.conf new file mode 100644 index 00000000000..2a25d35512c --- /dev/null +++ b/src/scripts/vnet/mpls-o-ethernet/single.conf @@ -0,0 +1,17 @@ +comment { single node configuration } + +loop create +loop create +set int state loop0 up +set int state loop1 up + +set int ip address loop0 1.0.0.1/24 +set int ip address loop1 2.0.0.1/24 + + +ip route add 2.2.2.2/32 via 2.0.0.2 loop1 + +mpls encap add label 30 fib 0 dest 2.2.2.2 +mpls decap add label 30 fib 0 + +create mpls ethernet tunnel dst 00:50:56:b7:05:cb adj 2.2.2.2/32 tx-intfc loop1 fib-id 0 diff --git a/src/scripts/vnet/mpls-o-gre/dhcpd.conf b/src/scripts/vnet/mpls-o-gre/dhcpd.conf new file mode 100644 index 00000000000..f0f659cd55f --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/dhcpd.conf @@ -0,0 +1,116 @@ +# +# Sample configuration file for ISC dhcpd for Debian +# +# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as +# configuration file instead of this file. +# +# + +# The ddns-updates-style parameter controls whether or not the server will +# attempt to do a DNS update when a lease is confirmed. We default to the +# behavior of the version 2 packages ('none', since DHCP v2 didn't +# have support for DDNS.) +ddns-update-style none; + +# option definitions common to all supported networks... +option domain-name "example.org"; +option domain-name-servers ns1.example.org, ns2.example.org; + +default-lease-time 600; +max-lease-time 7200; + +# If this DHCP server is the official DHCP server for the local +# network, the authoritative directive should be uncommented. +#authoritative; + +# Use this to send dhcp log messages to a different log file (you also +# have to hack syslog.conf to complete the redirection). +log-facility local7; + +# No service will be given on this subnet, but declaring it helps the +# DHCP server to understand the network topology. + +#subnet 10.152.187.0 netmask 255.255.255.0 { +#} + +# This is a very basic subnet declaration. + +#subnet 10.254.239.0 netmask 255.255.255.224 { +# range 10.254.239.10 10.254.239.20; +# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; +#} + +# This declaration allows BOOTP clients to get dynamic addresses, +# which we don't really recommend. + +#subnet 10.254.239.32 netmask 255.255.255.224 { +# range dynamic-bootp 10.254.239.40 10.254.239.60; +# option broadcast-address 10.254.239.31; +# option routers rtr-239-32-1.example.org; +#} + +# A slightly different configuration for an internal subnet. +#subnet 10.5.5.0 netmask 255.255.255.224 { +# range 10.5.5.26 10.5.5.30; +# option domain-name-servers ns1.internal.example.org; +# option domain-name "internal.example.org"; +# option routers 10.5.5.1; +# option broadcast-address 10.5.5.31; +# default-lease-time 600; +# max-lease-time 7200; +#} + +# Hosts which require special configuration options can be listed in +# host statements. If no address is specified, the address will be +# allocated dynamically (if possible), but the host-specific information +# will still come from the host declaration. + +#host passacaglia { +# hardware ethernet 0:0:c0:5d:bd:95; +# filename "vmunix.passacaglia"; +# server-name "toccata.fugue.com"; +#} + +# Fixed IP addresses can also be specified for hosts. These addresses +# should not also be listed as being available for dynamic assignment. +# Hosts for which fixed IP addresses have been specified can boot using +# BOOTP or DHCP. Hosts for which no fixed address is specified can only +# be booted with DHCP, unless there is an address range on the subnet +# to which a BOOTP client is connected which has the dynamic-bootp flag +# set. +#host fantasia { +# hardware ethernet 08:00:07:26:c0:a5; +# fixed-address fantasia.fugue.com; +#} + +# You can declare a class of clients and then do address allocation +# based on that. The example below shows a case where all clients +# in a certain class get addresses on the 10.17.224/24 subnet, and all +# other clients get addresses on the 10.0.29/24 subnet. + +#class "foo" { +# match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; +#} + +#shared-network 224-29 { +# subnet 10.17.224.0 netmask 255.255.255.0 { +# option routers rtr-224.example.org; +# } +# subnet 10.0.29.0 netmask 255.255.255.0 { +# option routers rtr-29.example.org; +# } +# pool { +# allow members of "foo"; +# range 10.17.224.10 10.17.224.250; +# } +# pool { +# deny members of "foo"; +# range 10.0.29.10 10.0.29.230; +# } +#} +subnet 6.0.0.0 netmask 255.255.0.0 { + range 6.0.2.2 6.0.2.5; + option routers 6.0.2.1; + default-lease-time 15; + max-lease-time 15; +} diff --git a/src/scripts/vnet/mpls-o-gre/leftpeer.conf b/src/scripts/vnet/mpls-o-gre/leftpeer.conf new file mode 100644 index 00000000000..149c70c068d --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/leftpeer.conf @@ -0,0 +1,14 @@ +comment { left linux ping target configure at e.g. 6.0.2.2/24 } + +set int ip table GigabitEthernet2/2/0 1 +set int ip address GigabitEthernet2/2/0 6.0.2.1/24 +set int state GigabitEthernet2/2/0 up + +comment { tunnel to rightpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.1/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.3 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.1 dst 6.0.3.3 intfc 6.0.4.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/mpls-o-gre/rightpeer.conf b/src/scripts/vnet/mpls-o-gre/rightpeer.conf new file mode 100644 index 00000000000..b5bb597db49 --- /dev/null +++ b/src/scripts/vnet/mpls-o-gre/rightpeer.conf @@ -0,0 +1,14 @@ +comment { right linux ping target configure e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/mpls-tunnel b/src/scripts/vnet/mpls-tunnel new file mode 100644 index 00000000000..d04b29702e7 --- /dev/null +++ b/src/scripts/vnet/mpls-tunnel @@ -0,0 +1,87 @@ +packet-generator new { + name x0 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x1 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.1.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x2 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.2.2 + ICMP echo_request + incrementing 100 + } +} +packet-generator new { + name x3 + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.3.2 + ICMP echo_request + incrementing 100 + } +} + + + +trace add pg-input 100 + +loop create +set int state loop0 up + +set int ip address loop0 10.0.0.1/24 +set ip arp loop0 10.0.0.2 00:00:11:aa:bb:cc + +mpls tunnel add via 10.0.0.2 loop0 out-label 33 out-label 34 out-label 35 out-label 36 +set int state mpls-tunnel0 up +set int ip addr mpls-tunnel0 192.168.0.1/32 +ip route add 2.0.0.2/32 via 192.168.0.2 mpls-tunnel0 + + +mpls tunnel add via 10.0.0.2 out-label 33 +set int state mpls-tunnel1 up +set int ip addr mpls-tunnel1 192.168.1.1/32 +ip route add 2.0.1.2/32 via 192.168.1.2 mpls-tunnel1 out-label 99 + +mpls tunnel add via 10.0.0.2 loop0 out-label 3 +set int state mpls-tunnel2 up +set int ip addr mpls-tunnel2 192.168.2.1/32 +ip route add 2.0.2.2/32 via 192.168.2.2 mpls-tunnel2 + + +mpls tunnel add l2-only via 10.0.0.2 loop0 out-label 234 out-label 0 +set int state mpls-tunnel3 up +set int l2 bridge mpls-tunnel3 1 + +loop create +set int ip addr loop1 6.0.1.44/24 +set int l2 bridge loop1 1 bvi +set int l2 learn loop1 disable +set int state loop1 up + +ip route add 2.0.3.2/32 via 6.0.1.45 loop1 diff --git a/src/scripts/vnet/pcap b/src/scripts/vnet/pcap new file mode 100644 index 00000000000..692e5f27012 --- /dev/null +++ b/src/scripts/vnet/pcap @@ -0,0 +1,18 @@ +packet-generator new { + name x + limit 1 + node ethernet-input + no-recycle + pcap /home/eliot/pcap-data/ISIS_level1_adjacency.cap +} + +packet-generator new { + name y + limit 1 + node hdlc-input + no-recycle + pcap /home/eliot/pcap-data/ISIS_p2p_adjacency.cap +} + +tr add pg-input 10 + diff --git a/src/scripts/vnet/probe4 b/src/scripts/vnet/probe4 new file mode 100644 index 00000000000..b530e0dbc1d --- /dev/null +++ b/src/scripts/vnet/probe4 @@ -0,0 +1,11 @@ +ethernet create-interfaces +set int state fake-eth0 up +set int ip address fake-eth0 1.0.0.1/24 +comment { error } +comment { ip probe fake-eth0 1.0.0.1 } +comment { ip probe fake-eth0 1.2.3.4 } +comment { error } +comment { ip probe fake-eth0 1.0.0.2 } + + + diff --git a/src/scripts/vnet/probe6 b/src/scripts/vnet/probe6 new file mode 100644 index 00000000000..a5490c90b98 --- /dev/null +++ b/src/scripts/vnet/probe6 @@ -0,0 +1,7 @@ +ethernet create-interfaces +set int state fake-eth0 up +set int ip address fake-eth0 2000::1/64 +comment { ip probe fake-eth0 2000::1 } + + + diff --git a/src/scripts/vnet/rewrite b/src/scripts/vnet/rewrite new file mode 100644 index 00000000000..d41b9dbf7fc --- /dev/null +++ b/src/scripts/vnet/rewrite @@ -0,0 +1,62 @@ + + +comment { test ipv4 port/vlan/qinq rewrites by generating arps } + +set int state tuntap-0 down + +set int ip address GigabitEthernet2/2/0 1.2.5.4/24 + +cre sub GigabitEthernet2/2/0 1 dot1q 6 exact-match +set int ip address GigabitEthernet2/2/0.1 1.2.6.4/24 + +cre sub GigabitEthernet2/2/0 2 dot1ad 7 inner-dot1q 8 exact-match +set int ip address GigabitEthernet2/2/0.2 1.2.7.4/24 + +set int state GigabitEthernet2/1/0 up +set int state GigabitEthernet2/2/0 up +set int state GigabitEthernet2/2/0.1 up +set int state GigabitEthernet2/2/0.2 up + +trace add pg-input 2 + +cle er +cle int +cle run + +packet-generator new { + name toport + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.5.6 mpls_unicast + } +} + +packet-generator new { + name tovlan + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.6.6 mpls_unicast + } +} + +packet-generator new { + name toqinq + limit 2 + no-recycle + node ethernet-input + interface GigabitEthernet2/1/0 + data { + IP4: 0050.56b7.7c83 -> 0050.56b7.296d + GRE: 8.0.0.1 -> 1.2.7.6 mpls_unicast + } +} + + diff --git a/src/scripts/vnet/rightpeer/rightpeer-ioam.conf b/src/scripts/vnet/rightpeer/rightpeer-ioam.conf new file mode 100644 index 00000000000..3e9a8d343e2 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-ioam.conf @@ -0,0 +1,14 @@ +comment { connects to right ping target eth3 addr db04::4/64 } +set int ip address GigabitEthernet2/4/0 db04::1/64 +set int state GigabitEthernet2/4/0 up + +comment { connects to ioam domain leftpeer addr db03::1/64 } +set int ip address GigabitEthernet2/3/0 db03::3/64 +set int state GigabitEthernet2/3/0 up + +set ip6 neighbor GigabitEthernet2/3/0 db03::1 00:50:56:b7:05:bf +set ip6 neighbor GigabitEthernet2/4/0 db04::4 00:50:56:b7:05:d2 + +ip route add db02::0/64 via db03::1 + +ioam set destination db04::4/128 pop diff --git a/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf b/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf new file mode 100644 index 00000000000..abba1ab0ef6 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-l3vxlan.conf @@ -0,0 +1,9 @@ +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer on vlan 101 } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +vxlan tunnel src 6.0.3.3 peer 6.0.3.1 vni 123 adj 6.0.2.0/24 + diff --git a/src/scripts/vnet/rightpeer/rightpeer-lisp.conf b/src/scripts/vnet/rightpeer/rightpeer-lisp.conf new file mode 100644 index 00000000000..961204a346b --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-lisp.conf @@ -0,0 +1,16 @@ +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +lisp gpe tunnel src 6.0.3.3 dst 6.0.3.1 next-ip4 decap-next ip4 iid 3311 +set int ip address lisp_gpe_tunnel0 6.0.2.3/24 +set int state lisp_gpe_tunnel0 up + +lisp gpe tunnel src 6.0.3.1 dst 6.0.3.3 next-ip4 decap-next ip4 iid 1133 +set int state lisp_gpe_tunnel1 up diff --git a/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf b/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf new file mode 100644 index 00000000000..0ce38583e83 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-mpls-l2.conf @@ -0,0 +1,24 @@ +comment { vpe_phase1d configuration } + +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 next output GigabitEthernet2/4/0 + +comment { create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 l2-only } + +comment {set int l2 xconnect GigabitEthernet2/4/0 mpls-gre0 } + +uncomment { create mpls ethernet tunnel dst 00:50:56:b7:05:bf adj 6.0.3.1/8 l2-only tx-intfc GigabitEthernet2/3/0 fib-id 1 } + +uncomment { set int l2 xconnect GigabitEthernet2/4/0 mpls-eth0 } + diff --git a/src/scripts/vnet/rightpeer/rightpeer-mpls.conf b/src/scripts/vnet/rightpeer/rightpeer-mpls.conf new file mode 100644 index 00000000000..fc97ba16332 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-mpls.conf @@ -0,0 +1,17 @@ +comment { vpe_phase1d configuration } + +comment { local client facing interface } +comment { configure lc4 eth1 at e.g. 6.0.4.4/24 } + +set int ip table GigabitEthernet2/4/0 1 +set int ip address GigabitEthernet2/4/0 6.0.4.1/24 +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +mpls encap add label 30 fib 1 dest 6.0.3.1 +mpls decap add label 30 fib 1 + +create mpls gre tunnel src 6.0.3.3 dst 6.0.3.1 intfc 6.0.2.1/24 inner-fib-id 1 outer-fib-id 0 diff --git a/src/scripts/vnet/rightpeer/rightpeer-sr.conf b/src/scripts/vnet/rightpeer/rightpeer-sr.conf new file mode 100644 index 00000000000..0b2a98bba1b --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-sr.conf @@ -0,0 +1,28 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to leftpeer } +set int ip address GigabitEthernet2/3/0 db03::1/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber right peer target } +set int ip address GigabitEthernet2/4/0 db04::2/64 + +comment { next address to fake out ND on shared LAN segment } +comment { set int ip address GigabitEthernet2/4/0 db02::13/64 } + +enable ip6 interface GigabitEthernet2/4/0 +set int state GigabitEthernet2/4/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db04::1 dst db02::1/128 next db03::2 next db02::1 tag db04::2 clean key Hoser + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf b/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf new file mode 100644 index 00000000000..bd4c427e768 --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer-vxlan.conf @@ -0,0 +1,16 @@ + +comment { local client facing interface } + +comment { configure client lc4 eth1 } +set int state GigabitEthernet2/4/0 up + +comment { tunnel to leftpeer } +set int ip address GigabitEthernet2/3/0 6.0.3.3/24 +set int state GigabitEthernet2/3/0 up + +comment { tunnel to extra ping target } +set int ip address GigabitEthernet2/7/0 6.0.5.3/24 +set int state GigabitEthernet2/3/0 up + +vxlan tunnel src 6.0.3.3 peer 6.0.3.1 peer 6.0.3.5 vni 123 +vxlan l2 GigabitEthernet2/4/0 vni 123 diff --git a/src/scripts/vnet/rightpeer/rightpeer.script b/src/scripts/vnet/rightpeer/rightpeer.script new file mode 100644 index 00000000000..153988cefad --- /dev/null +++ b/src/scripts/vnet/rightpeer/rightpeer.script @@ -0,0 +1,9 @@ +l2tp_set_lookup_key lookup_v6_src + +sw_interface_add_del_address GigabitEthernet2/3/0 db03::1/64 +sw_interface_set_flags GigabitEthernet2/3/0 admin-up + +comment sw_interface_add_del_address GigabitEthernet2/4/0 db02::2/64 +sw_interface_set_flags GigabitEthernet2/4/0 admin-up + +l2tp_session_add_del client_address db03::2 our_address db03::1 GigabitEthernet2/4/0 local_session_id 3 remote_session_id 1 local_cookie 33 remote_cookie 11 diff --git a/src/scripts/vnet/rpf b/src/scripts/vnet/rpf new file mode 100644 index 00000000000..571c6b79a8c --- /dev/null +++ b/src/scripts/vnet/rpf @@ -0,0 +1,18 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +set interface ip source-check pg/stream-0 +ip route 1.2.3.4/32 via pg/stream-0 0x01020304 +ip route 5.6.7.8/32 via drop + diff --git a/src/scripts/vnet/rtt-test b/src/scripts/vnet/rtt-test new file mode 100644 index 00000000000..5501b99dc45 --- /dev/null +++ b/src/scripts/vnet/rtt-test @@ -0,0 +1,31 @@ +set int state TenGigabitEthernet4/0/0 up +set int state TenGigabitEthernet5/0/0 up + +set int ip address TenGigabitEthernet4/0/0 1.0.0.1/24 +set int ip address TenGigabitEthernet5/0/0 2.0.0.1/24 + +ip route table 0 1.0.0.2/32 via TenGigabitEthernet4/0/0 IP4: 00:1b:21:74:5b:04 -> 00:1b:21:79:8e:bc +ip route table 0 2.0.0.2/32 via TenGigabitEthernet5/0/0 IP4: 00:1b:21:79:8e:bc -> 00:1b:21:74:5b:04 +ip route table 1 2.0.0.2/32 via local +ip route table 1 1.0.0.2/32 via local + +set int ip table TenGigabitEthernet5/0/0 1 +set int ip table TenGigabitEthernet4/0/0 1 + +comment { trace add rtt-test-tx 100 } +comment { trace add ixge-input 100 } +comment { te rtt { 1.0.0.2 -> 2.0.0.2 count 1e4 rate 1e9 size 100 histogram-time 1e-5 } } + +packet-generator new { + name x + limit 1 + node ip4-input + size 170-170 + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + + diff --git a/src/scripts/vnet/snat b/src/scripts/vnet/snat new file mode 100644 index 00000000000..87fd699ee51 --- /dev/null +++ b/src/scripts/vnet/snat @@ -0,0 +1,34 @@ +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3005 -> 3006 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +ip route 172.16.1.2/32 via drop +set int ip address pg0 10.0.0.1/24 +set int snat in pg0 +trace add pg-input 10 diff --git a/src/scripts/vnet/snat_static b/src/scripts/vnet/snat_static new file mode 100644 index 00000000000..8fe48bffaaa --- /dev/null +++ b/src/scripts/vnet/snat_static @@ -0,0 +1,44 @@ +create packet-generator interface pg0 +create packet-generator interface pg1 + +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + interface pg0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + interface pg1 + data { + UDP: 172.16.1.2 -> 172.16.1.3 + UDP: 3001 -> 3000 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +snat add static mapping local 10.0.0.3 external 172.16.1.3 +set int ip address pg0 10.0.0.1/24 +set int ip address pg1 172.16.1.1/24 +set int state pg0 up +set int state pg1 up +set ip arp static pg0 10.0.0.3 abcd.abcd.abcd +set ip arp static pg1 172.16.1.2 cdef.abcd.abcd +set int snat in pg0 out pg1 +trace add pg-input 10 diff --git a/src/scripts/vnet/snat_static_with_port b/src/scripts/vnet/snat_static_with_port new file mode 100644 index 00000000000..f646145a5bf --- /dev/null +++ b/src/scripts/vnet/snat_static_with_port @@ -0,0 +1,44 @@ +create packet-generator interface pg0 +create packet-generator interface pg1 + +packet-generator new { + name f1 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 0 + interface pg0 + data { + UDP: 10.0.0.3 -> 172.16.1.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + + +packet-generator new { + name f2 + limit 1000000 + node ip4-input + size 64-64 + no-recycle + worker 1 + interface pg1 + data { + UDP: 172.16.1.2 -> 172.16.1.3 + UDP: 3001 -> 3000 + length 128 checksum 0 incrementing 1 + } +} + +snat add address 172.16.1.3 +snat add static mapping local 10.0.0.3 3000 external 172.16.1.3 3000 +set int ip address pg0 10.0.0.1/24 +set int ip address pg1 172.16.1.1/24 +set int state pg0 up +set int state pg1 up +set ip arp static pg0 10.0.0.3 abcd.abcd.abcd +set ip arp static pg1 172.16.1.2 cdef.abcd.abcd +set int snat in pg0 out pg1 +trace add pg-input 10 diff --git a/src/scripts/vnet/source_and_port_range_check b/src/scripts/vnet/source_and_port_range_check new file mode 100644 index 00000000000..dce227b4315 --- /dev/null +++ b/src/scripts/vnet/source_and_port_range_check @@ -0,0 +1,63 @@ + +create loop int + +set int state loop0 up +set int ip addr loop0 10.10.10.10/32 + +packet-generator new { + name deny-from-default-route + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.2.3.4 -> 5.6.7.8 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 5.6.7.8 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name deny-from-port-range + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 5.6.7.8 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +set ip source-and-port-range-check 1.1.1.0/24 range 2000 - 3000 vrf 99 + +set interface ip source-and-port-range-check pg0 udp-out-vrf 99 + + show ip source-and-port-range-check vrf 99 1.1.1.1 + +set ip source-and-port-range-check 1.1.1.0/24 range 4000 - 5000 vrf 99 + +set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99 + +show ip source-and-port-range-check vrf 99 1.1.1.1 +show ip source-and-port-range-check vrf 99 1.1.2.1 + +set ip source-and-port-range-check 1.1.2.0/24 range 4000 - 5000 vrf 99 del + +show ip source-and-port-range-check vrf 99 1.1.2.1 + +tr add pg-input 100 diff --git a/src/scripts/vnet/speed b/src/scripts/vnet/speed new file mode 100644 index 00000000000..d60d671f29f --- /dev/null +++ b/src/scripts/vnet/speed @@ -0,0 +1,14 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 50-50 + data { + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via pg/stream-0 000102030405060708090a0b0c0d diff --git a/src/scripts/vnet/sr/left-linux-ping.sh b/src/scripts/vnet/sr/left-linux-ping.sh new file mode 100755 index 00000000000..55b835063c7 --- /dev/null +++ b/src/scripts/vnet/sr/left-linux-ping.sh @@ -0,0 +1,3 @@ +#!/bin/bash +ifconfig eth2 inet6 add db02::1/64 +route -A inet6 add db04::1/128 gw db02::2 diff --git a/src/scripts/vnet/sr/leftpeer.conf b/src/scripts/vnet/sr/leftpeer.conf new file mode 100644 index 00000000000..9591d968b8b --- /dev/null +++ b/src/scripts/vnet/sr/leftpeer.conf @@ -0,0 +1,27 @@ +comment { test sr segment chunk-offset on } +test sr hmac validate on + +comment { trunk to rightpeer } +set int ip address GigabitEthernet2/3/0 db03::2/64 +enable ip6 interface GigabitEthernet2/3/0 +set int state GigabitEthernet2/3/0 up + +comment { subscriber left-linux-ping } +set int ip address GigabitEthernet2/2/0 db02::2/64 +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr hmac id 2 key Gozzer +sr hmac id 3 key Hoser + +sr tunnel src db01::1 dst db04::1/128 next db03::1 next db04::1 tag db02::2 clean key Gozzer InPE 1 + +comment { sr unaware service chaining to db03::5 } +comment { sr tunnel src db01::1 dst db04::1/128 next db03::1 next db03::5 next db04::1 tag db02::2 clean key Gozzer InPE 1 } + +comment { tap connect srlocal hwaddr random } +comment { set int ip6 table tap-0 1 } +comment { set int ip address tap-0 db04::99/64 } +comment { enable ip6 interface tap-0 } +comment { set int state tap-0 up } +comment { ip route add table 1 db02::0/64 lookup in table 0 } diff --git a/src/scripts/vnet/sr/right-linux-ping.sh b/src/scripts/vnet/sr/right-linux-ping.sh new file mode 100755 index 00000000000..029368dbb8b --- /dev/null +++ b/src/scripts/vnet/sr/right-linux-ping.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ifconfig eth1 inet6 add db04::1/64 +route -A inet6 add db02::1/128 gw db04::2 diff --git a/src/scripts/vnet/sr/rightpeer.conf b/src/scripts/vnet/sr/rightpeer.conf new file mode 100644 index 00000000000..6da7a7afd05 --- /dev/null +++ b/src/scripts/vnet/sr/rightpeer.conf @@ -0,0 +1,22 @@ +comment { trunk to leftpeer } +set int ip address GigabitEthernet2/0/0 db03::1/64 +enable ip6 interface GigabitEthernet2/0/0 +set int state GigabitEthernet2/0/0 up + +comment { subscriber right-linux-ping } +set int ip address GigabitEthernet2/2/0 db04::2/64 + +comment { next address to fake out ND on shared LAN segment } +set int ip address GigabitEthernet2/2/0 db02::13/64 + +enable ip6 interface GigabitEthernet2/2/0 +set int state GigabitEthernet2/2/0 up + +sr tunnel src db04::1 dst db02::1/128 next db03::2 next db02::1 tag db04::2 clean + +tap connect srlocal hwaddr random +set int ip6 table tap-0 1 +set int ip address tap-0 db04::99/64 +enable ip6 interface tap-0 +set int state tap-0 up +ip route add table 1 db02::0/64 lookup in table 0 diff --git a/src/scripts/vnet/sr/srlocal.sh b/src/scripts/vnet/sr/srlocal.sh new file mode 100755 index 00000000000..2f568408b94 --- /dev/null +++ b/src/scripts/vnet/sr/srlocal.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +ifconfig srlocal inet6 add db04::1/64 +route -6 add db02::0/64 gw db04::99 diff --git a/src/scripts/vnet/srp b/src/scripts/vnet/srp new file mode 100644 index 00000000000..7cc37011386 --- /dev/null +++ b/src/scripts/vnet/srp @@ -0,0 +1,27 @@ +srp create-interfaces +srp create-interfaces +set int hw-class fake-srp0 srp +set int hw-class fake-srp1 srp + +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + ICMP: 1.0.0.2 -> 2.0.0.2 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +set int state fake-srp0 up +set int state fake-srp1 up + +set int ip address fake-srp0 1.0.0.1/24 +set int ip address fake-srp1 2.0.0.1/24 + + + diff --git a/src/scripts/vnet/tcp b/src/scripts/vnet/tcp new file mode 100644 index 00000000000..a2ee8b2dacc --- /dev/null +++ b/src/scripts/vnet/tcp @@ -0,0 +1,16 @@ +packet-generator new { + name x + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + TCP: 1.2.3.4 -> 5.6.7.8 + TCP: 1234 -> 5678 + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vnet/tcp-test b/src/scripts/vnet/tcp-test new file mode 100644 index 00000000000..52bfbcdd8c0 --- /dev/null +++ b/src/scripts/vnet/tcp-test @@ -0,0 +1,6 @@ +int create-ethernet +set int ip address fake-eth0 1.2.3.4/24 +set int state fake-eth0 up +ip route 1.2.3.5/32 via local +trace add tuntap-rx 100 + diff --git a/src/scripts/vnet/tf-ucs-1 b/src/scripts/vnet/tf-ucs-1 new file mode 100644 index 00000000000..efa5f2dc27f --- /dev/null +++ b/src/scripts/vnet/tf-ucs-1 @@ -0,0 +1,16 @@ +comment { connected to Ixia port 1} +set int ip address TenGigabitEthernet4/0/0 1.0.0.2/8 + +set int state TenGigabitEthernet4/0/0 up + +comment { connected to Ixia port 2} +set int ip address TenGigabitEthernet4/0/1 2.0.0.2/8 +set int state TenGigabitEthernet4/0/1 up + +comment { connected to Ixia port 3} +set int ip address TenGigabitEthernet6/0/0 3.0.0.2/8 +set int state TenGigabitEthernet6/0/0 up + +comment { connected to Ixia port 4} +set int ip address TenGigabitEthernet6/0/1 4.0.0.2/8 +set int state TenGigabitEthernet6/0/1 up diff --git a/src/scripts/vnet/urpf b/src/scripts/vnet/urpf new file mode 100644 index 00000000000..a4d875276ee --- /dev/null +++ b/src/scripts/vnet/urpf @@ -0,0 +1,86 @@ + +create loop int + +set int state loop0 up +set int ip addr loop0 10.10.10.10/24 + +packet-generator new { + name transit-deny + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.2.3.4 -> 2.2.2.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name transit-allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 2.2.2.2 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name transit-allow-from-excemption + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 11.11.12.13 -> 2.2.2.2 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name for-us-allow-from-excemption + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 11.11.12.13 -> 10.10.10.10 + UDP: 6000 -> 6001 + length 128 checksum 0 incrementing 1 + } +} + +packet-generator new { + name for-us-allow + limit 1 + node ip4-input + size 64-64 + no-recycle + data { + UDP: 1.1.1.1 -> 10.10.10.10 + UDP: 3000 -> 3001 + length 128 checksum 0 incrementing 1 + } +} + +tr add pg-input 100 + +set int ip addr pg0 10.10.11.10/24 + +set interface ip source-check pg0 strict + +ip route add 1.1.1.1/32 via 10.10.11.11 pg0 +ip route add 2.2.2.2/32 via 10.10.10.11 loop0 + +ip urpf-accept 11.11.0.0/16 + +#set interface ip source-check pg0 strict del +#set interface ip source-check pg0 loose + +#ip urpf-accept del 11.11.0.0/16 diff --git a/src/scripts/vnet/virl/ip6sr.virl b/src/scripts/vnet/virl/ip6sr.virl new file mode 100644 index 00000000000..5d4d1a0ac67 --- /dev/null +++ b/src/scripts/vnet/virl/ip6sr.virl @@ -0,0 +1,874 @@ + + + + flat + dual_stack + false + + + + ! +! Last configuration change at 16:41:18 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.2 255.255.255.255 + ipv6 address ::B:1:0:0:2/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.193 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:6/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! route to iosv-2 +ipv6 route ::A:1:1:0:16/128 ::A:1:1:0:7 +! route to iosv-4 +ipv6 route ::A:1:1:0:22/128 ::A:1:1:0:7 +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:41:10 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-2 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.3 255.255.255.255 + ipv6 address ::B:1:0:0:3/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.191 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.21 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:16/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +ipv6 route ::A:1:1:0:6/128 ::A:1:1:0:17 +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:27:43 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-3 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.6 255.255.255.255 + ipv6 address ::B:1:0:0:4/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.192 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.9 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:A/126 +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 16:27:43 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-4 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.8 255.255.255.255 + ipv6 address ::B:1:0:0:5/128 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.194 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.33 255.255.255.252 + duplex auto + speed auto + media-type rj45 + ipv6 address ::A:1:1:0:22/126 +! +! Route to iosv-1 +ipv6 route ::A:1:1:0:6/128 ::A:1:1:0:23 +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:7/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.10/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:b/126 + set interface state GigabitEthernet0/5/0 up + set interface ip address GigabitEthernet0/6/0 10.0.0.13/30 + set interface ip address GigabitEthernet0/6/0 ::a:1:1:0:e/126 + set interface state GigabitEthernet0/6/0 up + set interface ip address GigabitEthernet0/7/0 10.0.0.17/30 + set interface ip address GigabitEthernet0/7/0 ::a:1:1:0:12/126 + set interface state GigabitEthernet0/7/0 up + sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:16/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:16 tag 0::a:1:1:0:7 InPE 1 clean + sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:22/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:22 tag 0::a:1:1:0:7 InPE 1 clean + + + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-2 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.25/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:1a/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.29/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1e/126 + set interface state GigabitEthernet0/5/0 up + set interface ip address GigabitEthernet0/6/0 10.0.0.22/30 + set interface ip address GigabitEthernet0/6/0 ::a:1:1:0:17/126 + set interface state GigabitEthernet0/6/0 up + set interface ip address GigabitEthernet0/7/0 10.0.0.34/30 + set interface ip address GigabitEthernet0/7/0 ::a:1:1:0:23/126 + set interface state GigabitEthernet0/7/0 up + sr tunnel src 0::a:1:1:0:16 dst 0::a:1:1:0:6/128 next 0::a:1:1:0:1b next 0::a:1:1:0:e next 0::a:1:1:0:6 tag 0::a:1:1:0:17 InPE 1 clean + + + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-3 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.14/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:f/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.26/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1b/126 + set interface state GigabitEthernet0/5/0 up + comment { fix src rpf drop screws} + ip route add ::a:1:1:0:6/128 via drop + ip route add ::a:1:1:0:16/128 via drop + ip route add ::a:1:1:0:22/128 via drop + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-4 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.18/30 + set interface ip address GigabitEthernet0/4/0 ::a:1:1:0:13/126 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.30/30 + set interface ip address GigabitEthernet0/5/0 ::a:1:1:0:1f/126 + set interface state GigabitEthernet0/5/0 up + + + + + + + + + + + + + + diff --git a/src/scripts/vnet/virl/ip6sr_notes.txt b/src/scripts/vnet/virl/ip6sr_notes.txt new file mode 100644 index 00000000000..5febf2c690b --- /dev/null +++ b/src/scripts/vnet/virl/ip6sr_notes.txt @@ -0,0 +1,38 @@ +vpp-1, tunnel 1: iosv-1 vpp-1 vpp-3 vpp-2 iosv-2 + +iosv-1 +::a:1:1:0:6 + +to iosv2 +ipv6 route ::a:1:1:0:16/128 ::a:1:1:0:7 +to iosv4 +ipv6 route ::a:1:1:0:22/128 ::a:1:1:0:7 + +vpp-1 + +::a:1:1:0:7 +... +::a:1:1:0:e + +sr tunnel src 0::a:1:1:0:6 dst 0::a:1:1:0:16/128 next 0::a:1:1:0:f next 0::a:1:1:0:1a next 0::a:1:1:0:16 tag 0::a:1:1:0:7 InPE 1 clean + +vpp-3 +::a:1:1:0:f +.. +::a:1:1:0:1b + +comment {fix src rpf screws} +ip route add ::a:1:1:0:6/128 via drop +ip route add ::a:1:1:0:16/128 via drop +ip route add ::a:1:1:0:22/128 via drop +vpp-2 +::a:1:1:0:1a +.. +::a:1:1:0:17 + +sr tunnel src 0::a:1:1:0:16 dst 0::a:1:1:0:6/128 next 0::a:1:1:0:1b next 0::a:1:1:0:e next 0::a:1:1:0:6 tag 0::a:1:1:0:17 InPE 1 clean + +iosv-2 +::a:1:1:0:16 + +ipv6 route ::a:1:1:0:6/128 ::a:1:1:0:17 diff --git a/src/scripts/vnet/virl/mplsogre.virl b/src/scripts/vnet/virl/mplsogre.virl new file mode 100644 index 00000000000..33dd03299d4 --- /dev/null +++ b/src/scripts/vnet/virl/mplsogre.virl @@ -0,0 +1,319 @@ + + + + flat + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.9/30 + set interface state GigabitEthernet0/5/0 up + mpls encap add label 30 fib 0 dest 10.0.0.10 + mpls decap add label 30 fib 0 + create mpls gre tunnel src 10.0.0.9 dst 10.0.0.10 intfc 10.0.0.13/30 inner-fib-id 0 outer-fib-id 0 + + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-2 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.10/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.14/30 + set interface state GigabitEthernet0/5/0 up + mpls encap add label 30 fib 0 dest 10.0.0.9 + mpls decap add label 30 fib 0 + create mpls gre tunnel src 10.0.0.10 dst 10.0.0.9 intfc 10.0.0.5/30 inner-fib-id 0 outer-fib-id 0 + + + + + + + + ! IOS Config generated on 2015-03-03 17:26 +! by autonetkit_0.15.0 +! +hostname iosv-1 +boot-start-marker +boot-end-marker +! +no aaa new-model +! +! +ip cef +ipv6 unicast-routing +ipv6 cef +! +! +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +no service config +enable password cisco +ip classless +ip subnet-zero +no ip domain lookup +line vty 0 4 + transport input ssh telnet + exec-timeout 720 0 + password cisco + login +line con 0 + password cisco +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.1 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ! Configured on launch + no ip address + duplex auto + speed auto + no shutdown +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + no shutdown +! +! +! +router ospf 1 + network 192.168.0.1 0.0.0.0 area 0 + log-adjacency-changes + passive-interface Loopback0 + network 10.0.0.4 0.0.0.3 area 0 +! +! +router bgp 1 + bgp router-id 192.168.0.1 + no synchronization +! ibgp + ! ibgp peers + ! + neighbor 192.168.0.4 remote-as 1 + neighbor 192.168.0.4 description iBGP peer iosv-2 + neighbor 192.168.0.4 update-source Loopback0 +! +! + ! + address-family ipv4 + network 192.168.0.1 mask 255.255.255.255 + neighbor 192.168.0.4 activate + exit-address-family +! +! +! +ip route 10.0.0.13 255.255.255.255 10.0.0.6 +end + + + + + + + + ! IOS Config generated on 2015-03-03 17:26 +! by autonetkit_0.15.0 +! +hostname iosv-2 +boot-start-marker +boot-end-marker +! +no aaa new-model +! +! +ip cef +ipv6 unicast-routing +ipv6 cef +! +! +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +no service config +enable password cisco +ip classless +ip subnet-zero +no ip domain lookup +line vty 0 4 + transport input ssh telnet + exec-timeout 720 0 + password cisco + login +line con 0 + password cisco +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.4 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ! Configured on launch + no ip address + duplex auto + speed auto + no shutdown +! +interface GigabitEthernet0/1 + description to vpp-2 + ip address 10.0.0.13 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + no shutdown +! +! +! +router ospf 1 + network 192.168.0.4 0.0.0.0 area 0 + log-adjacency-changes + passive-interface Loopback0 + network 10.0.0.12 0.0.0.3 area 0 +! +! +router bgp 1 + bgp router-id 192.168.0.4 + no synchronization +! ibgp + ! ibgp peers + ! + neighbor 192.168.0.1 remote-as 1 + neighbor 192.168.0.1 description iBGP peer iosv-1 + neighbor 192.168.0.1 update-source Loopback0 +! +! + ! + address-family ipv4 + network 192.168.0.4 mask 255.255.255.255 + neighbor 192.168.0.1 activate + exit-address-family +! +! +ip route 10.0.0.5 255.255.255.255 10.0.0.14 +! +end + + + + + + + + + diff --git a/src/scripts/vnet/virl/simple.virl b/src/scripts/vnet/virl/simple.virl new file mode 100644 index 00000000000..6033c42c36a --- /dev/null +++ b/src/scripts/vnet/virl/simple.virl @@ -0,0 +1,389 @@ + + + + flat + + + + ! +! Last configuration change at 14:27:32 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.2 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.167 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.5 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + media-type rj45 +! +router ospf 1 + passive-interface Loopback0 + network 10.0.0.4 0.0.0.3 area 0 + network 192.168.0.2 0.0.0.0 area 0 +! +router bgp 1 + bgp router-id 192.168.0.2 + bgp log-neighbor-changes + neighbor 192.168.0.3 remote-as 1 + neighbor 192.168.0.3 description iBGP peer iosv-2 + neighbor 192.168.0.3 update-source Loopback0 + ! + address-family ipv4 + network 192.168.0.2 mask 255.255.255.255 + neighbor 192.168.0.3 activate + exit-address-family +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip route 10.0.0.9 255.255.255.255 10.0.0.6 +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + ! +! Last configuration change at 14:26:58 UTC Fri Mar 27 2015 +! +version 15.4 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-encryption +! +hostname iosv-2 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +no aaa new-model +! +! +! +mmi polling-interval 60 +no mmi auto-configure +no mmi pvc +mmi snmp-timeout 180 +! +! +! +! +! +! +! +! +! +! +! +! +! +no ip domain lookup +ip cef +ipv6 unicast-routing +ipv6 cef +! +multilink bundle-name authenticated +! +! +cts logging verbose +! +! +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + description Loopback + ip address 192.168.0.3 255.255.255.255 +! +interface GigabitEthernet0/0 + description OOB Management + ip address 172.16.1.164 255.255.255.0 + duplex auto + speed auto + media-type rj45 +! +interface GigabitEthernet0/1 + description to vpp-1 + ip address 10.0.0.9 255.255.255.252 + ip ospf cost 1 + duplex auto + speed auto + media-type rj45 +! +router ospf 1 + passive-interface Loopback0 + network 10.0.0.8 0.0.0.3 area 0 + network 192.168.0.3 0.0.0.0 area 0 +! +router bgp 1 + bgp router-id 192.168.0.3 + bgp log-neighbor-changes + neighbor 192.168.0.2 remote-as 1 + neighbor 192.168.0.2 description iBGP peer iosv-1 + neighbor 192.168.0.2 update-source Loopback0 + ! + address-family ipv4 + network 192.168.0.3 mask 255.255.255.255 + neighbor 192.168.0.2 activate + exit-address-family +! +ip forward-protocol nd +! +! +no ip http server +no ip http secure-server +ip route 10.0.0.5 255.255.255.255 10.0.0.10 +! +! +! +! +control-plane +! +banner exec ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner incoming ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +banner login ` +************************************************************************** +* IOSv is strictly limited to use for evaluation, demonstration and IOS * +* education. IOSv is provided as-is and is not supported by Cisco's * +* Technical Advisory Center. Any use or disclosure, in whole or in part, * +* of the IOSv Software or Documentation to any third party for any * +* purposes is expressly prohibited except as otherwise authorized by * +* Cisco in writing. * +**************************************************************************` +! +line con 0 + password cisco +line aux 0 +line vty 0 4 + exec-timeout 720 0 + password cisco + login + transport input telnet ssh +! +no scheduler allocate +! +end + + + + + + + #cloud-config +bootcmd: +- ln -s -t /etc/rc.d /etc/rc.local +hostname: vpp-1 +manage_etc_hosts: true +runcmd: +- start ttyS0 +- systemctl start getty@ttyS0.service +- systemctl start rc-local +- sed -i '/^\s*PasswordAuthentication\s\+no/d' /etc/ssh/sshd_config +- echo "UseDNS no" >> /etc/ssh/sshd_config +- service ssh restart +- service sshd restart +- sed -i 's/no-pci//' /cisco/etc/qn.conf +- sed -i 's/1024/1024 decimal-interface-names/g' /cisco/etc/qn.conf +users: +- default +- gecos: User configured by VIRL Configuration Engine 0.15.3 + lock-passwd: false + name: cisco + plain-text-passwd: cisco + shell: /bin/bash + ssh-authorized-keys: + - VIRL-USER-SSH-PUBLIC-KEY + sudo: ALL=(ALL) ALL +write_files: +- path: /etc/init/ttyS0.conf + owner: root:root + content: | + # ttyS0 - getty + # This service maintains a getty on ttyS0 from the point the system is + # started until it is shut down again. + start on stopped rc or RUNLEVEL=[12345] + stop on runlevel [!12345] + respawn + exec /sbin/getty -L 115200 ttyS0 vt102 + permissions: '0644' +- path: /etc/systemd/system/dhclient@.service + content: | + [Unit] + Description=Run dhclient on %i interface + After=network.target + [Service] + Type=oneshot + ExecStart=/sbin/dhclient %i -pf /var/run/dhclient.%i.pid -lf /var/lib/dhclient/dhclient.%i.lease + RemainAfterExit=yes + owner: root:root + permissions: '0644' +- path: /cisco/etc/vpp-server.conf + owner: root:root + permissions: '0644' + content: |- + set interface ip address GigabitEthernet0/4/0 10.0.0.6/30 + set interface state GigabitEthernet0/4/0 up + set interface ip address GigabitEthernet0/5/0 10.0.0.10/30 + set interface state GigabitEthernet0/5/0 up + + + + + + + + diff --git a/src/scripts/vnet/vlan b/src/scripts/vnet/vlan new file mode 100644 index 00000000000..076080a6978 --- /dev/null +++ b/src/scripts/vnet/vlan @@ -0,0 +1,23 @@ +int create-ethernet +int create-sub fake-eth0 1 +set int state fake-eth0 up +set int state fake-eth0.1 up + +packet-generator new { + name x + limit 1 + node ethernet-input + interface fake-eth0 + size 64-64 + no-recycle + data { + IP4: 1.2.3 -> 4.5.6 vlan 1 + ICMP: 1.2.3.4 -> 5.6.7.8 + ICMP echo_request + incrementing 100 + } +} + +tr add pg-input 100 +ip route 5.6.7.8/32 via local +ip route 1.2.3.4/32 via local diff --git a/src/scripts/vppctl b/src/scripts/vppctl new file mode 100755 index 00000000000..4fdf03c78ff --- /dev/null +++ b/src/scripts/vppctl @@ -0,0 +1,121 @@ +#! /usr/bin/python +''' +Copyright 2016 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +''' + +from cmd import Cmd +import os +import subprocess +import re +import sys +try: + import readline +except ImportError: + readline = None + +persishist = os.path.expanduser('~/.vpphistory') +persishist_size = 1000 +if not persishist: + os.mknod(persishist, stat.S_IFREG) + +class Vppctl(Cmd): + + def historyWrite(self): + if readline: + readline.set_history_length(persishist_size) + readline.write_history_file(persishist) + + def runVat(self, line): + input_prefix = "exec " + input_command = input_prefix + line + line_remove = '^load_one_plugin:' + s = '\n' + command = ['vpp_api_test'] + + if os.geteuid() != 0: + command = ['sudo', 'vpp_api_test'] + + vpp_process = subprocess.Popen(command, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + stdout_value = vpp_process.communicate(input_command)[0] + + buffer_stdout = stdout_value.splitlines() + + buffer_stdout[:] = [b for b in buffer_stdout + if line_remove not in b] + + for i, num in enumerate(buffer_stdout): + buffer_stdout[i] = num.replace('vat# ','') + + stdout_value = s.join(buffer_stdout) + print stdout_value + + def do_help(self, line): + self.runVat("help") + + def default(self, line): + self.runVat(line) + + def do_exit(self, line): + self.historyWrite() + raise SystemExit + + def emptyline(self): + pass + + def do_EOF(self,line): + self.historyWrite() + sys.stdout.write('\n') + raise SystemExit + + def preloop(self): + if readline and os.path.exists(persishist): + readline.read_history_file(persishist) + + def postcmd(self, stop, line): + self.historyWrite() + +if __name__ == '__main__': + command_args = sys.argv + + + if not len(command_args) > 1: + prompt = Vppctl() + red_set = '\033[31m' + norm_set = '\033[0m' + if sys.stdout.isatty(): + prompt.prompt = 'vpp# ' + try: + prompt.cmdloop(red_set + " _______ _ " + norm_set + " _ _____ ___ \n" + + red_set + " __/ __/ _ \ (_)__ " + norm_set + " | | / / _ \/ _ \\\n" + + red_set + " _/ _// // / / / _ \\" + norm_set + " | |/ / ___/ ___/\n" + + red_set + " /_/ /____(_)_/\___/ " + norm_set + "|___/_/ /_/ \n") + except KeyboardInterrupt: + sys.stdout.write('\n') + else: + try: + prompt.cmdloop() + except KeyboardInterrupt: + sys.stdout.write('\n') + else: + del command_args[0] + stdout_value = " ".join(command_args) + VatAddress = Vppctl() + VatAddress.runVat(stdout_value) + + + diff --git a/src/suffix-rules.mk b/src/suffix-rules.mk new file mode 100644 index 00000000000..e3eeb9220bf --- /dev/null +++ b/src/suffix-rules.mk @@ -0,0 +1,27 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Shared suffix rules +# Please do not set "SUFFIXES = .api.h .api" here + +%.api.h: %.api + @echo " APIGEN " $@ ; \ + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --output $@ --show-name $@ + +%.api.json: %.api + @echo " JSON APIGEN " $@ ; \ + mkdir -p `dirname $@` ; \ + $(CC) $(CPPFLAGS) -E -P -C -x c $^ \ + | vppapigen --input - --json $@ diff --git a/src/svm.am b/src/svm.am new file mode 100644 index 00000000000..d91eaa272a2 --- /dev/null +++ b/src/svm.am @@ -0,0 +1,31 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +bin_PROGRAMS += svmtool svmdbtool + +nobase_include_HEADERS += svm/svm.h svm/ssvm.h svm/svmdb.h + +libsvmdir = ${libdir} +libsvm_LTLIBRARIES = libsvm.la libsvmdb.la + +libsvm_la_SOURCES = svm/svm.c svm/ssvm.c + +svmtool_SOURCES = svm/svmtool.c +svmtool_LDADD = libsvm.la libvppinfra.la -lpthread -lrt + +libsvmdb_la_SOURCES = svm/svmdb.c + +svmdbtool_SOURCES = svm/svmdbtool.c +svmdbtool_LDADD = libsvmdb.la libsvm.la libvppinfra.la -lpthread -lrt + +# vi:syntax=automake diff --git a/src/svm/dir.dox b/src/svm/dir.dox new file mode 100644 index 00000000000..83246979ca8 --- /dev/null +++ b/src/svm/dir.dox @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Doxygen directory documentation */ +/** +@dir +@brief Shared virtual memory allocation library. +*/ diff --git a/src/svm/persist.c b/src/svm/persist.c new file mode 100644 index 00000000000..023c596b9cf --- /dev/null +++ b/src/svm/persist.c @@ -0,0 +1,258 @@ +/* + *------------------------------------------------------------------ + * persist.c - persistent data structure storage test / demo code + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct +{ + svmdb_client_t *c; +} persist_main_t; + +persist_main_t persist_main; + +typedef struct +{ + u8 *string1; + u8 *string2; +} demo_struct2_t; + +typedef struct +{ + demo_struct2_t *demo2; + u8 *name; +} demo_struct1_t; + +/* + * Data structures in persistent shared memory, all the time + */ +clib_error_t * +persist_malloc (persist_main_t * pm) +{ + demo_struct2_t *demo2; + demo_struct1_t *demo1; + time_t starttime = time (0); + char *datestring = ctime (&starttime); + void *oldheap; + + /* Get back the root pointer */ + demo1 = svmdb_local_get_variable_reference + (pm->c, SVMDB_NAMESPACE_VEC, "demo1_location"); + + /* It doesnt exist create our data structures */ + if (demo1 == 0) + { + /* If you want MP / thread safety, lock the region... */ + pthread_mutex_lock (&pm->c->db_rp->mutex); + + /* Switch to the shared memory region heap */ + oldheap = svm_push_data_heap (pm->c->db_rp); + + /* Allocate the top-level structure as a single element vector */ + vec_validate (demo1, 0); + + /* Allocate the next-level structure as a plain old memory obj */ + demo2 = clib_mem_alloc (sizeof (*demo2)); + + demo1->demo2 = demo2; + demo1->name = format (0, "My name is Ishmael%c", 0); + demo2->string1 = format (0, "Here is string1%c", 0); + demo2->string2 = format (0, "Born at %s%c", datestring, 0); + + /* Back to the process-private heap */ + svm_pop_heap (oldheap); + pthread_mutex_unlock (&pm->c->db_rp->mutex); + + /* + * Set the root pointer. Note: this guy switches heaps, locks, etc. + * We allocated demo1 as a vector to make this "just work..." + */ + svmdb_local_set_vec_variable (pm->c, "demo1_location", + demo1, sizeof (demo1)); + + } + else + { + /* retrieve and print data from shared memory */ + demo2 = demo1->demo2; + fformat (stdout, "name: %s\n", demo1->name); + fformat (stdout, "demo2 location: %llx\n", demo2); + fformat (stdout, "string1: %s\n", demo2->string1); + fformat (stdout, "string2: %s\n", demo2->string2); + } + return 0; +} + +void +unserialize_demo1 (serialize_main_t * sm, va_list * args) +{ + demo_struct1_t **result = va_arg (*args, demo_struct1_t **); + demo_struct1_t *demo1; + demo_struct2_t *demo2; + + /* Allocate data structures in process private memory */ + demo1 = clib_mem_alloc (sizeof (*demo1)); + demo2 = clib_mem_alloc (sizeof (*demo2)); + demo1->demo2 = demo2; + + /* retrieve data from shared memory checkpoint */ + unserialize_cstring (sm, (char **) &demo1->name); + unserialize_cstring (sm, (char **) &demo2->string1); + unserialize_cstring (sm, (char **) &demo2->string2); + *result = demo1; +} + +void +serialize_demo1 (serialize_main_t * sm, va_list * args) +{ + demo_struct1_t *demo1 = va_arg (*args, demo_struct1_t *); + demo_struct2_t *demo2 = demo1->demo2; + + serialize_cstring (sm, (char *) demo1->name); + serialize_cstring (sm, (char *) demo2->string1); + serialize_cstring (sm, (char *) demo2->string2); +} + +/* Serialize / unserialize variant */ +clib_error_t * +persist_serialize (persist_main_t * pm) +{ + u8 *checkpoint; + serialize_main_t sm; + + demo_struct2_t *demo2; + demo_struct1_t *demo1; + time_t starttime = time (0); + char *datestring = ctime (&starttime); + + /* Get back the root pointer */ + checkpoint = svmdb_local_get_vec_variable (pm->c, "demo1_checkpoint", + sizeof (u8)); + + /* It doesnt exist create our data structures */ + if (checkpoint == 0) + { + /* Allocate data structures in process-private memory */ + demo1 = clib_mem_alloc (sizeof (*demo2)); + vec_validate (demo1, 0); + demo2 = clib_mem_alloc (sizeof (*demo2)); + + demo1->demo2 = demo2; + demo1->name = format (0, "My name is Ishmael%c", 0); + demo2->string1 = format (0, "Here is string1%c", 0); + demo2->string2 = format (0, "Born at %s%c", datestring, 0); + + /* Create checkpoint */ + serialize_open_vector (&sm, checkpoint); + serialize (&sm, serialize_demo1, demo1); + checkpoint = serialize_close_vector (&sm); + + /* Copy checkpoint into shared memory */ + svmdb_local_set_vec_variable (pm->c, "demo1_checkpoint", + checkpoint, sizeof (u8)); + /* Toss the process-private-memory original.. */ + vec_free (checkpoint); + } + else + { + /* Open the checkpoint */ + unserialize_open_data (&sm, checkpoint, vec_len (checkpoint)); + unserialize (&sm, unserialize_demo1, &demo1); + + /* Toss the process-private-memory checkpoint copy */ + vec_free (checkpoint); + + /* Off we go... */ + demo2 = demo1->demo2; + fformat (stdout, "name: %s\n", demo1->name); + fformat (stdout, "demo2 location: %llx\n", demo2); + fformat (stdout, "string1: %s\n", demo2->string1); + fformat (stdout, "string2: %s\n", demo2->string2); + } + return 0; +} + + +int +main (int argc, char **argv) +{ + unformat_input_t _input, *input = &_input; + persist_main_t *pm = &persist_main; + clib_error_t *error = 0; + + /* Make a 4mb database arena, chroot so it's truly private */ + pm->c = svmdb_map_chroot_size ("/ptest", 4 << 20); + + ASSERT (pm->c); + + unformat_init_command_line (input, argv); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "malloc")) + error = persist_malloc (pm); + else if (unformat (input, "serialize")) + error = persist_serialize (pm); + else + { + error = clib_error_return (0, "Unknown flavor '%U'", + format_unformat_error, input); + break; + } + } + + svmdb_unmap (pm->c); + + if (error) + { + clib_error_report (error); + exit (1); + } + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/ssvm.c b/src/svm/ssvm.c new file mode 100644 index 00000000000..6f409eb68b6 --- /dev/null +++ b/src/svm/ssvm.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ssvm.h" + +int +ssvm_master_init (ssvm_private_t * ssvm, u32 master_index) +{ + int ssvm_fd; + u8 *ssvm_filename; + u8 junk = 0; + int flags; + ssvm_shared_header_t *sh; + u64 ticks = clib_cpu_time_now (); + u64 randomize_baseva; + void *oldheap; + + if (ssvm->ssvm_size == 0) + return SSVM_API_ERROR_NO_SIZE; + + ssvm_filename = format (0, "/dev/shm/%s%c", ssvm->name, 0); + + unlink ((char *) ssvm_filename); + + vec_free (ssvm_filename); + + ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR | O_CREAT | O_EXCL, 0777); + + if (ssvm_fd < 0) + { + clib_unix_warning ("create segment '%s'", ssvm->name); + return SSVM_API_ERROR_CREATE_FAILURE; + } + + if (lseek (ssvm_fd, ssvm->ssvm_size, SEEK_SET) < 0) + { + clib_unix_warning ("lseek"); + close (ssvm_fd); + return SSVM_API_ERROR_SET_SIZE; + } + + if (write (ssvm_fd, &junk, 1) != 1) + { + clib_unix_warning ("set ssvm size"); + close (ssvm_fd); + return SSVM_API_ERROR_SET_SIZE; + } + + flags = MAP_SHARED; + if (ssvm->requested_va) + flags |= MAP_FIXED; + + randomize_baseva = (ticks & 15) * MMAP_PAGESIZE; + + if (ssvm->requested_va) + ssvm->requested_va += randomize_baseva; + + sh = ssvm->sh = + (ssvm_shared_header_t *) mmap ((void *) ssvm->requested_va, + ssvm->ssvm_size, PROT_READ | PROT_WRITE, + flags, ssvm_fd, 0); + + if (ssvm->sh == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + + close (ssvm_fd); + + ssvm->my_pid = getpid (); + sh->master_pid = ssvm->my_pid; + sh->ssvm_size = ssvm->ssvm_size; + sh->heap = mheap_alloc_with_flags + (((u8 *) sh) + MMAP_PAGESIZE, ssvm->ssvm_size - MMAP_PAGESIZE, + MHEAP_FLAG_DISABLE_VM | MHEAP_FLAG_THREAD_SAFE); + + sh->ssvm_va = pointer_to_uword (sh); + sh->master_index = master_index; + + oldheap = ssvm_push_heap (sh); + sh->name = format (0, "%s%c", ssvm->name, 0); + ssvm_pop_heap (oldheap); + + ssvm->i_am_master = 1; + + /* The application has to set set sh->ready... */ + return 0; +} + +int +ssvm_slave_init (ssvm_private_t * ssvm, int timeout_in_seconds) +{ + struct stat stat; + int ssvm_fd = -1; + ssvm_shared_header_t *sh; + + ssvm->i_am_master = 0; + + while (timeout_in_seconds-- > 0) + { + if (ssvm_fd < 0) + ssvm_fd = shm_open ((char *) ssvm->name, O_RDWR, 0777); + if (ssvm_fd < 0) + { + sleep (1); + continue; + } + if (fstat (ssvm_fd, &stat) < 0) + { + sleep (1); + continue; + } + + if (stat.st_size > 0) + goto map_it; + } + clib_warning ("slave timeout"); + return SSVM_API_ERROR_SLAVE_TIMEOUT; + +map_it: + sh = (void *) mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, + ssvm_fd, 0); + if (sh == MAP_FAILED) + { + clib_unix_warning ("slave research mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + + while (timeout_in_seconds-- > 0) + { + if (sh->ready) + goto re_map_it; + } + close (ssvm_fd); + munmap (sh, MMAP_PAGESIZE); + clib_warning ("slave timeout 2"); + return SSVM_API_ERROR_SLAVE_TIMEOUT; + +re_map_it: + ssvm->requested_va = (u64) sh->ssvm_va; + ssvm->ssvm_size = sh->ssvm_size; + munmap (sh, MMAP_PAGESIZE); + + sh = ssvm->sh = (void *) mmap ((void *) ssvm->requested_va, ssvm->ssvm_size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, ssvm_fd, 0); + + if (sh == MAP_FAILED) + { + clib_unix_warning ("slave final mmap"); + close (ssvm_fd); + return SSVM_API_ERROR_MMAP; + } + sh->slave_pid = getpid (); + return 0; +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/ssvm.h b/src/svm/ssvm.h new file mode 100644 index 00000000000..9e61b9a0827 --- /dev/null +++ b/src/svm/ssvm.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __included_ssvm_h__ +#define __included_ssvm_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMAP_PAGESIZE (4<<10) +#define SSVM_N_OPAQUE 7 + +typedef struct +{ + /* Spin-lock */ + volatile u32 lock; + volatile u32 owner_pid; + int recursion_count; + u32 tag; /* for debugging */ + + /* The allocation arena */ + void *heap; + + /* Segment must be mapped at this address, or no supper */ + u64 ssvm_va; + /* The actual mmap size */ + u64 ssvm_size; + u32 master_pid; + u32 slave_pid; + u8 *name; + void *opaque[SSVM_N_OPAQUE]; + + /* Set when the master application thinks it's time to make the donuts */ + volatile u32 ready; + + /* Needed to make unique MAC addresses, etc. */ + u32 master_index; +} ssvm_shared_header_t; + +typedef struct +{ + ssvm_shared_header_t *sh; + u64 ssvm_size; + u32 my_pid; + u32 vlib_hw_if_index; + u8 *name; + uword requested_va; + int i_am_master; + u32 per_interface_next_index; + u32 *rx_queue; +} ssvm_private_t; + +always_inline void +ssvm_lock (ssvm_shared_header_t * h, u32 my_pid, u32 tag) +{ + if (h->owner_pid == my_pid) + { + h->recursion_count++; + return; + } + + while (__sync_lock_test_and_set (&h->lock, 1)) + ; + + h->owner_pid = my_pid; + h->recursion_count = 1; + h->tag = tag; +} + +always_inline void +ssvm_unlock (ssvm_shared_header_t * h) +{ + if (--h->recursion_count == 0) + { + h->owner_pid = 0; + h->tag = 0; + CLIB_MEMORY_BARRIER (); + h->lock = 0; + } +} + +static inline void * +ssvm_push_heap (ssvm_shared_header_t * sh) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (sh->heap); + return ((void *) oldheap); +} + +static inline void +ssvm_pop_heap (void *oldheap) +{ + clib_mem_set_heap (oldheap); +} + +#define foreach_ssvm_api_error \ +_(NO_NAME, "No shared segment name", -10) \ +_(NO_SIZE, "Size not set (master)", -11) \ +_(CREATE_FAILURE, "Create failed", -12) \ +_(SET_SIZE, "Set size failed", -13) \ +_(MMAP, "mmap failed", -14) \ +_(SLAVE_TIMEOUT, "Slave map timeout", -15) + +typedef enum +{ +#define _(n,s,c) SSVM_API_ERROR_##n = c, + foreach_ssvm_api_error +#undef _ +} ssvm_api_error_enum_t; + +#define SSVM_API_ERROR_NO_NAME (-10) + +int ssvm_master_init (ssvm_private_t * ssvm, u32 master_index); +int ssvm_slave_init (ssvm_private_t * ssvm, int timeout_in_seconds); + +#endif /* __included_ssvm_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm.c b/src/svm/svm.c new file mode 100644 index 00000000000..e4ca98e1ed2 --- /dev/null +++ b/src/svm/svm.c @@ -0,0 +1,1237 @@ +/* + *------------------------------------------------------------------ + * svm.c - shared VM allocation, mmap(...MAP_FIXED...) + * library + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + +static svm_region_t *root_rp; +static int root_rp_refcount; + +#define MAXLOCK 2 +static pthread_mutex_t *mutexes_held[MAXLOCK]; +static int nheld; + +svm_region_t * +svm_get_root_rp (void) +{ + return root_rp; +} + +#define MUTEX_DEBUG + +static void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif + ASSERT (nheld < MAXLOCK); + /* + * Keep score of held mutexes so we can try to exit + * cleanly if the world comes to an end at the worst possible + * moment + */ + mutexes_held[nheld++] = &rp->mutex; +} + +static void +region_unlock (svm_region_t * rp) +{ + int i, j; +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + + for (i = nheld - 1; i >= 0; i--) + { + if (mutexes_held[i] == &rp->mutex) + { + for (j = i; j < MAXLOCK - 1; j++) + mutexes_held[j] = mutexes_held[j + 1]; + nheld--; + goto found; + } + } + ASSERT (0); + +found: + CLIB_MEMORY_BARRIER (); + pthread_mutex_unlock (&rp->mutex); +} + + +static u8 * +format_svm_flags (u8 * s, va_list * args) +{ + uword f = va_arg (*args, uword); + + if (f & SVM_FLAGS_MHEAP) + s = format (s, "MHEAP "); + if (f & SVM_FLAGS_FILE) + s = format (s, "FILE "); + if (f & SVM_FLAGS_NODATA) + s = format (s, "NODATA "); + if (f & SVM_FLAGS_NEED_DATA_INIT) + s = format (s, "INIT "); + + return (s); +} + +static u8 * +format_svm_size (u8 * s, va_list * args) +{ + uword size = va_arg (*args, uword); + + if (size >= (1 << 20)) + { + s = format (s, "(%d mb)", size >> 20); + } + else if (size >= (1 << 10)) + { + s = format (s, "(%d kb)", size >> 10); + } + else + { + s = format (s, "(%d bytes)", size); + } + return (s); +} + +u8 * +format_svm_region (u8 * s, va_list * args) +{ + svm_region_t *rp = va_arg (*args, svm_region_t *); + int verbose = va_arg (*args, int); + int i; + uword lo, hi; + + s = format (s, "%s: base va 0x%x size 0x%x %U\n", + rp->region_name, rp->virtual_base, + rp->virtual_size, format_svm_size, rp->virtual_size); + s = format (s, " user_ctx 0x%x, bitmap_size %d\n", + rp->user_ctx, rp->bitmap_size); + + if (verbose) + { + s = format (s, " flags: 0x%x %U\n", rp->flags, + format_svm_flags, rp->flags); + s = format (s, + " region_heap 0x%x data_base 0x%x data_heap 0x%x\n", + rp->region_heap, rp->data_base, rp->data_heap); + } + + s = format (s, " %d clients, pids: ", vec_len (rp->client_pids)); + + for (i = 0; i < vec_len (rp->client_pids); i++) + s = format (s, "%d ", rp->client_pids[i]); + + s = format (s, "\n"); + + if (verbose) + { + lo = hi = ~0; + + s = format (s, " VM in use: "); + + for (i = 0; i < rp->bitmap_size; i++) + { + if (clib_bitmap_get_no_check (rp->bitmap, i) != 0) + { + if (lo == ~0) + { + hi = lo = rp->virtual_base + i * MMAP_PAGESIZE; + } + else + { + hi = rp->virtual_base + i * MMAP_PAGESIZE; + } + } + else + { + if (lo != ~0) + { + hi = rp->virtual_base + i * MMAP_PAGESIZE - 1; + s = format (s, " 0x%x - 0x%x (%dk)\n", lo, hi, + (hi - lo) >> 10); + lo = hi = ~0; + } + } + } + s = format (s, " rgn heap stats: %U", format_mheap, + rp->region_heap, 0); + if ((rp->flags & SVM_FLAGS_MHEAP) && rp->data_heap) + { + s = format (s, "\n data heap stats: %U", format_mheap, + rp->data_heap, 1); + } + s = format (s, "\n"); + } + + return (s); +} + +/* + * rnd_pagesize + * Round to a pagesize multiple, presumably 4k works + */ +static u64 +rnd_pagesize (u64 size) +{ + u64 rv; + + rv = (size + (MMAP_PAGESIZE - 1)) & ~(MMAP_PAGESIZE - 1); + return (rv); +} + +/* + * svm_data_region_setup + */ +static int +svm_data_region_create (svm_map_region_args_t * a, svm_region_t * rp) +{ + int fd; + u8 junk = 0; + uword map_size; + + map_size = rp->virtual_size - (MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : + SVM_PVT_MHEAP_SIZE)); + + if (a->flags & SVM_FLAGS_FILE) + { + struct stat statb; + + fd = open (a->backing_file, O_RDWR | O_CREAT, 0777); + + if (fd < 0) + { + clib_unix_warning ("open"); + return -1; + } + + if (fstat (fd, &statb) < 0) + { + clib_unix_warning ("fstat"); + close (fd); + return -2; + } + + if (statb.st_mode & S_IFREG) + { + if (statb.st_size == 0) + { + if (lseek (fd, map_size, SEEK_SET) == (off_t) - 1) + { + clib_unix_warning ("seek region size"); + close (fd); + return -3; + } + if (write (fd, &junk, 1) != 1) + { + clib_unix_warning ("set region size"); + close (fd); + return -3; + } + } + else + { + map_size = rnd_pagesize (statb.st_size); + } + } + else + { + map_size = a->backing_mmap_size; + } + + ASSERT (map_size <= rp->virtual_size - + (MMAP_PAGESIZE + SVM_PVT_MHEAP_SIZE)); + + if (mmap (rp->data_base, map_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (fd); + return -3; + } + close (fd); + rp->backing_file = (char *) format (0, "%s\0", a->backing_file); + rp->flags |= SVM_FLAGS_FILE; + } + + if (a->flags & SVM_FLAGS_MHEAP) + { + rp->data_heap = + mheap_alloc_with_flags ((void *) (rp->data_base), map_size, + MHEAP_FLAG_DISABLE_VM); + rp->flags |= SVM_FLAGS_MHEAP; + } + return 0; +} + +static int +svm_data_region_map (svm_map_region_args_t * a, svm_region_t * rp) +{ + int fd; + u8 junk = 0; + uword map_size; + struct stat statb; + + map_size = rp->virtual_size - + (MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE)); + + if (a->flags & SVM_FLAGS_FILE) + { + + fd = open (a->backing_file, O_RDWR, 0777); + + if (fd < 0) + { + clib_unix_warning ("open"); + return -1; + } + + if (fstat (fd, &statb) < 0) + { + clib_unix_warning ("fstat"); + close (fd); + return -2; + } + + if (statb.st_mode & S_IFREG) + { + if (statb.st_size == 0) + { + if (lseek (fd, map_size, SEEK_SET) == (off_t) - 1) + { + clib_unix_warning ("seek region size"); + close (fd); + return -3; + } + if (write (fd, &junk, 1) != 1) + { + clib_unix_warning ("set region size"); + close (fd); + return -3; + } + } + else + { + map_size = rnd_pagesize (statb.st_size); + } + } + else + { + map_size = a->backing_mmap_size; + } + + ASSERT (map_size <= rp->virtual_size + - (MMAP_PAGESIZE + + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE))); + + if (mmap (rp->data_base, map_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0) == MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (fd); + return -3; + } + close (fd); + } + return 0; +} + +u8 * +shm_name_from_svm_map_region_args (svm_map_region_args_t * a) +{ + u8 *path; + u8 *shm_name; + u8 *split_point; + u8 *mkdir_arg = 0; + int root_path_offset = 0; + int name_offset = 0; + + if (a->root_path) + { + /* Tolerate present or absent slashes */ + if (a->root_path[0] == '/') + root_path_offset++; + + /* create the root_path under /dev/shm + iterate through path creating directories */ + + path = format (0, "/dev/shm/%s%c", &a->root_path[root_path_offset], 0); + split_point = path + 1; + vec_add1 (mkdir_arg, '-'); + + while (*split_point) + { + while (*split_point && *split_point != '/') + { + vec_add1 (mkdir_arg, *split_point); + split_point++; + } + vec_add1 (mkdir_arg, 0); + + /* ready to descend another level */ + mkdir_arg[vec_len (mkdir_arg) - 1] = '-'; + split_point++; + } + vec_free (mkdir_arg); + vec_free (path); + + if (a->name[0] == '/') + name_offset = 1; + + shm_name = format (0, "/%s-%s%c", a->root_path, + &a->name[name_offset], 0); + } + else + shm_name = format (0, "%s%c", a->name, 0); + return (shm_name); +} + +/* + * svm_map_region + */ +void * +svm_map_region (svm_map_region_args_t * a) +{ + int svm_fd; + svm_region_t *rp; + pthread_mutexattr_t attr; + pthread_condattr_t cattr; + int deadman = 0; + u8 junk = 0; + void *oldheap; + int overhead_space; + int rv; + uword data_base; + int nbits, words, bit; + int pid_holding_region_lock; + u8 *shm_name; + int dead_region_recovery = 0; + int time_left; + struct stat stat; + struct timespec ts, tsrem; + + if (CLIB_DEBUG > 1) + clib_warning ("[%d] map region %s", getpid (), a->name); + + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + ASSERT (a->name); + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR | O_CREAT | O_EXCL, 0777); + + if (svm_fd >= 0) + { + if (fchmod (svm_fd, 0770) < 0) + clib_unix_warning ("segment chmod"); + /* This turns out to fail harmlessly if the client starts first */ + if (fchown (svm_fd, a->uid, a->gid) < 0) + clib_unix_warning ("segment chown [ok if client starts first]"); + + vec_free (shm_name); + + if (lseek (svm_fd, a->size, SEEK_SET) == (off_t) - 1) + { + clib_warning ("seek region size"); + close (svm_fd); + return (0); + } + if (write (svm_fd, &junk, 1) != 1) + { + clib_warning ("set region size"); + close (svm_fd); + return (0); + } + + rp = mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + clib_unix_warning ("mmap create"); + close (svm_fd); + return (0); + } + close (svm_fd); + memset (rp, 0, sizeof (*rp)); + + if (pthread_mutexattr_init (&attr)) + clib_unix_warning ("mutexattr_init"); + + if (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED)) + clib_unix_warning ("mutexattr_setpshared"); + + if (pthread_mutex_init (&rp->mutex, &attr)) + clib_unix_warning ("mutex_init"); + + if (pthread_mutexattr_destroy (&attr)) + clib_unix_warning ("mutexattr_destroy"); + + if (pthread_condattr_init (&cattr)) + clib_unix_warning ("condattr_init"); + + if (pthread_condattr_setpshared (&cattr, PTHREAD_PROCESS_SHARED)) + clib_unix_warning ("condattr_setpshared"); + + if (pthread_cond_init (&rp->condvar, &cattr)) + clib_unix_warning ("cond_init"); + + if (pthread_condattr_destroy (&cattr)) + clib_unix_warning ("condattr_destroy"); + + region_lock (rp, 1); + + rp->virtual_base = a->baseva; + rp->virtual_size = a->size; + + rp->region_heap = + mheap_alloc_with_flags ((void *) (a->baseva + MMAP_PAGESIZE), + (a->pvt_heap_size != 0) ? + a->pvt_heap_size : SVM_PVT_MHEAP_SIZE, + MHEAP_FLAG_DISABLE_VM); + oldheap = svm_push_pvt_heap (rp); + + rp->region_name = (char *) format (0, "%s%c", a->name, 0); + vec_add1 (rp->client_pids, getpid ()); + + nbits = rp->virtual_size / MMAP_PAGESIZE; + + ASSERT (nbits > 0); + rp->bitmap_size = nbits; + words = (nbits + BITS (uword) - 1) / BITS (uword); + vec_validate (rp->bitmap, words - 1); + + overhead_space = MMAP_PAGESIZE /* header */ + + ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + + bit = 0; + data_base = (uword) rp->virtual_base; + + if (a->flags & SVM_FLAGS_NODATA) + rp->flags |= SVM_FLAGS_NEED_DATA_INIT; + + do + { + clib_bitmap_set_no_check (rp->bitmap, bit, 1); + bit++; + overhead_space -= MMAP_PAGESIZE; + data_base += MMAP_PAGESIZE; + } + while (overhead_space > 0); + + rp->data_base = (void *) data_base; + + /* + * Note: although the POSIX spec guarantees that only one + * process enters this block, we have to play games + * to hold off clients until e.g. the mutex is ready + */ + rp->version = SVM_VERSION; + + /* setup the data portion of the region */ + + rv = svm_data_region_create (a, rp); + if (rv) + { + clib_warning ("data_region_create: %d", rv); + } + + region_unlock (rp); + + svm_pop_heap (oldheap); + + return ((void *) rp); + } + else + { + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + vec_free (shm_name); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + return (0); + } + + time_left = 20; + while (1) + { + if (0 != fstat (svm_fd, &stat)) + { + clib_warning ("fstat failed: %d", errno); + close (svm_fd); + return (0); + } + if (stat.st_size > 0) + { + break; + } + if (0 == time_left) + { + clib_warning ("waiting for resize of shm file timed out"); + close (svm_fd); + return (0); + } + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + while (nanosleep (&ts, &tsrem) < 0) + ts = tsrem; + time_left--; + } + + rp = mmap (0, MMAP_PAGESIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + return (0); + } + /* + * We lost the footrace to create this region; make sure + * the winner has crossed the finish line. + */ + while (rp->version == 0 && deadman++ < 5) + { + sleep (1); + } + + /* + * -ed? + */ + if (rp->version == 0) + { + clib_warning ("rp->version %d not %d", rp->version, SVM_VERSION); + close (svm_fd); + munmap (rp, a->size); + return (0); + } + /* Remap now that the region has been placed */ + a->baseva = rp->virtual_base; + a->size = rp->virtual_size; + munmap (rp, MMAP_PAGESIZE); + + rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + close (svm_fd); + return (0); + } + + if ((uword) rp != rp->virtual_base) + { + clib_warning ("mmap botch"); + } + + /* + * Try to fix the region mutex if it is held by + * a dead process + */ + pid_holding_region_lock = rp->mutex_owner_pid; + if (pid_holding_region_lock && kill (pid_holding_region_lock, 0) < 0) + { + clib_warning + ("region %s mutex held by dead pid %d, tag %d, force unlock", + rp->region_name, pid_holding_region_lock, rp->mutex_owner_tag); + /* owner pid is nonexistent */ + rp->mutex.__data.__owner = 0; + rp->mutex.__data.__lock = 0; + dead_region_recovery = 1; + } + + if (dead_region_recovery) + clib_warning ("recovery: attempt to re-lock region"); + + region_lock (rp, 2); + oldheap = svm_push_pvt_heap (rp); + vec_add1 (rp->client_pids, getpid ()); + + if (dead_region_recovery) + clib_warning ("recovery: attempt svm_data_region_map"); + + rv = svm_data_region_map (a, rp); + if (rv) + { + clib_warning ("data_region_map: %d", rv); + } + + if (dead_region_recovery) + clib_warning ("unlock and continue"); + + region_unlock (rp); + + svm_pop_heap (oldheap); + + return ((void *) rp); + + } + return 0; /* NOTREACHED */ +} + +static void +svm_mutex_cleanup (void) +{ + int i; + for (i = 0; i < nheld; i++) + { + pthread_mutex_unlock (mutexes_held[i]); + } +} + +static void +svm_region_init_internal (svm_map_region_args_t * a) +{ + svm_region_t *rp; + u64 ticks = clib_cpu_time_now (); + uword randomize_baseva; + + /* guard against klutz calls */ + if (root_rp) + return; + + root_rp_refcount++; + + atexit (svm_mutex_cleanup); + + /* Randomize the shared-VM base at init time */ + if (MMAP_PAGESIZE <= (4 << 10)) + randomize_baseva = (ticks & 15) * MMAP_PAGESIZE; + else + randomize_baseva = (ticks & 3) * MMAP_PAGESIZE; + + a->baseva += randomize_baseva; + + rp = svm_map_region (a); + ASSERT (rp); + + region_lock (rp, 3); + + /* Set up the main region data structures */ + if (rp->flags & SVM_FLAGS_NEED_DATA_INIT) + { + svm_main_region_t *mp = 0; + void *oldheap; + + rp->flags &= ~(SVM_FLAGS_NEED_DATA_INIT); + + oldheap = svm_push_pvt_heap (rp); + vec_validate (mp, 0); + mp->name_hash = hash_create_string (0, sizeof (uword)); + mp->root_path = a->root_path ? format (0, "%s%c", a->root_path, 0) : 0; + rp->data_base = mp; + svm_pop_heap (oldheap); + } + region_unlock (rp); + root_rp = rp; +} + +void +svm_region_init (void) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = 0; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = 0; + a->gid = 0; + + svm_region_init_internal (a); +} + +void +svm_region_init_chroot (char *root_path) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = root_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = 0; + a->gid = 0; + + svm_region_init_internal (a); +} + +void +svm_region_init_chroot_uid_gid (char *root_path, int uid, int gid) +{ + svm_map_region_args_t _a, *a = &_a; + + memset (a, 0, sizeof (*a)); + a->root_path = root_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + a->uid = uid; + a->gid = gid; + + svm_region_init_internal (a); +} + +void +svm_region_init_args (svm_map_region_args_t * a) +{ + svm_region_init_internal (a); +} + +void * +svm_region_find_or_create (svm_map_region_args_t * a) +{ + svm_main_region_t *mp; + svm_region_t *rp; + uword need_nbits; + int index, i; + void *oldheap; + uword *p; + u8 *name; + svm_subregion_t *subp; + + ASSERT (root_rp); + + a->size += MMAP_PAGESIZE + + ((a->pvt_heap_size != 0) ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + a->size = rnd_pagesize (a->size); + + region_lock (root_rp, 4); + oldheap = svm_push_pvt_heap (root_rp); + mp = root_rp->data_base; + + ASSERT (mp); + + /* Map the named region from the correct chroot environment */ + a->root_path = (char *) mp->root_path; + + /* + * See if this region is already known. If it is, we're + * almost done... + */ + p = hash_get_mem (mp->name_hash, a->name); + + if (p) + { + rp = svm_map_region (a); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return rp; + } + + /* Create the region. */ + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + + need_nbits = a->size / MMAP_PAGESIZE; + + index = 1; /* $$$ fixme, figure out how many bit to really skip */ + + /* + * Scan the virtual space allocation bitmap, looking for a large + * enough chunk + */ + do + { + if (clib_bitmap_get_no_check (root_rp->bitmap, index) == 0) + { + for (i = 0; i < (need_nbits - 1); i++) + { + if (clib_bitmap_get_no_check (root_rp->bitmap, index + i) == 1) + { + index = index + i; + goto next; + } + } + break; + } + index++; + next:; + } + while (index < root_rp->bitmap_size); + + /* Completely out of VM? */ + if (index >= root_rp->bitmap_size) + { + clib_warning ("region %s: not enough VM to allocate 0x%llx (%lld)", + root_rp->region_name, a->size, a->size); + svm_pop_heap (oldheap); + region_unlock (root_rp); + return 0; + } + + /* + * Mark virtual space allocated + */ +#if CLIB_DEBUG > 1 + clib_warning ("set %d bits at index %d", need_nbits, index); +#endif + + for (i = 0; i < need_nbits; i++) + { + clib_bitmap_set_no_check (root_rp->bitmap, index + i, 1); + } + + /* Place this region where it goes... */ + a->baseva = root_rp->virtual_base + index * MMAP_PAGESIZE; + + rp = svm_map_region (a); + + pool_get (mp->subregions, subp); + name = format (0, "%s%c", a->name, 0); + subp->subregion_name = name; + + hash_set_mem (mp->name_hash, name, subp - mp->subregions); + + svm_pop_heap (oldheap); + + region_unlock (root_rp); + + return (rp); +} + +/* + * svm_region_unmap + * + * Let go of the indicated region. If the calling process + * is the last customer, throw it away completely. + * The root region mutex guarantees atomicity with respect to + * a new region client showing up at the wrong moment. + */ +void +svm_region_unmap (void *rp_arg) +{ + int i, mypid = getpid (); + int nclients_left; + void *oldheap; + uword virtual_base, virtual_size; + svm_region_t *rp = rp_arg; + char *name; + + /* + * If we take a signal while holding one or more shared-memory + * mutexes, we may end up back here from an otherwise + * benign exit handler. Bail out to avoid a recursive + * mutex screw-up. + */ + if (nheld) + return; + + ASSERT (rp); + ASSERT (root_rp); + + if (CLIB_DEBUG > 1) + clib_warning ("[%d] unmap region %s", getpid (), rp->region_name); + + region_lock (root_rp, 5); + region_lock (rp, 6); + + oldheap = svm_push_pvt_heap (rp); /* nb vec_delete() in the loop */ + + /* Remove the caller from the list of mappers */ + for (i = 0; i < vec_len (rp->client_pids); i++) + { + if (rp->client_pids[i] == mypid) + { + vec_delete (rp->client_pids, 1, i); + goto found; + } + } + clib_warning ("pid %d AWOL", mypid); + +found: + + svm_pop_heap (oldheap); + + nclients_left = vec_len (rp->client_pids); + virtual_base = rp->virtual_base; + virtual_size = rp->virtual_size; + + if (nclients_left == 0) + { + int index, nbits, i; + svm_main_region_t *mp; + uword *p; + svm_subregion_t *subp; + + /* Kill the region, last guy on his way out */ + + oldheap = svm_push_pvt_heap (root_rp); + name = vec_dup (rp->region_name); + + virtual_base = rp->virtual_base; + virtual_size = rp->virtual_size; + + /* Figure out which bits to clear in the root region bitmap */ + index = (virtual_base - root_rp->virtual_base) / MMAP_PAGESIZE; + + nbits = (virtual_size + MMAP_PAGESIZE - 1) / MMAP_PAGESIZE; + +#if CLIB_DEBUG > 1 + clib_warning ("clear %d bits at index %d", nbits, index); +#endif + /* Give back the allocated VM */ + for (i = 0; i < nbits; i++) + { + clib_bitmap_set_no_check (root_rp->bitmap, index + i, 0); + } + + mp = root_rp->data_base; + + p = hash_get_mem (mp->name_hash, name); + + /* Better never happen ... */ + if (p == NULL) + { + region_unlock (rp); + region_unlock (root_rp); + svm_pop_heap (oldheap); + clib_warning ("Region name '%s' not found?", name); + return; + } + + /* Remove from the root region subregion pool */ + subp = mp->subregions + p[0]; + pool_put (mp->subregions, subp); + + hash_unset_mem (mp->name_hash, name); + + vec_free (name); + + region_unlock (rp); + shm_unlink (rp->region_name); + munmap ((void *) virtual_base, virtual_size); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return; + } + + region_unlock (rp); + region_unlock (root_rp); + + munmap ((void *) virtual_base, virtual_size); +} + +/* + * svm_region_exit + * There is no clean way to unlink the + * root region when all clients go away, + * so remove the pid entry and call it a day. + */ +void +svm_region_exit () +{ + void *oldheap; + int i, mypid = getpid (); + uword virtual_base, virtual_size; + + /* It felt so nice we did it twice... */ + if (root_rp == 0) + return; + + if (--root_rp_refcount > 0) + return; + + /* + * If we take a signal while holding one or more shared-memory + * mutexes, we may end up back here from an otherwise + * benign exit handler. Bail out to avoid a recursive + * mutex screw-up. + */ + if (nheld) + return; + + region_lock (root_rp, 7); + oldheap = svm_push_pvt_heap (root_rp); + + virtual_base = root_rp->virtual_base; + virtual_size = root_rp->virtual_size; + + for (i = 0; i < vec_len (root_rp->client_pids); i++) + { + if (root_rp->client_pids[i] == mypid) + { + vec_delete (root_rp->client_pids, 1, i); + goto found; + } + } + clib_warning ("pid %d AWOL", mypid); + +found: + + region_unlock (root_rp); + svm_pop_heap (oldheap); + + root_rp = 0; + munmap ((void *) virtual_base, virtual_size); +} + +void +svm_client_scan_this_region_nolock (svm_region_t * rp) +{ + int j; + int mypid = getpid (); + void *oldheap; + + for (j = 0; j < vec_len (rp->client_pids); j++) + { + if (mypid == rp->client_pids[j]) + continue; + if (rp->client_pids[j] && (kill (rp->client_pids[j], 0) < 0)) + { + clib_warning ("%s: cleanup ghost pid %d", + rp->region_name, rp->client_pids[j]); + /* nb: client vec in rp->region_heap */ + oldheap = svm_push_pvt_heap (rp); + vec_delete (rp->client_pids, 1, j); + j--; + svm_pop_heap (oldheap); + } + } +} + + +/* + * Scan svm regions for dead clients + */ +void +svm_client_scan (char *root_path) +{ + int i, j; + svm_main_region_t *mp; + svm_map_region_args_t *a = 0; + svm_region_t *root_rp; + svm_region_t *rp; + svm_subregion_t *subp; + u8 *name = 0; + u8 **svm_names = 0; + void *oldheap; + int mypid = getpid (); + + vec_validate (a, 0); + + svm_region_init_chroot (root_path); + + root_rp = svm_get_root_rp (); + + pthread_mutex_lock (&root_rp->mutex); + + mp = root_rp->data_base; + + for (j = 0; j < vec_len (root_rp->client_pids); j++) + { + if (mypid == root_rp->client_pids[j]) + continue; + if (root_rp->client_pids[j] && (kill (root_rp->client_pids[j], 0) < 0)) + { + clib_warning ("%s: cleanup ghost pid %d", + root_rp->region_name, root_rp->client_pids[j]); + /* nb: client vec in root_rp->region_heap */ + oldheap = svm_push_pvt_heap (root_rp); + vec_delete (root_rp->client_pids, 1, j); + j--; + svm_pop_heap (oldheap); + } + } + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + vec_validate (a, 0); + a->root_path = root_path; + a->name = (char *) svm_names[i]; + rp = svm_region_find_or_create (a); + if (rp) + { + pthread_mutex_lock (&rp->mutex); + + svm_client_scan_this_region_nolock (rp); + + pthread_mutex_unlock (&rp->mutex); + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + vec_free (a); + } + vec_free (svm_names); + + svm_region_exit (); + + vec_free (a); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm.h b/src/svm/svm.h new file mode 100644 index 00000000000..0b87dbcbc64 --- /dev/null +++ b/src/svm/svm.h @@ -0,0 +1,207 @@ +/* + *------------------------------------------------------------------ + * svm.h - shared VM allocation, mmap(...MAP_FIXED...) + * brain police + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef __included_svm_h__ +#define __included_svm_h__ + +#include +#include +#include + +#define MMAP_PAGESIZE (clib_mem_get_page_size()) + +#define SVM_VERSION ((1<<16) | 1) /* set to declare region ready. */ + +#define SVM_FLAGS_MHEAP (1<<0) /* region contains an mheap */ +#define SVM_FLAGS_FILE (1<<1) /* region backed by one or more files */ +#define SVM_FLAGS_NODATA (1<<2) /* region will be further subdivided */ +#define SVM_FLAGS_NEED_DATA_INIT (1<<3) + +#define SVM_PVT_MHEAP_SIZE (128<<10) /* region's private mheap (128k) */ + +typedef struct svm_region_ +{ + volatile uword version; + pthread_mutex_t mutex; + pthread_cond_t condvar; + int mutex_owner_pid; /* in case of trouble */ + int mutex_owner_tag; + uword flags; + uword virtual_base; /* base of the region object */ + uword virtual_size; + void *region_heap; + void *data_base; /* data portion base address */ + void *data_heap; /* data heap, if any */ + volatile void *user_ctx; /* user context pointer */ + /* stuff allocated in the region's heap */ + uword bitmap_size; /* nbits in virtual alloc bitmap */ + uword *bitmap; /* the bitmap */ + char *region_name; + char *backing_file; + char **filenames; + uword *client_pids; + /* pad */ + + /* next page: + * (64K) clib heap for the region itself + * + * data_base -> whatever is in this region + */ + +} svm_region_t; + +typedef struct svm_map_region_args_ +{ + char *root_path; /* NULL means use the truly global arena */ + char *name; + u64 baseva; + u64 size; + u64 pvt_heap_size; + uword flags; + char *backing_file; + uword backing_mmap_size; + /* uid, gid to own the svm region(s) */ + int uid; + int gid; +} svm_map_region_args_t; + + +/* + * Memory shared across all router instances. Packet buffers, etc + * Base should be "out of the way," and size should be big enough to + * cover everything we plan to put here. + */ +#define SVM_GLOBAL_REGION_BASEVA 0x30000000 +#define SVM_GLOBAL_REGION_SIZE (64<<20) +#define SVM_GLOBAL_REGION_NAME "/global_vm" + +/* + * Memory shared across individual router instances. + */ +#define SVM_OVERLAY_REGION_BASEVA \ + (SVM_GLOBAL_REGION_BASEVA + SVM_GLOBAL_REGION_SIZE) +#define SVM_OVERLAY_REGION_SIZE (1<<20) +#define SVM_OVERLAY_REGION_BASENAME "/overlay_vm" + +typedef struct +{ + u8 *subregion_name; +} svm_subregion_t; + +typedef struct +{ + svm_subregion_t *subregions; /* subregion pool */ + uword *name_hash; + u8 *root_path; +} svm_main_region_t; + + +void *svm_region_find_or_create (svm_map_region_args_t * a); +void svm_region_init (void); +void svm_region_init_chroot (char *root_path); +void svm_region_init_chroot_uid_gid (char *root_path, int uid, int gid); +void svm_region_init_args (svm_map_region_args_t * a); +void svm_region_exit (void); +void svm_region_unmap (void *rp_arg); +void svm_client_scan (char *root_path); +void svm_client_scan_this_region_nolock (svm_region_t * rp); +u8 *shm_name_from_svm_map_region_args (svm_map_region_args_t * a); + +static inline void * +svm_mem_alloc (svm_region_t * rp, uword size) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + u8 *rv; + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + rv = clib_mem_alloc (size); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + return (rv); +} + +static inline void * +svm_mem_alloc_aligned_at_offset (svm_region_t * rp, + uword size, uword align, uword offset) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + u8 *rv; + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + rv = clib_mem_alloc_aligned_at_offset (size, align, offset, + 1 /* yes, call os_out_of_memory */ ); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + return (rv); +} + +static inline void +svm_mem_free (svm_region_t * rp, void *ptr) +{ + u8 *oldheap; + ASSERT (rp->flags & SVM_FLAGS_MHEAP); + + pthread_mutex_lock (&rp->mutex); + oldheap = clib_mem_set_heap (rp->data_heap); + clib_mem_free (ptr); + clib_mem_set_heap (oldheap); + pthread_mutex_unlock (&rp->mutex); + +} + +static inline void * +svm_push_pvt_heap (svm_region_t * rp) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (rp->region_heap); + return ((void *) oldheap); +} + +static inline void * +svm_push_data_heap (svm_region_t * rp) +{ + u8 *oldheap; + oldheap = clib_mem_set_heap (rp->data_heap); + return ((void *) oldheap); +} + +static inline void +svm_pop_heap (void *oldheap) +{ + clib_mem_set_heap (oldheap); +} + +u8 *format_svm_region (u8 * s, va_list * args); + +svm_region_t *svm_get_root_rp (void); + +#endif /* __included_svm_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svm_test.c b/src/svm/svm_test.c new file mode 100644 index 00000000000..ab0b9e248e6 --- /dev/null +++ b/src/svm/svm_test.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + *------------------------------------------------------------------ + * svm_test.c -- brain police + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + + +int +main (int argc, char **argv) +{ + svm_region_t *root_rp, *rp; + svm_map_region_args_t *a = 0; + + vec_validate (a, 0); + + root_rp = svm_region_init (); + + ASSERT (root_rp); + + a->name = "/qvnet"; + a->size = (4 << 10); + + rp = svm_region_find_or_create (root_rp, a); + + ASSERT (rp); + + *((u32 *) rp->data_base) = 0xdeadbeef; + svm_region_unmap (root_rp, rp); + + fformat (stdout, "exiting...\n"); + + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdb.c b/src/svm/svmdb.c new file mode 100644 index 00000000000..03dfe7c33d3 --- /dev/null +++ b/src/svm/svmdb.c @@ -0,0 +1,671 @@ +/* + *------------------------------------------------------------------ + * svmdb.c -- simple shared memory database + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svmdb.h" + +static void local_set_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, + u8 * var, u8 * val, u32 elsize); + +always_inline void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif +} + +always_inline void +region_unlock (svm_region_t * rp) +{ +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + pthread_mutex_unlock (&rp->mutex); +} + +svmdb_client_t * +svmdb_map (svmdb_map_args_t * dba) +{ + svmdb_client_t *client = 0; + svm_map_region_args_t *a = 0; + svm_region_t *db_rp; + void *oldheap; + svmdb_shm_hdr_t *hp = 0; + + vec_validate (client, 0); + vec_validate (a, 0); + + svm_region_init_chroot_uid_gid (dba->root_path, dba->uid, dba->gid); + + a->root_path = dba->root_path; + a->name = "/db"; + a->size = dba->size ? dba->size : SVMDB_DEFAULT_SIZE; + a->flags = SVM_FLAGS_MHEAP; + a->uid = dba->uid; + a->gid = dba->gid; + + db_rp = client->db_rp = svm_region_find_or_create (a); + + ASSERT (db_rp); + + vec_free (a); + + region_lock (client->db_rp, 10); + /* Has someone else set up the shared-memory variable table? */ + if (db_rp->user_ctx) + { + client->shm = (void *) db_rp->user_ctx; + client->pid = getpid (); + region_unlock (client->db_rp); + ASSERT (client->shm->version == SVMDB_SHM_VERSION); + return (client); + } + /* Nope, it's our problem... */ + + /* Add a bogus client (pid=0) so the svm won't be deallocated */ + oldheap = svm_push_pvt_heap (db_rp); + vec_add1 (client->db_rp->client_pids, 0); + svm_pop_heap (oldheap); + + oldheap = svm_push_data_heap (db_rp); + + vec_validate (hp, 0); + hp->version = SVMDB_SHM_VERSION; + hp->namespaces[SVMDB_NAMESPACE_STRING] + = hash_create_string (0, sizeof (uword)); + hp->namespaces[SVMDB_NAMESPACE_VEC] + = hash_create_string (0, sizeof (uword)); + + db_rp->user_ctx = hp; + client->shm = hp; + + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + client->pid = getpid (); + + return (client); +} + +void +svmdb_unmap (svmdb_client_t * client) +{ + ASSERT (client); + + if (!svm_get_root_rp ()) + return; + + svm_region_unmap ((void *) client->db_rp); + svm_region_exit (); + vec_free (client); +} + +static void +notify_value (svmdb_value_t * v, svmdb_action_t a) +{ + int i; + int rv; + union sigval sv; + u32 value; + u32 *dead_registrations = 0; + + svmdb_notify_t *np; + + for (i = 0; i < vec_len (v->notifications); i++) + { + np = vec_elt_at_index (v->notifications, i); + if (np->action == a) + { + value = (np->action << 28) | (np->opaque); + sv.sival_ptr = (void *) (uword) value; + do + { + rv = 0; + if (sigqueue (np->pid, np->signum, sv) == 0) + break; + rv = errno; + } + while (rv == EAGAIN); + if (rv == 0) + continue; + vec_add1 (dead_registrations, i); + } + } + + for (i = 0; i < vec_len (dead_registrations); i++) + { + np = vec_elt_at_index (v->notifications, dead_registrations[i]); + clib_warning ("dead reg pid %d sig %d action %d opaque %x", + np->pid, np->signum, np->action, np->opaque); + vec_delete (v->notifications, 1, dead_registrations[i]); + } + vec_free (dead_registrations); +} + +int +svmdb_local_add_del_notification (svmdb_client_t * client, + svmdb_notification_args_t * a) +{ + uword *h; + void *oldheap; + hash_pair_t *hp; + svmdb_shm_hdr_t *shm; + u8 *dummy_value = 0; + svmdb_value_t *value; + svmdb_notify_t *np; + int i; + int rv = 0; + + ASSERT (a->elsize); + + region_lock (client->db_rp, 18); + shm = client->shm; + oldheap = svm_push_data_heap (client->db_rp); + + h = shm->namespaces[a->nspace]; + + hp = hash_get_pair_mem (h, a->var); + if (hp == 0) + { + local_set_variable_nolock (client, a->nspace, (u8 *) a->var, + dummy_value, a->elsize); + /* might have moved */ + h = shm->namespaces[a->nspace]; + hp = hash_get_pair_mem (h, a->var); + ASSERT (hp); + } + + value = pool_elt_at_index (shm->values, hp->value[0]); + + for (i = 0; i < vec_len (value->notifications); i++) + { + np = vec_elt_at_index (value->notifications, i); + if ((np->pid == client->pid) + && (np->signum == a->signum) + && (np->action == a->action) && (np->opaque == a->opaque)) + { + if (a->add_del == 0 /* delete */ ) + { + vec_delete (value->notifications, 1, i); + goto out; + } + else + { /* add */ + clib_warning + ("%s: ignore dup reg pid %d signum %d action %d opaque %x", + a->var, client->pid, a->signum, a->action, a->opaque); + rv = -2; + goto out; + } + } + } + if (a->add_del == 0) + { + rv = -3; + goto out; + } + + vec_add2 (value->notifications, np, 1); + np->pid = client->pid; + np->signum = a->signum; + np->action = a->action; + np->opaque = a->opaque; + +out: + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + return rv; +} + + +static void +local_unset_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, char *var) +{ + uword *h; + svmdb_value_t *oldvalue; + hash_pair_t *hp; + + h = client->shm->namespaces[namespace]; + hp = hash_get_pair_mem (h, var); + if (hp) + { + oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]); + if (vec_len (oldvalue->notifications)) + notify_value (oldvalue, SVMDB_ACTION_UNSET); + /* zero length value means unset */ + _vec_len (oldvalue->value) = 0; + } + client->shm->namespaces[namespace] = h; +} + +void +svmdb_local_unset_string_variable (svmdb_client_t * client, char *var) +{ + void *oldheap; + + region_lock (client->db_rp, 11); + oldheap = svm_push_data_heap (client->db_rp); + local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +static void +local_set_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, + u8 * var, u8 * val, u32 elsize) +{ + uword *h; + hash_pair_t *hp; + u8 *name; + svmdb_shm_hdr_t *shm; + + shm = client->shm; + h = shm->namespaces[namespace]; + hp = hash_get_pair_mem (h, var); + if (hp) + { + svmdb_value_t *oldvalue; + oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]); + vec_alloc (oldvalue->value, vec_len (val) * elsize); + clib_memcpy (oldvalue->value, val, vec_len (val) * elsize); + _vec_len (oldvalue->value) = vec_len (val); + notify_value (oldvalue, SVMDB_ACTION_SET); + } + else + { + svmdb_value_t *newvalue; + pool_get (shm->values, newvalue); + memset (newvalue, 0, sizeof (*newvalue)); + newvalue->elsize = elsize; + vec_alloc (newvalue->value, vec_len (val) * elsize); + clib_memcpy (newvalue->value, val, vec_len (val) * elsize); + _vec_len (newvalue->value) = vec_len (val); + name = format (0, "%s%c", var, 0); + hash_set_mem (h, name, newvalue - shm->values); + } + shm->namespaces[namespace] = h; +} + +void +svmdb_local_set_string_variable (svmdb_client_t * client, + char *var, char *val) +{ + void *oldheap; + + region_lock (client->db_rp, 12); + oldheap = svm_push_data_heap (client->db_rp); + + local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var); + + local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING, + (u8 *) var, (u8 *) val, 1 /* elsize */ ); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +static u8 * +local_get_variable_nolock (svmdb_client_t * client, + svmdb_namespace_t namespace, u8 * var) +{ + uword *h; + uword *p; + svmdb_shm_hdr_t *shm; + svmdb_value_t *oldvalue; + + shm = client->shm; + h = shm->namespaces[namespace]; + p = hash_get_mem (h, var); + if (p) + { + oldvalue = pool_elt_at_index (shm->values, p[0]); + notify_value (oldvalue, SVMDB_ACTION_GET); + return (oldvalue->value); + } + return 0; +} + +void * +svmdb_local_get_variable_reference (svmdb_client_t * client, + svmdb_namespace_t namespace, char *var) +{ + u8 *rv; + + region_lock (client->db_rp, 19); + rv = local_get_variable_nolock (client, namespace, (u8 *) var); + region_unlock (client->db_rp); + return (void *) rv; +} + +char * +svmdb_local_get_string_variable (svmdb_client_t * client, char *var) +{ + u8 *rv = 0; + + region_lock (client->db_rp, 13); + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var); + + if (rv && vec_len (rv)) + { + rv = format (0, "%s", rv); + vec_add1 (rv, 0); + } + region_unlock (client->db_rp); + return ((char *) rv); +} + +void +svmdb_local_dump_strings (svmdb_client_t * client) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm = client->shm; + + region_lock (client->db_rp, 14); + + h = client->shm->namespaces[SVMDB_NAMESPACE_STRING]; + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + + fformat(stdout, "%s: %s\n", key, + vec_len(v->value) ? v->value : (u8 *)"(nil)"); + })); + /* *INDENT-ON* */ + region_unlock (client->db_rp); +} + +int +svmdb_local_serialize_strings (svmdb_client_t * client, char *filename) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm = client->shm; + serialize_main_t _sm, *sm = &_sm; + clib_error_t *error = 0; + u8 *sanitized_name = 0; + int fd = 0; + + if (strstr (filename, "..") || index (filename, '/')) + { + error = clib_error_return (0, "Illegal characters in filename '%s'", + filename); + goto out; + } + + sanitized_name = format (0, "/tmp/%s%c", filename, 0); + + fd = creat ((char *) sanitized_name, 0644); + + if (fd < 0) + { + error = clib_error_return_unix (0, "Create '%s'", sanitized_name); + goto out; + } + + serialize_open_unix_file_descriptor (sm, fd); + + region_lock (client->db_rp, 20); + + h = client->shm->namespaces[SVMDB_NAMESPACE_STRING]; + + serialize_likely_small_unsigned_integer (sm, hash_elts (h)); + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + + /* Omit names with nil values */ + if (vec_len(v->value)) + { + serialize_cstring (sm, (char *)key); + serialize_cstring (sm, (char *)v->value); + } + })); + /* *INDENT-ON* */ + region_unlock (client->db_rp); + + serialize_close (sm); + +out: + if (fd > 0 && close (fd) < 0) + error = clib_error_return_unix (0, "close fd %d", fd); + + if (error) + { + clib_error_report (error); + return -1; + } + return 0; +} + +int +svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename) +{ + serialize_main_t _sm, *sm = &_sm; + void *oldheap; + clib_error_t *error = 0; + u8 *key, *value; + int fd = 0; + u32 nelts; + int i; + + fd = open (filename, O_RDONLY); + + if (fd < 0) + { + error = clib_error_return_unix (0, "Failed to open '%s'", filename); + goto out; + } + + unserialize_open_unix_file_descriptor (sm, fd); + + region_lock (client->db_rp, 21); + oldheap = svm_push_data_heap (client->db_rp); + + nelts = unserialize_likely_small_unsigned_integer (sm); + + for (i = 0; i < nelts; i++) + { + unserialize_cstring (sm, (char **) &key); + unserialize_cstring (sm, (char **) &value); + local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING, + key, value, 1 /* elsize */ ); + vec_free (key); + vec_free (value); + } + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + + serialize_close (sm); + +out: + if (fd > 0 && close (fd) < 0) + error = clib_error_return_unix (0, "close fd %d", fd); + + if (error) + { + clib_error_report (error); + return -1; + } + return 0; +} + +void +svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var) +{ + void *oldheap; + + region_lock (client->db_rp, 15); + oldheap = svm_push_data_heap (client->db_rp); + local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var); + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +void +svmdb_local_set_vec_variable (svmdb_client_t * client, + char *var, void *val_arg, u32 elsize) +{ + u8 *val = (u8 *) val_arg; + void *oldheap; + + region_lock (client->db_rp, 16); + oldheap = svm_push_data_heap (client->db_rp); + + local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var); + local_set_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var, + val, elsize); + + svm_pop_heap (oldheap); + region_unlock (client->db_rp); +} + +void * +svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize) +{ + u8 *rv = 0; + u8 *copy = 0; + + region_lock (client->db_rp, 17); + + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var); + + if (rv && vec_len (rv)) + { + /* Make a copy in process-local memory */ + vec_alloc (copy, vec_len (rv) * elsize); + clib_memcpy (copy, rv, vec_len (rv) * elsize); + _vec_len (copy) = vec_len (rv); + region_unlock (client->db_rp); + return (copy); + } + region_unlock (client->db_rp); + return (0); +} + +void +svmdb_local_dump_vecs (svmdb_client_t * client) +{ + uword *h; + u8 *key; + u32 value; + svmdb_shm_hdr_t *shm; + + region_lock (client->db_rp, 17); + shm = client->shm; + + h = client->shm->namespaces[SVMDB_NAMESPACE_VEC]; + + /* *INDENT-OFF* */ + hash_foreach_mem(key, value, h, + ({ + svmdb_value_t *v = pool_elt_at_index (shm->values, value); + (void) fformat(stdout, "%s:\n %U (%.2f)\n", key, + format_hex_bytes, v->value, + vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]); + })); + /* *INDENT-ON* */ + + region_unlock (client->db_rp); +} + +void * +svmdb_local_find_or_add_vec_variable (svmdb_client_t * client, + char *var, u32 nbytes) +{ + void *oldheap; + u8 *rv = 0; + + region_lock (client->db_rp, 18); + oldheap = svm_push_data_heap (client->db_rp); + + rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var); + + if (rv) + { + goto out; + } + else + { + uword *h; + u8 *name; + svmdb_shm_hdr_t *shm; + svmdb_value_t *newvalue; + + shm = client->shm; + h = shm->namespaces[SVMDB_NAMESPACE_VEC]; + + pool_get (shm->values, newvalue); + memset (newvalue, 0, sizeof (*newvalue)); + newvalue->elsize = 1; + vec_alloc (newvalue->value, nbytes); + _vec_len (newvalue->value) = nbytes; + name = format (0, "%s%c", var, 0); + hash_set_mem (h, name, newvalue - shm->values); + shm->namespaces[SVMDB_NAMESPACE_VEC] = h; + rv = newvalue->value; + } + +out: + svm_pop_heap (oldheap); + region_unlock (client->db_rp); + return (rv); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdb.h b/src/svm/svmdb.h new file mode 100644 index 00000000000..e02628a0bb9 --- /dev/null +++ b/src/svm/svmdb.h @@ -0,0 +1,135 @@ +/* + *------------------------------------------------------------------ + * svmdb.h - shared VM database + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef __included_svmdb_h__ +#define __included_svmdb_h__ + +#include "svm.h" + +typedef enum +{ + SVMDB_ACTION_ILLEGAL = 0, + SVMDB_ACTION_GET, /* not clear why anyone would care */ + SVMDB_ACTION_SET, + SVMDB_ACTION_UNSET, +} svmdb_action_t; + +typedef struct +{ + int pid; + int signum; + u32 action:4; + u32 opaque:28; +} svmdb_notify_t; + +typedef struct +{ + u8 *value; + svmdb_notify_t *notifications; + u32 elsize; +} svmdb_value_t; + +typedef enum +{ + SVMDB_NAMESPACE_STRING = 0, + SVMDB_NAMESPACE_VEC, + SVMDB_N_NAMESPACES, +} svmdb_namespace_t; + +typedef struct +{ + uword version; + /* pool of values */ + svmdb_value_t *values; + uword *namespaces[SVMDB_N_NAMESPACES]; +} svmdb_shm_hdr_t; + +#define SVMDB_SHM_VERSION 2 + +typedef struct +{ + int flags; + int pid; + svm_region_t *db_rp; + svmdb_shm_hdr_t *shm; +} svmdb_client_t; + +typedef struct +{ + int add_del; + svmdb_namespace_t nspace; + char *var; + u32 elsize; + int signum; + u32 action:4; + u32 opaque:28; +} svmdb_notification_args_t; + +typedef struct +{ + char *root_path; + uword size; + u32 uid; + u32 gid; +} svmdb_map_args_t; + +/* + * Must be a reasonable number, several mb smaller than + * SVM_GLOBAL_REGION_SIZE, or no donut for you... + */ +#define SVMDB_DEFAULT_SIZE (4<<20) + +svmdb_client_t *svmdb_map (svmdb_map_args_t *); + +void svmdb_unmap (svmdb_client_t * client); +void svmdb_local_unset_string_variable (svmdb_client_t * client, char *var); +void svmdb_local_set_string_variable (svmdb_client_t * client, + char *var, char *val); +char *svmdb_local_get_string_variable (svmdb_client_t * client, char *var); +void *svmdb_local_get_variable_reference (svmdb_client_t * client, + svmdb_namespace_t ns, char *var); + +void svmdb_local_dump_strings (svmdb_client_t * client); + +void svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var); +void svmdb_local_set_vec_variable (svmdb_client_t * client, + char *var, void *val, u32 elsize); +void *svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, + u32 elsize); +void svmdb_local_dump_vecs (svmdb_client_t * client); + +int svmdb_local_add_del_notification (svmdb_client_t * client, + svmdb_notification_args_t * args); + +void *svmdb_local_find_or_add_vec_variable (svmdb_client_t * client, + char *var, u32 nbytes); + +int svmdb_local_serialize_strings (svmdb_client_t * client, char *filename); +int svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename); + + +#endif /* __included_svmdb_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmdbtool.c b/src/svm/svmdbtool.c new file mode 100644 index 00000000000..a0af15fcbbf --- /dev/null +++ b/src/svm/svmdbtool.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "svmdb.h" + +typedef struct +{ + svmdb_map_args_t map_args; + int uid, gid; + uword size; +} svmdbtool_main_t; + +svmdbtool_main_t svmdbtool_main; + +static inline svmdb_map_args_t * +map_arg_setup (char *chroot_path) +{ + svmdbtool_main_t *sm = &svmdbtool_main; + svmdb_map_args_t *ma = &sm->map_args; + + memset (ma, 0, sizeof (*ma)); + ma->root_path = chroot_path; + ma->size = sm->size; + ma->uid = sm->uid; + ma->gid = sm->gid; + return ma; +} + +static void +get_string (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + char *rv; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + rv = svmdb_local_get_string_variable (c, (char *) vbl); + + fformat (stdout, "%s\n", rv ? rv : "UNSET"); + vec_free (rv); + svmdb_unmap (c); +} + +static void +set_string (char *chroot_path, u8 * vbl, u8 * value) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_set_string_variable (c, (char *) vbl, (char *) value); + svmdb_unmap (c); +} + +static void +unset_string (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_unset_string_variable (c, (char *) vbl); + svmdb_unmap (c); +} + +static void +dump_strings (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + svmdb_local_dump_strings (c); + svmdb_unmap (c); +} + +static void +serialize_strings (char *chroot_path, char *filename) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + (void) svmdb_local_serialize_strings (c, filename); + svmdb_unmap (c); +} + +static void +unserialize_strings (char *chroot_path, char *filename) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + (void) svmdb_local_unserialize_strings (c, filename); + svmdb_unmap (c); +} + +static void +test_vlib_vec_rate (char *chroot_path, f64 vr) +{ + svmdb_client_t *c; + f64 *tv = 0; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + vec_add1 (tv, vr); + + svmdb_local_set_vec_variable (c, "vlib_vector_rate", (char *) tv, + sizeof (*tv)); + svmdb_unmap (c); + + vec_free (tv); +} + + + +static void +test_vec (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + u64 *tv = 0; + int i; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + /* my amp goes to 11 */ + for (i = 0; i < 11; i++) + { + vec_add1 (tv, i); + } + + svmdb_local_set_vec_variable (c, (char *) vbl, (char *) tv, sizeof (tv[0])); + svmdb_unmap (c); + + vec_free (tv); +} + +static void +fake_install (char *chroot_path, u8 * add_value) +{ + svmdb_client_t *c; + u8 *v = 0; + u8 **values = 0; + u8 *oldvalue; + u8 *value; + int nitems = 0, i; + serialize_main_t m; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + oldvalue = svmdb_local_get_vec_variable (c, "installed_sw", 1); + if (oldvalue) + { + unserialize_open_data (&m, oldvalue, vec_len (oldvalue)); + nitems = unserialize_likely_small_unsigned_integer (&m); + for (i = 0; i < nitems; i++) + { + unserialize_cstring (&m, (char **) &value); + vec_add1 (values, value); + } + vec_free (v); + } + nitems++; + value = format (0, "%s%c", add_value, 0); + + vec_add1 (values, value); + + fformat (stdout, "Resulting installed_sw vector:\n"); + + serialize_open_vector (&m, v); + serialize_likely_small_unsigned_integer (&m, vec_len (values)); + for (i = 0; i < vec_len (values); i++) + { + fformat (stdout, "%s\n", values[i]); + serialize_cstring (&m, (char *) values[i]); + } + + v = serialize_close_vector (&m); + + svmdb_local_set_vec_variable (c, "installed_sw", v, sizeof (v[0])); + svmdb_unmap (c); + + for (i = 0; i < vec_len (values); i++) + vec_free (values[i]); + vec_free (values); +} + +static void +sigaction_handler (int signum, siginfo_t * i, void *notused) +{ + u32 action, opaque; + + action = (u32) (uword) i->si_ptr; + action >>= 28; + opaque = (u32) (uword) i->si_ptr; + opaque &= ~(0xF0000000); + + clib_warning ("signal %d, action %d, opaque %x", signum, action, opaque); +} + +static void +test_reg (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_notification_args_t args; + svmdb_notification_args_t *a = &args; + struct sigaction sa; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + memset (&sa, 0, sizeof (sa)); + sa.sa_sigaction = sigaction_handler; + sa.sa_flags = SA_SIGINFO; + if (sigaction (SIGUSR2, &sa, 0) < 0) + { + clib_unix_warning ("sigaction"); + return; + } + + memset (a, 0, sizeof (*a)); + + c = svmdb_map (ma); + + a->add_del = 1 /* add */ ; + a->nspace = SVMDB_NAMESPACE_STRING; + a->var = (char *) vbl; + a->elsize = 1; + a->signum = SIGUSR2; + a->action = SVMDB_ACTION_GET; + a->opaque = 0x0eadbeef; + + svmdb_local_add_del_notification (c, a); + + (void) svmdb_local_get_string_variable (c, (char *) vbl); + + a->add_del = 0; /* del */ + svmdb_local_add_del_notification (c, a); + + + + svmdb_unmap (c); +} + +static void +unset_vec (char *chroot_path, u8 * vbl) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_local_unset_vec_variable (c, (char *) vbl); + svmdb_unmap (c); +} + +static void +dump_vecs (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_local_dump_vecs (c); + svmdb_unmap (c); +} + +static void +crash_test (char *chroot_path) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + clib_warning ("Grab region mutex and crash deliberately!"); + c->db_rp->mutex_owner_pid = getpid (); + c->db_rp->mutex_owner_tag = -13; + pthread_mutex_lock (&c->db_rp->mutex); + + abort (); +} + +static void +map_with_size (char *chroot_path, uword size) +{ + svmdb_client_t *c; + svmdb_map_args_t *ma; + + svmdbtool_main.size = size; + ma = map_arg_setup (chroot_path); + + c = svmdb_map (ma); + + svmdb_unmap (c); +} + +int +main (int argc, char **argv) +{ + unformat_input_t input; + int parsed = 0; + u8 *vbl = 0, *value = 0; + char *chroot_path = 0; + u8 *chroot_path_u8; + u8 *filename; + uword size; + f64 vr; + int uid, gid, rv; + struct passwd _pw, *pw; + struct group _grp, *grp; + char *s, buf[128]; + + svmdbtool_main.uid = geteuid (); + svmdbtool_main.gid = getegid (); + + unformat_init_command_line (&input, argv); + + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&input, "get-string %s", &vbl)) + { + get_string (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "set-string %s %s", &vbl, &value)) + { + set_string (chroot_path, vbl, value); + vec_free (vbl); + vec_free (value); + parsed++; + } + else if (unformat (&input, "unset-string %s", &vbl)) + { + unset_string (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "dump-strings")) + { + dump_strings (chroot_path); + parsed++; + } + else if (unformat (&input, "unset-vec %s", &vbl)) + { + unset_vec (chroot_path, vbl); + vec_free (vbl); + parsed++; + } + else if (unformat (&input, "dump-vecs")) + { + dump_vecs (chroot_path); + parsed++; + } + else if (unformat (&input, "test-vec %s", &vbl)) + { + test_vec (chroot_path, vbl); + // vec_free(vbl); + parsed++; + } + else if (unformat (&input, "vlib-vec-rate %f", &vr)) + { + test_vlib_vec_rate (chroot_path, vr); + parsed++; + } + else if (unformat (&input, "test-reg %s", &vbl)) + { + test_reg (chroot_path, vbl); + parsed++; + } + else if (unformat (&input, "crash-test")) + { + crash_test (chroot_path); + } + else if (unformat (&input, "chroot %s", &chroot_path_u8)) + { + chroot_path = (char *) chroot_path_u8; + } + else if (unformat (&input, "fake-install %s", &value)) + { + fake_install (chroot_path, value); + parsed++; + } + else if (unformat (&input, "size %d", &size)) + { + map_with_size (chroot_path, size); + parsed++; + } + else if (unformat (&input, "uid %d", &uid)) + svmdbtool_main.uid = uid; + else if (unformat (&input, "gid %d", &gid)) + svmdbtool_main.gid = gid; + else if (unformat (&input, "uid %s", &s)) + { + /* lookup the username */ + pw = NULL; + rv = getpwnam_r (s, &_pw, buf, sizeof (buf), &pw); + if (rv < 0) + { + fformat (stderr, "cannot fetch username %s", s); + exit (1); + } + if (pw == NULL) + { + fformat (stderr, "username %s does not exist", s); + exit (1); + } + vec_free (s); + svmdbtool_main.uid = pw->pw_uid; + } + else if (unformat (&input, "gid %s", &s)) + { + /* lookup the group name */ + grp = NULL; + rv = getgrnam_r (s, &_grp, buf, sizeof (buf), &grp); + if (rv != 0) + { + fformat (stderr, "cannot fetch group %s", s); + exit (1); + } + if (grp == NULL) + { + fformat (stderr, "group %s does not exist", s); + exit (1); + } + vec_free (s); + svmdbtool_main.gid = grp->gr_gid; + } + else if (unformat (&input, "serialize-strings %s", &filename)) + { + vec_add1 (filename, 0); + serialize_strings (chroot_path, (char *) filename); + parsed++; + } + else if (unformat (&input, "unserialize-strings %s", &filename)) + { + vec_add1 (filename, 0); + unserialize_strings (chroot_path, (char *) filename); + parsed++; + } + else + { + break; + } + } + + unformat_free (&input); + + if (!parsed) + { + fformat (stdout, "%s: get-string | set-string \n", + argv[0]); + fformat (stdout, " unset-string | dump-strings\n"); + fformat (stdout, " test-vec |\n"); + fformat (stdout, " unset-vec | dump-vecs\n"); + fformat (stdout, " chroot [uid ]\n"); + fformat (stdout, " [gid ]\n"); + } + + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/svm/svmtool.c b/src/svm/svmtool.c new file mode 100644 index 00000000000..b319551425c --- /dev/null +++ b/src/svm/svmtool.c @@ -0,0 +1,528 @@ +/* + *------------------------------------------------------------------ + * svmtool.c + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "svm.h" + + + +/* + * format_all_svm_regions + * Maps / unmaps regions. Do NOT call from client code! + */ +u8 * +format_all_svm_regions (u8 * s, va_list * args) +{ + int verbose = va_arg (*args, int); + svm_region_t *root_rp = svm_get_root_rp (); + svm_main_region_t *mp; + svm_subregion_t *subp; + svm_region_t *rp; + svm_map_region_args_t *a = 0; + u8 **svm_names = 0; + u8 *name = 0; + int i; + + ASSERT (root_rp); + + pthread_mutex_lock (&root_rp->mutex); + + s = format (s, "%U", format_svm_region, root_rp, verbose); + + mp = root_rp->data_base; + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + vec_validate (a, 0); + a->name = (char *) svm_names[i]; + rp = svm_region_find_or_create (a); + if (rp) + { + pthread_mutex_lock (&rp->mutex); + s = format (s, "%U", format_svm_region, rp, verbose); + pthread_mutex_unlock (&rp->mutex); + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + vec_free (a); + } + vec_free (svm_names); + return (s); +} + +void +show (char *chroot_path, int verbose) +{ + svm_map_region_args_t *a = 0; + + vec_validate (a, 0); + + svm_region_init_chroot (chroot_path); + + fformat (stdout, "My pid is %d\n", getpid ()); + + fformat (stdout, "%U", format_all_svm_regions, verbose); + + svm_region_exit (); + + vec_free (a); +} + + +static void * +svm_map_region_nolock (svm_map_region_args_t * a) +{ + int svm_fd; + svm_region_t *rp; + int deadman = 0; + u8 *shm_name; + + ASSERT ((a->size & ~(MMAP_PAGESIZE - 1)) == a->size); + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + return (0); + } + vec_free (shm_name); + + rp = mmap (0, MMAP_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + return (0); + } + /* + * We lost the footrace to create this region; make sure + * the winner has crossed the finish line. + */ + while (rp->version == 0 && deadman++ < 5) + { + sleep (1); + } + + /* + * -ed? + */ + if (rp->version == 0) + { + clib_warning ("rp->version %d not %d", rp->version, SVM_VERSION); + munmap (rp, MMAP_PAGESIZE); + return (0); + } + /* Remap now that the region has been placed */ + a->baseva = rp->virtual_base; + a->size = rp->virtual_size; + munmap (rp, MMAP_PAGESIZE); + + rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + return (0); + } + + if ((uword) rp != rp->virtual_base) + { + clib_warning ("mmap botch"); + } + + if (pthread_mutex_trylock (&rp->mutex)) + { + clib_warning ("rp->mutex LOCKED by pid %d, tag %d, cleared...", + rp->mutex_owner_pid, rp->mutex_owner_tag); + memset (&rp->mutex, 0, sizeof (rp->mutex)); + + } + else + { + clib_warning ("mutex OK...\n"); + pthread_mutex_unlock (&rp->mutex); + } + + return ((void *) rp); +} + +/* + * rnd_pagesize + * Round to a pagesize multiple, presumably 4k works + */ +static u64 +rnd_pagesize (u64 size) +{ + u64 rv; + + rv = (size + (MMAP_PAGESIZE - 1)) & ~(MMAP_PAGESIZE - 1); + return (rv); +} + +#define MUTEX_DEBUG + +always_inline void +region_lock (svm_region_t * rp, int tag) +{ + pthread_mutex_lock (&rp->mutex); +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = getpid (); + rp->mutex_owner_tag = tag; +#endif +} + +always_inline void +region_unlock (svm_region_t * rp) +{ +#ifdef MUTEX_DEBUG + rp->mutex_owner_pid = 0; + rp->mutex_owner_tag = 0; +#endif + pthread_mutex_unlock (&rp->mutex); +} + + +static void * +svm_existing_region_map_nolock (void *root_arg, svm_map_region_args_t * a) +{ + svm_region_t *root_rp = root_arg; + svm_main_region_t *mp; + svm_region_t *rp; + void *oldheap; + uword *p; + + a->size += MMAP_PAGESIZE + + (a->pvt_heap_size ? a->pvt_heap_size : SVM_PVT_MHEAP_SIZE); + a->size = rnd_pagesize (a->size); + + region_lock (root_rp, 4); + oldheap = svm_push_pvt_heap (root_rp); + mp = root_rp->data_base; + + ASSERT (mp); + + p = hash_get_mem (mp->name_hash, a->name); + + if (p) + { + rp = svm_map_region_nolock (a); + region_unlock (root_rp); + svm_pop_heap (oldheap); + return rp; + } + return 0; + +} + +static void +trace (char *chroot_path, char *name, int enable_disable) +{ + svm_map_region_args_t *a = 0; + svm_region_t *db_rp; + void *oldheap; + + vec_validate (a, 0); + + svm_region_init_chroot (chroot_path); + + a->name = name; + a->size = 1 << 20; + a->flags = SVM_FLAGS_MHEAP; + + db_rp = svm_region_find_or_create (a); + + ASSERT (db_rp); + + region_lock (db_rp, 20); + + oldheap = svm_push_data_heap (db_rp); + + mheap_trace (db_rp->data_heap, enable_disable); + + svm_pop_heap (oldheap); + region_unlock (db_rp); + + svm_region_unmap ((void *) db_rp); + svm_region_exit (); + vec_free (a); +} + + + +static void +subregion_repair (char *chroot_path) +{ + int i; + svm_main_region_t *mp; + svm_map_region_args_t a; + svm_region_t *root_rp; + svm_region_t *rp; + svm_subregion_t *subp; + u8 *name = 0; + u8 **svm_names = 0; + + svm_region_init_chroot (chroot_path); + root_rp = svm_get_root_rp (); + + pthread_mutex_lock (&root_rp->mutex); + + mp = root_rp->data_base; + + /* + * Snapshoot names, can't hold root rp mutex across + * find_or_create. + */ + /* *INDENT-OFF* */ + pool_foreach (subp, mp->subregions, ({ + name = vec_dup (subp->subregion_name); + vec_add1(svm_names, name); + })); + /* *INDENT-ON* */ + + pthread_mutex_unlock (&root_rp->mutex); + + for (i = 0; i < vec_len (svm_names); i++) + { + memset (&a, 0, sizeof (a)); + a.root_path = chroot_path; + a.name = (char *) svm_names[i]; + fformat (stdout, "Checking %s region...\n", a.name); + rp = svm_existing_region_map_nolock (root_rp, &a); + if (rp) + { + svm_region_unmap (rp); + vec_free (svm_names[i]); + } + } + vec_free (svm_names); +} + +void +repair (char *chroot_path, int crash_root_region) +{ + svm_region_t *root_rp = 0; + svm_map_region_args_t *a = 0; + void *svm_map_region (svm_map_region_args_t * a); + int svm_fd; + u8 *shm_name; + + fformat (stdout, "our pid: %d\n", getpid ()); + + vec_validate (a, 0); + + a->root_path = chroot_path; + a->name = SVM_GLOBAL_REGION_NAME; + a->baseva = SVM_GLOBAL_REGION_BASEVA; + a->size = SVM_GLOBAL_REGION_SIZE; + a->flags = SVM_FLAGS_NODATA; + + shm_name = shm_name_from_svm_map_region_args (a); + + svm_fd = shm_open ((char *) shm_name, O_RDWR, 0777); + + if (svm_fd < 0) + { + perror ("svm_region_map(mmap open)"); + goto out; + } + + vec_free (shm_name); + + root_rp = mmap (0, MMAP_PAGESIZE, + PROT_READ | PROT_WRITE, MAP_SHARED, svm_fd, 0); + + if (root_rp == (svm_region_t *) MAP_FAILED) + { + close (svm_fd); + clib_warning ("mmap"); + goto out; + } + + /* Remap now that the region has been placed */ + clib_warning ("remap to 0x%x", root_rp->virtual_base); + + a->baseva = root_rp->virtual_base; + a->size = root_rp->virtual_size; + munmap (root_rp, MMAP_PAGESIZE); + + root_rp = (void *) mmap ((void *) a->baseva, a->size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, svm_fd, 0); + if ((uword) root_rp == (uword) MAP_FAILED) + { + clib_unix_warning ("mmap"); + goto out; + } + + close (svm_fd); + + if ((uword) root_rp != root_rp->virtual_base) + { + clib_warning ("mmap botch"); + goto out; + } + + if (pthread_mutex_trylock (&root_rp->mutex)) + { + clib_warning ("root_rp->mutex LOCKED by pid %d, tag %d, cleared...", + root_rp->mutex_owner_pid, root_rp->mutex_owner_tag); + memset (&root_rp->mutex, 0, sizeof (root_rp->mutex)); + goto out; + } + else + { + clib_warning ("root_rp->mutex OK...\n"); + pthread_mutex_unlock (&root_rp->mutex); + } + +out: + vec_free (a); + /* + * Now that the root region is known to be OK, + * fix broken subregions + */ + subregion_repair (chroot_path); + + if (crash_root_region) + { + clib_warning ("Leaving root region locked on purpose..."); + pthread_mutex_lock (&root_rp->mutex); + root_rp->mutex_owner_pid = getpid (); + root_rp->mutex_owner_tag = 99; + } + svm_region_exit (); +} + +int +main (int argc, char **argv) +{ + unformat_input_t input; + int parsed = 0; + char *name; + char *chroot_path = 0; + u8 *chroot_u8; + + unformat_init_command_line (&input, argv); + + while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&input, "show-verbose")) + { + show (chroot_path, 1); + parsed++; + } + else if (unformat (&input, "show")) + { + show (chroot_path, 0); + parsed++; + } + else if (unformat (&input, "client-scan")) + { + svm_client_scan (chroot_path); + parsed++; + } + else if (unformat (&input, "repair")) + { + repair (chroot_path, 0 /* fix it */ ); + parsed++; + } + else if (unformat (&input, "crash")) + { + repair (chroot_path, 1 /* crash it */ ); + parsed++; + } + else if (unformat (&input, "trace-on %s", &name)) + { + trace (chroot_path, name, 1); + parsed++; + } + else if (unformat (&input, "trace-off %s", &name)) + { + trace (chroot_path, name, 0); + parsed++; + } + else if (unformat (&input, "chroot %s", &chroot_u8)) + { + chroot_path = (char *) chroot_u8; + } + else + { + break; + } + } + + unformat_free (&input); + + if (!parsed) + { + fformat (stdout, + "%s: show | show-verbose | client-scan | trace-on \n", + argv[0]); + fformat (stdout, " trace-off \n"); + } + exit (0); +} + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/tests/vnet/README b/src/tests/vnet/README new file mode 100644 index 00000000000..10579e50e33 --- /dev/null +++ b/src/tests/vnet/README @@ -0,0 +1,10 @@ +Unit test infrastructure for vnet + +To run unit tests do the following: + + 1. build vpp with 'vpp_enable_tests = yes' in build-data/platforms/vpp.mk + + 2. go to build-root/build-$tag-$arch/vnet + + 3. run + $ make check diff --git a/src/tests/vnet/lisp-cp/test_cp_serdes.c b/src/tests/vnet/lisp-cp/test_cp_serdes.c new file mode 100644 index 00000000000..9d51dc8fa51 --- /dev/null +++ b/src/tests/vnet/lisp-cp/test_cp_serdes.c @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* FIXME */ +#include +vpe_api_main_t vpe_api_main; + +#define _assert(e) \ + error = CLIB_ERROR_ASSERT (e); \ + if (error) \ + goto done; + +static void print_chunk(u8 * b, int * offset, int c, char * des) +{ + int i, n = offset[0] + c;; + for (i = offset[0]; i < n; i++) + { + printf("0x%02x, ", b[i]); + } + printf(" // %s\n", des); + *offset += c; +} + +void print_map_request(map_request_hdr_t * h) +{ +#define pchunk(_count, _desc) \ + print_chunk((u8 *)h, &offset, _count, _desc) + + int offset = 0; + + pchunk(4, "data"); + pchunk(8, "Nonce"); + pchunk(2, "Source-EID-AFI"); + pchunk(4, "Source EID Address"); + pchunk(2, "ITR-RLOC-AFI 1"); + pchunk(4, "ITR-RLOC Address 1"); + pchunk(2, "ITR-RLOC-AFI 2"); + pchunk(16, "ITR-RLOC Address 2"); + pchunk(1, "REC: reserved"); + pchunk(1, "REC: EID mask-len"); + pchunk(2, "REC: EID-prefix-AFI"); + pchunk(4, "REC: EID-prefix"); + printf("\n"); +} + +static clib_error_t * test_lisp_msg_push_ecm () +{ + vlib_main_t * vm = vlib_get_main (); + clib_error_t * error = 0; + gid_address_t la, ra; + vlib_buffer_t * b = 0; + u32 buff_len = 900; + int lp = 0x15, rp = 0x14; + + b = clib_mem_alloc (buff_len); + memset((u8 *)b, 0, buff_len); + b->current_length = buff_len; + b->current_data = sizeof(udp_header_t) + sizeof(ip4_header_t) + + sizeof(ecm_hdr_t) + 1; + + la.type = GID_ADDR_IP_PREFIX; + la.ippref.addr.ip.v4.as_u32 = 0xa1b2c3d4; + la.ippref.addr.version = IP4; + + ra.type = GID_ADDR_IP_PREFIX; + ra.ippref.addr.ip.v4.as_u32 = 0x90817263; + ra.ippref.addr.version = IP4; + + ecm_hdr_t * lh = lisp_msg_push_ecm (vm, b, lp, rp, &la, &ra); + + u8 expected_ecm_hdr[] = { + 0x80, 0x00, 0x00, 0x00 + }; + _assert(0 == memcmp(expected_ecm_hdr, lh, sizeof(expected_ecm_hdr))); + + ip4_header_t * ih = (ip4_header_t *) (lh + 1); + /* clear ip checksum */ + memset((u8 *)ih + 10, 0, 2); + + u8 expected_ip4_hdr[] = { + 0x45, /* version; IHL */ + 0x00, /* services */ + 0x03, 0xa0, /* total length */ + 0x00, 0x00, /* identification */ + 0x40, 0x00, /* flags; fragment offset*/ + 0xff, /* TTL */ + 0x11, /* protocol */ + 0x00, 0x00, /* header checksum */ + 0xd4, 0xc3, 0xb2, 0xa1, /* src IP */ + 0x63, 0x72, 0x81, 0x90, /* dst IP */ + }; + _assert(0 == memcmp(ih, expected_ip4_hdr, sizeof(expected_ip4_hdr))); + + udp_header_t * uh = (udp_header_t *) (ih + 1); + /* clear udp checksum */ + memset((u8 *)uh + 6, 0, 2); + + u8 expected_udp_hdr[] = { + 0x00, 0x15, /* src port */ + 0x00, 0x14, /* dst port */ + 0x03, 0x8c, /* length */ + 0x00, 0x00, /* checksum */ + }; + _assert(0 == memcmp(uh, expected_udp_hdr, sizeof(expected_udp_hdr))); + +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * test_lisp_msg_parse_mapping_record () +{ + clib_error_t * error = 0; + locator_t probed; + locator_t * locs = 0; + vlib_buffer_t * b = 0; + gid_address_t eid; + u32 buff_len = 500; + + b = clib_mem_alloc (buff_len); + memset((u8 *)b, 0, buff_len); + + u8 map_reply_records[] = { + /* 1. record */ + 0x01, 0x02, 0x03, 0x04, /* record TTL */ + 0x01, /* locator count */ + 0x00, 0x00, 0x00, /* eid-mask-len; ... */ + 0x00, 0x00, /* reserved; map-version num */ + 0x00, 0x01, /* EID-Prefix-AFI */ + 0x33, 0x44, 0x55, 0x66, /* eid-prefix */ + /* loc */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x00, 0x01, /* Loc-AFI */ + 0xaa, 0xbb, 0xcc, 0xdd, /* Loator */ + }; + b->current_length = buff_len; + clib_memcpy(b->data, map_reply_records, sizeof(map_reply_records)); + + lisp_msg_parse_mapping_record (b, &eid, &locs, &probed); + _assert(vec_len (locs) == 1); + _assert(eid.ippref.addr.ip.v4.as_u32 == 0x66554433); + _assert(locs[0].local == 0); + _assert(locs[0].address.ippref.addr.ip.v4.as_u32 == 0xddccbbaa); + _assert(locs[0].address.type == GID_ADDR_IP_PREFIX); + _assert(locs[0].priority == 0xa); + _assert(locs[0].weight == 0xb); + _assert(locs[0].mpriority == 0xc); + _assert(locs[0].mweight == 0xd); + +done: + clib_mem_free (b); + if (locs) + vec_free (locs); + return error; +} + +static map_request_hdr_t * +build_map_request (lisp_cp_main_t * lcm, vlib_buffer_t * b, + gid_address_t * rlocs) +{ + gid_address_t _seid, * seid = &_seid; + gid_address_t _deid, * deid = &_deid; + u8 is_smr_invoked = 1; + u8 rloc_probe_set = 0; + u64 nonce = 0; + map_request_hdr_t * h = 0; + memset (deid, 0, sizeof (deid[0])); + memset (seid, 0, sizeof (seid[0])); + + gid_address_type (seid) = GID_ADDR_IP_PREFIX; + ip_address_t * ip_addr = &gid_address_ip (seid); + ip_addr_v4 (ip_addr).as_u32 = 0x12345678; + seid->ippref.addr.version = IP4; + + gid_address_type (deid) = GID_ADDR_IP_PREFIX; + ip_address_t * ip_addr2 = &gid_address_ip (deid); + ip_addr_v4 (ip_addr2).as_u32 = 0x9abcdef0; + deid->ippref.addr.version = IP4; + gid_address_ippref_len (deid) = 24; + + h = lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, + is_smr_invoked, rloc_probe_set, &nonce); + vec_free(rlocs); + return h; +} + +static void +generate_rlocs (gid_address_t **rlocs, u32 * count) +{ + gid_address_t gid_addr_data, * gid_addr = &gid_addr_data; + memset (gid_addr, 0, sizeof (gid_addr[0])); + ip_address_t * addr = &gid_address_ip (gid_addr); + + gid_address_type (gid_addr) = GID_ADDR_IP_PREFIX; + + ip_addr_version (addr) = IP4; + ip_addr_v4 (addr).data_u32 = 0x10203040; + vec_add1 (rlocs[0], gid_addr[0]); + + ip_addr_v6 (addr).as_u32[0] = 0xffeeddcc; + ip_addr_v6 (addr).as_u32[1] = 0xbbaa9988; + ip_addr_v6 (addr).as_u32[2] = 0x77665544; + ip_addr_v6 (addr).as_u32[3] = 0x33221100; + ip_addr_version (addr) = IP6; + vec_add1 (rlocs[0], gid_addr[0]); +} + +static clib_error_t * test_lisp_msg_parse () +{ + gid_address_t eid; + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + map_request_hdr_t *h; + gid_address_t gid; + clib_error_t * error = 0; + vlib_buffer_t * b; + gid_address_t * rlocs_decode = 0, * rlocs = 0; + u32 rloc_count_parse = 0; + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + b = (vlib_buffer_t *) data; + + generate_rlocs (&rlocs_decode, &rloc_count_parse); + h = build_map_request (lcm, b, rlocs_decode); + + vlib_buffer_pull(b, sizeof(*h)); + u32 len = lisp_msg_parse_addr(b, &gid); + _assert (len == 2 + 4 + /* Source-EID-AFI field lenght + IPv4 address length */); + _assert (gid.ippref.addr.ip.v4.as_u32 == 0x12345678); + _assert (gid.ippref.addr.version == IP4); + + u8 rloc_count = MREQ_ITR_RLOC_COUNT(h) + 1; + lisp_msg_parse_itr_rlocs (b, &rlocs, rloc_count); + + _assert (vec_len (rlocs) == 2); + _assert (rlocs[0].ippref.addr.ip.v4.as_u32 == 0x10203040); + _assert (rlocs[0].ippref.addr.version == IP4); + + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[0] == 0xffeeddcc); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[1] == 0xbbaa9988); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[2] == 0x77665544); + _assert (rlocs[1].ippref.addr.ip.v6.as_u32[3] == 0x33221100); + _assert (rlocs[1].ippref.addr.version == IP6); + + lisp_msg_parse_eid_rec (b, &eid); + _assert (eid.ippref.addr.ip.v4.as_u32 == 0x9abcdef0); + _assert (eid.ippref.addr.version == IP4); + _assert (eid.ippref.len == 24); + +done: + clib_mem_free (data); + if (rlocs) + vec_free (rlocs); + return error; +} + +static clib_error_t * test_lisp_msg_put_mreq_with_lcaf () +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main (); + clib_error_t * error = 0; + map_request_hdr_t *h = 0; + gid_address_t * rlocs = 0; + + ip_prefix_t ippref; + ip_prefix_version (&ippref) = IP4; + ip4_address_t * ip = &ip_prefix_v4 (&ippref); + ip->as_u32 = 0x11223344; + + gid_address_t g = + { + .type = GID_ADDR_IP_PREFIX, + .ippref = ippref, + .vni = 0x90919293, + .vni_mask = 0x17 + }; + vec_add1 (rlocs, g); + + u8 * data = clib_mem_alloc (500); + memset (data, 0, 500); + + h = build_map_request (lcm, (vlib_buffer_t *) data, rlocs); + + /* clear Nonce to simplify comparison */ + memset ((u8 *)h + 4, 0, 8); + + u8 expected_data[] = + { + 0x10, 0x40, 0x00, 0x01, /* type; flags; IRC; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x01, /* Source-EID-AFI */ + 0x78, 0x56, 0x34, 0x12, /* Source EID Address */ + + /* RLOCs */ + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x17, /* IID mask-len */ + 0x00, 0x0a, /* lenght */ + 0x90, 0x91, 0x92, 0x93, /* IID / VNI */ + + 0x00, 0x01, /* AFI = ipv4 */ + 0x44, 0x33, 0x22, 0x11, /* ITR-RLOC Address 1 */ + + /* record */ + 0x00, /* reserved */ + 0x18, /* EID mask-len */ + 0x00, 0x01, /* EID-prefix-AFI */ + 0xf0, 0xde, 0xbc, 0x9a, /* EID-prefix */ + }; + + _assert (0 == memcmp (expected_data, (u8 *) h, sizeof (expected_data))); +done: + clib_mem_free (data); + return error; +} + +static clib_error_t * test_lisp_msg_put_mreq () +{ + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main(); + clib_error_t * error = 0; + map_request_hdr_t *h; + gid_address_t * rlocs = 0; + u32 rloc_count = 0; + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + + generate_rlocs (&rlocs, &rloc_count); + h = build_map_request (lcm, (vlib_buffer_t *) data, rlocs); + + /* clear Nonce to simplify comparison */ + memset((u8 *)h + 4, 0, 8); + + print_map_request(h); + + u8 expected_data[50] = { + 0x10, 0x40, 0x01, 0x01, /* type; flags; IRC; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x01, /* Source-EID-AFI */ + 0x78, 0x56, 0x34, 0x12, /* Source EID Address */ + + /* RLOCs */ + 0x00, 0x01, /* ITR-RLOC-AFI 1 */ + 0x40, 0x30, 0x20, 0x10, /* ITR-RLOC Address 1 */ + 0x00, 0x02, /* ITR-RLOC-AFI 2 */ + 0xcc, 0xdd, 0xee, 0xff, + 0x88, 0x99, 0xaa, 0xbb, + 0x44, 0x55, 0x66, 0x77, + 0x00, 0x11, 0x22, 0x33, /* ITR-RLOC Address 2 */ + + /* record */ + 0x00, /* reserved */ + 0x18, /* EID mask-len */ + 0x00, 0x01, /* EID-prefix-AFI */ + 0xf0, 0xde, 0xbc, 0x9a, /* EID-prefix */ + }; + _assert (0 == memcmp (expected_data, (u8 *) h, sizeof (expected_data))); + +done: + clib_mem_free (data); + return error; +} + +/* generate a vector of eid records */ +static mapping_t * +build_test_map_records () +{ + mapping_t * records = 0; + + mapping_t r = { + .ttl = 0x44332211, + .eid = { + .type = GID_ADDR_MAC, + .mac = {1, 2, 3, 4, 5, 6}, + .vni = 0x0 + } + }; + + locator_t loc = { + .weight = 1, + .priority = 2, + .local = 1, + .address = { + .type = GID_ADDR_IP_PREFIX, + .ippref = { + .addr = { + .ip.v4.as_u32 = 0x99887766, + .version = IP4 + } + } + } + }; + vec_add1 (r.locators, loc); + vec_add1 (records, r); + + return records; +} + +static void +free_test_map_records (mapping_t * maps) +{ + mapping_t * map; + vec_foreach (map, maps) + { + vec_free (map->locators); + } + vec_free (maps); +} + +static clib_error_t * +test_lisp_map_register () +{ + vlib_buffer_t *b; + clib_error_t * error = 0; + u64 nonce; + u32 msg_len = 0; + mapping_t * records = build_test_map_records (); + + u8 * data = clib_mem_alloc(500); + memset(data, 0, 500); + b = (vlib_buffer_t *) data; + + lisp_msg_put_map_register (b, records, 1 /* want map notify */, + 20 /* length of HMAC_SHA_1_96 */, + &nonce, &msg_len); + free_test_map_records (records); + + /* clear Nonce to simplify comparison */ + memset((u8 *)b->data + 4, 0, 8); + + /* clear authentication data */ + memset ((u8 *)b->data + 16, 0, 20); + + u8 expected_data[] = { + 0x30, 0x00, 0x01, 0x01, /* type; rsvd; want notify; REC count */ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* nonce */ + 0x00, 0x00, 0x00, 0x00, /* key id, auth data length: + both are zeroes because those are set in another + function (see auth_data_len_by_key_id())*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /* auth data */ + + /* first record */ + 0x44, 0x33, 0x22, 0x11, /* ttl */ + 0x01, 0x00, 0x00, 0x00, /* loc count, eid len, ACT, A */ + 0x00, 0x00, 0x40, 0x05, /* rsvd, map ver num, AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06, /* MAC EID */ + + /* locator 1 */ + 0x02, 0x01, 0x00, 0x00, /* prio, weight, mprio, mweight */ + 0x00, 0x04, 0x00, 0x01, /* flags, AFI = ipv4 */ + 0x66, 0x77, 0x88, 0x99, /* ipv4 locator address */ + }; + _assert (0 == memcmp (expected_data, b->data, sizeof (expected_data))); +done: + clib_mem_free (data); + return error; +} + +static clib_error_t * +test_lisp_parse_lcaf () +{ + int i; + clib_error_t * error = 0; + gid_address_t eid; + locator_t * locs = 0; + locator_t probed; + vlib_buffer_t * b = 0; + u32 buff_len = 500; + + b = clib_mem_alloc (buff_len); + memset ((u8 *)b, 0, buff_len); + + u8 map_reply_records[] = + { + /* 1. record */ + 0x01, 0x02, 0x03, 0x04, /* record TTL */ + 0x03, /* locator count */ + 0x00, 0x00, 0x00, /* eid-mask-len; ... */ + 0x00, 0x00, /* reserved; map-version num */ + 0x00, 0x01, /* EID-Prefix-AFI */ + 0x33, 0x44, 0x55, 0x66, /* eid-prefix */ + + /* 1st locator */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x40, 0x03, /* Loc-AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x09, /* iid */ + 0x00, 0x01, /* AFI = ipv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 loator address */ + + /* 2nd locator */ + 0x07, /* prority */ + 0x06, /* weight */ + 0x05, /* m-prority */ + 0x04, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x40, 0x03, /* Loc-AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x16, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x22, 0x44, 0x66, 0x88, /* iid */ + 0x00, 0x02, /* AFI = ipv6 */ + 0xcc, 0xdd, 0xee, 0xff, + 0x88, 0x99, 0xaa, 0xbb, + 0x44, 0x55, 0x66, 0x77, + 0x00, 0x11, 0x22, 0x33, /* ipv6 locator address */ + + /* 3rd locator */ + 0x0a, /* prority */ + 0x0b, /* weight */ + 0x0c, /* m-prority */ + 0x0d, /* m-weight */ + 0x00, 0x00, /* unused flags */ + 0x00, 0x01, /* Loc-AFI */ + 0xaa, 0xbb, 0xcc, 0xdd, /* Loator */ + }; + + b->current_length = buff_len; + memcpy (b->data, map_reply_records, sizeof (map_reply_records)); + + lisp_msg_parse_mapping_record (b, &eid, &locs, &probed); + _assert (vec_len (locs) == 3); + _assert (eid.ippref.addr.ip.v4.as_u32 == 0x66554433); + + /* check 1st locator - an LCAF with ipv4 */ + _assert (locs[0].local == 0); + _assert (locs[0].priority == 0xa); + _assert (locs[0].weight == 0xb); + _assert (locs[0].mpriority == 0xc); + _assert (locs[0].mweight == 0xd); + + _assert (gid_address_type (&locs[0].address) == GID_ADDR_IP_PREFIX); + _assert (gid_address_vni (&locs[0].address) == 0x09); + ip_prefix_t * ip_pref = &gid_address_ippref (&locs[0].address); + _assert (IP4 == ip_prefix_version (ip_pref)); + + /* 2nd locator - LCAF entry with ipv6 address */ + _assert (locs[1].local == 0); + _assert (locs[1].priority == 0x7); + _assert (locs[1].weight == 0x6); + _assert (locs[1].mpriority == 0x5); + _assert (locs[1].mweight == 0x4); + + _assert (gid_address_type (&locs[1].address) == GID_ADDR_IP_PREFIX); + _assert (0x22446688 == gid_address_vni (&locs[1].address)); + ip_pref = &gid_address_ippref (&locs[1].address); + _assert (IP6 == ip_prefix_version (ip_pref)); + + /* 3rd locator - simple ipv4 address */ + _assert (gid_address_type (&locs[2].address) == GID_ADDR_IP_PREFIX); +done: + clib_mem_free (b); + + for (i = 0; i < 3; i++) + locator_free (&locs[i]); + vec_free (locs); + return error; +} + +#define foreach_test_case \ + _(lisp_msg_put_mreq) \ + _(lisp_msg_put_mreq_with_lcaf) \ + _(lisp_msg_push_ecm) \ + _(lisp_msg_parse) \ + _(lisp_msg_parse_mapping_record) \ + _(lisp_parse_lcaf) \ + _(lisp_map_register) + +int run_tests (void) +{ + clib_error_t * error; + +#define _(_test_name) \ + error = test_ ## _test_name (); \ + if (error) \ + { \ + clib_error_report (error); \ + return 0; \ + } + + foreach_test_case +#undef _ + + return 0; +} + +int main() +{ + return run_tests (); +} +#undef _assert diff --git a/src/tests/vnet/lisp-cp/test_lisp_types.c b/src/tests/vnet/lisp-cp/test_lisp_types.c new file mode 100644 index 00000000000..5d910f6669b --- /dev/null +++ b/src/tests/vnet/lisp-cp/test_lisp_types.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +/* FIXME */ +#include +vpe_api_main_t vpe_api_main; + +#define _assert(e) \ + error = CLIB_ERROR_ASSERT (e); \ + if (error) \ + goto done; + +static clib_error_t * test_locator_type (void) +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid = &_gid_addr; + ip_prefix_t * ippref; + gid_address_type (gid) = GID_ADDR_IP_PREFIX; + gid_address_ippref_len (gid) = 24; + ippref = &gid_address_ippref (gid); + ip_prefix_version (ippref) = IP4; + ip_prefix_len (ippref) = 0; + ip4_address_t * ip4 = &ip_prefix_v4 (ippref); + ip4->as_u32 = 0x20304050; + + /* local locator */ + locator_t loc1, loc2 = { + .local = 1, + .state = 2, + .sw_if_index = 8, + .priority = 3, + .weight = 100, + .mpriority = 4, + .mweight = 101 + }; + locator_copy (&loc1, &loc2); + _assert (0 == locator_cmp (&loc1, &loc2)); + + /* remote locator */ + loc2.local = 0; + + ip_prefix_t nested_ippref; + ip_prefix_version (&nested_ippref) = IP4; + ip_prefix_len (&nested_ippref) = 0; + ip4 = &ip_prefix_v4 (&nested_ippref); + ip4->as_u32 = 0x33882299; + gid_address_t nested_gid = + { + .type = GID_ADDR_IP_PREFIX, + .ippref = nested_ippref + }; + + lcaf_t lcaf = + { + .type = LCAF_INSTANCE_ID, + .uni = + { + .vni_mask_len = 5, + .vni = 0xa1b2c3d4, + .gid_addr = &nested_gid + } + }; + gid_address_type (gid) = GID_ADDR_LCAF; + gid_address_lcaf (gid) = lcaf; + + loc2.address = gid[0]; + locator_copy(&loc1, &loc2); + + _assert (0 == locator_cmp (&loc1, &loc2)); + +done: + locator_free (&loc1); + return error; +} + +static clib_error_t * test_gid_parse_ip_pref () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + u8 data[] = + { + 0x00, 0x01, /* AFI = IPv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 address */ + }; + + u32 len = gid_address_parse (data, gid_addr); + _assert (6 == len); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); +done: + return error; +} + +static clib_error_t * test_gid_parse_mac () +{ + clib_error_t * error = 0; + gid_address_t _gid, * gid = &_gid; + gid_address_t _gid_copy, * gid_copy = &_gid_copy; + + u8 data[] = + { + 0x40, 0x05, /* AFI = MAC address */ + 0x10, 0xbb, 0xcc, 0xdd, /* MAC */ + 0x77, 0x99, + }; + + u32 len = gid_address_parse (data, gid); + _assert (8 == len); + _assert (GID_ADDR_MAC == gid_address_type (gid)); + gid_address_copy (gid_copy, gid); + _assert (0 == gid_address_cmp (gid_copy, gid)); +done: + return error; +} + +static clib_error_t * test_gid_parse_lcaf () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (gid_addr_copy, 0, sizeof (gid_addr_copy[0])); + + u8 data[] = + { + 0x40, 0x03, /* AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x09, /* iid */ + 0x00, 0x01, /* AFI = ipv4 */ + 0x10, 0xbb, 0xcc, 0xdd, /* ipv4 address */ + }; + u32 len = gid_address_parse (data, gid_addr); + _assert (18 == len); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + _assert (GID_ADDR_IP_PREFIX == gid_address_type (gid_addr)); + _assert (9 == gid_address_vni (gid_addr)); + _assert (0x18 == gid_address_vni_mask (gid_addr)); + _assert (0xddccbb10 == gid_addr->ippref.addr.ip.v4.as_u32); + +done: + gid_address_free (gid_addr); + gid_address_free (gid_addr_copy); + return error; +} + +/* recursive LCAFs are not supported */ +#if 0 +static clib_error_t * test_gid_parse_lcaf_complex () +{ + clib_error_t * error = 0; + gid_address_t _gid_addr, * gid_addr = &_gid_addr; + gid_address_t _gid_addr_copy, * gid_addr_copy = &_gid_addr_copy; + + memset (gid_addr, 0, sizeof (gid_addr[0])); + memset (gid_addr_copy, 0, sizeof (gid_addr_copy[0])); + + u8 data[] = + { + 0x40, 0x03, /* AFI = LCAF*/ + + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x18, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0b, /* iid */ + + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x17, /* IID mask-len */ + 0x00, 0x0a, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0c, /* iid */ + + 0x40, 0x03, /* AFI = LCAF*/ + /* LCAF header*/ + 0x00, 0x00, /* reserved1, flags */ + 0x02, /* type = Instance ID */ + 0x16, /* IID mask-len */ + 0x00, 0x16, /* iid length + next AFI lenght */ + /* LCAF Instance ID */ + 0x00, 0x00, 0x00, 0x0d, /* iid */ + + 0x00, 0x02, /* AFI = IPv6 */ + + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, + 0x10, 0xbb, 0xcc, 0xdd, /* ipv6 address */ + }; + u32 len = gid_address_parse (data, gid_addr); + _assert (54 == len); + _assert (gid_addr->type == GID_ADDR_LCAF); + gid_address_copy (gid_addr_copy, gid_addr); + _assert (0 == gid_address_cmp (gid_addr_copy, gid_addr)); + _assert (gid_addr_copy->type == GID_ADDR_LCAF); + + lcaf_t * lcaf = &gid_address_lcaf (gid_addr_copy); + _assert (lcaf->type == LCAF_INSTANCE_ID); + vni_t * v = (vni_t *) lcaf; + _assert (v->vni == 0x0b); + _assert (v->vni_mask_len == 0x18); + + gid_address_t * tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_LCAF); + lcaf = &gid_address_lcaf (tmp); + _assert (lcaf->type == LCAF_INSTANCE_ID); + + v = (vni_t *) lcaf; + _assert (v->vni == 0x0c); + _assert (v->vni_mask_len == 0x17); + + tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_LCAF); + lcaf = &gid_address_lcaf (tmp); + + _assert (lcaf->type == LCAF_INSTANCE_ID); + v = (vni_t *) lcaf; + _assert (v->vni == 0x0d); + _assert (v->vni_mask_len == 0x16); + + tmp = vni_gid (v); + _assert (gid_address_type (tmp) == GID_ADDR_IP_PREFIX); + + ip_prefix_t * ip_pref = &gid_address_ippref (tmp); + ip6_address_t * ip6 = &ip_prefix_v6 (ip_pref); + _assert (ip6->as_u32[0] == 0xddccbb10); + _assert (ip6->as_u32[1] == 0xddccbb10); + _assert (ip6->as_u32[2] == 0xddccbb10); + _assert (ip6->as_u32[3] == 0xddccbb10); + _assert (ip_prefix_version (ip_pref) == IP6); + +done: + gid_address_free (gid_addr); + gid_address_free (gid_addr_copy); + return error; +} +#endif + +#if 0 /* uncomment this once VNI is supported */ +static clib_error_t * test_write_mac_in_lcaf (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .mac = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, + .vni = 0x30, + .vni_mask = 0x10, + .type = GID_ADDR_MAC, + }; + + u16 len = gid_address_put (b, &g); + _assert (8 == len); + + u8 expected[] = + { + 0x40, 0x03, /* AFI = LCAF */ + 0x00, /* reserved1 */ + 0x00, /* flags */ + 0x02, /* LCAF type = Instance ID */ + 0x20, /* IID/VNI mask len */ + 0x00, 0x0a, /* length */ + 0x01, 0x02, 0x03, 0x04, /* Instance ID / VNI */ + + 0x00, 0x06, /* AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06 /* MAC */ + } + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} +#endif + +static clib_error_t * test_mac_address_write (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + gid_address_t g = + { + .mac = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, + .type = GID_ADDR_MAC, + }; + + u16 len = gid_address_put (b, &g); + _assert (8 == len); + + u8 expected[] = + { + 0x40, 0x05, /* AFI = MAC */ + 0x01, 0x02, 0x03, 0x04, + 0x05, 0x06 /* MAC */ + }; + _assert (0 == memcmp (expected, b, len)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_src_dst_with_vni_serdes (void) +{ + clib_error_t * error = 0; + u8 * b = clib_mem_alloc (500); + memset (b, 0, 500); + + fid_address_t src = + { + .type = FID_ADDR_IP_PREF, + .ippref = + { + .len = 24, + .addr = + { + .version = IP4, + .ip.v4.data = { 0x1, 0x2, 0x3, 0x0 } + } + } + }; + + fid_address_t dst = + { + .type = FID_ADDR_IP_PREF, + .ippref = + { + .len = 16, + .addr = + { + .version = IP4, + .ip.v4.data = { 0x9, 0x8, 0x0, 0x0 } + } + } + }; + + source_dest_t sd = + { + .src = src, + .dst = dst + }; + + gid_address_t g = + { + .sd = sd, + .type = GID_ADDR_SRC_DST, + .vni = 0x12345678, + .vni_mask = 0x9 + }; + + u16 size_to_put = gid_address_size_to_put(&g); + _assert (36 == size_to_put); + _assert (0 == gid_address_len(&g)); + + u16 write_len = gid_address_put (b, &g); + printf("sizetoput %d; writelen %d\n", size_to_put, write_len); + _assert (size_to_put == write_len); + + u8 expected_data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x02, 0x09, 0x00, 0x1c, /* LCAF type = IID, IID mask-len, length */ + 0x12, 0x34, 0x56, 0x78, /* reserved; source-ML, Dest-ML */ + + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x0c, 0x00, 0x00, 0x10, /* LCAF type = source/dest key, rsvd, length */ + 0x00, 0x00, 0x18, 0x10, /* reserved; source-ML, Dest-ML */ + + 0x00, 0x01, /* AFI = ip4 */ + 0x01, 0x02, 0x03, 0x00, /* source */ + + 0x00, 0x01, /* AFI = ip4 */ + 0x09, 0x08, 0x00, 0x00, /* destination */ + }; + _assert (0 == memcmp (expected_data, b, sizeof (expected_data))); + + gid_address_t p; + memset (&p, 0, sizeof (p)); + _assert (write_len == gid_address_parse (b, &p)); + _assert (0 == gid_address_cmp (&g, &p)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * +test_src_dst_serdes (void) +{ + clib_error_t * error = 0; + + u8 * b = clib_mem_alloc (500); + memset (b, 0, 500); + + fid_address_t src = + { + .type = FID_ADDR_MAC, + .mac = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 } + }; + + fid_address_t dst = + { + .type = FID_ADDR_MAC, + .mac = { 0x10, 0x21, 0x32, 0x43, 0x54, 0x65 } + }; + + source_dest_t sd = + { + .src = src, + .dst = dst + }; + + gid_address_t g = + { + .sd = sd, + .type = GID_ADDR_SRC_DST, + .vni = 0x0, + .vni_mask = 0x0 + }; + + u16 size_to_put = gid_address_size_to_put(&g); + _assert (28 == size_to_put); + _assert (0 == gid_address_len(&g)); + + u16 write_len = gid_address_put (b, &g); + _assert (size_to_put == write_len); + + u8 expected_data[] = + { + 0x40, 0x03, 0x00, 0x00, /* AFI = LCAF, reserved1, flags */ + 0x0c, 0x00, 0x00, 0x14, /* LCAF type = source/dest key, rsvd, length */ + 0x00, 0x00, 0x00, 0x00, /* reserved; source-ML, Dest-ML */ + + 0x40, 0x05, /* AFI = MAC */ + 0x11, 0x22, 0x33, 0x44, + 0x55, 0x66, /* source */ + + 0x40, 0x05, /* AFI = MAC */ + 0x10, 0x21, 0x32, 0x43, + 0x54, 0x65, /* destination */ + }; + _assert (0 == memcmp (expected_data, b, sizeof (expected_data))); + + gid_address_t p; + memset (&p, 0, sizeof (p)); + _assert (write_len == gid_address_parse (b, &p)); + _assert (0 == gid_address_cmp (&g, &p)); +done: + clib_mem_free (b); + return error; +} + +static clib_error_t * test_gid_address_write (void) +{ + clib_error_t * error = 0; + ip_prefix_t ippref_data, * ippref = &ippref_data; + + u8 * b = clib_mem_alloc(500); + memset(b, 0, 500); + + ip_prefix_version (ippref) = IP4; + ip_prefix_len (ippref) = 9; + ip4_address_t * ip4 = &ip_prefix_v4 (ippref); + ip4->as_u32 = 0xaabbccdd; + + gid_address_t g = + { + .ippref = ippref[0], + .type = GID_ADDR_IP_PREFIX, + .vni = 0x01020304, + .vni_mask = 0x18 + }; + + _assert (18 == gid_address_size_to_put (&g)); + _assert (gid_address_len (&g) == 9); + + u16 write_len = gid_address_put (b, &g); + _assert (18 == write_len); + + u8 expected_gid_data[] = + { + 0x40, 0x03, /* AFI = LCAF */ + 0x00, /* reserved1 */ + 0x00, /* flags */ + 0x02, /* LCAF type = Instance ID */ + 0x18, /* IID/VNI mask len */ + 0x00, 0x0a, /* length */ + 0x01, 0x02, 0x03, 0x04, /* Instance ID / VNI */ + + 0x00, 0x01, /* AFI = IPv4 */ + 0xdd, 0xcc, 0xbb, 0xaa, /* ipv4 addr */ + }; + _assert (0 == memcmp (expected_gid_data, b, sizeof (expected_gid_data))); +done: + clib_mem_free (b); + return error; +} + +#define foreach_test_case \ + _(locator_type) \ + _(gid_parse_ip_pref) \ + _(gid_parse_mac) \ + _(gid_parse_lcaf) \ + _(mac_address_write) \ + _(gid_address_write) \ + _(src_dst_serdes) \ + _(src_dst_with_vni_serdes) + +int run_tests (void) +{ + clib_error_t * error; + +#define _(_test_name) \ + error = test_ ## _test_name (); \ + if (error) \ + { \ + clib_error_report (error); \ + return 0; \ + } + + foreach_test_case +#undef _ + + return 0; +} + +int main() +{ + return run_tests (); +} + diff --git a/src/tests/vnet/lisp-gpe/test.c b/src/tests/vnet/lisp-gpe/test.c new file mode 100644 index 00000000000..dde633ae4a3 --- /dev/null +++ b/src/tests/vnet/lisp-gpe/test.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +int main(int argc, char **argv) { + return 0; +} diff --git a/src/tools/elftool/dir.dox b/src/tools/elftool/dir.dox new file mode 100644 index 00000000000..40426e04df7 --- /dev/null +++ b/src/tools/elftool/dir.dox @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Copyright (c) 2016 Comcast Cable Communications Management, LLC. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** @dir + * @brief VPP instrastructure tools. + */ diff --git a/src/tools/elftool/elftool.c b/src/tools/elftool/elftool.c new file mode 100644 index 00000000000..d9d3704b4a3 --- /dev/null +++ b/src/tools/elftool/elftool.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + Copyright (c) 2008 Eliot Dresselhaus + + 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. +*/ + +#include + +#include +#include +#include + +#ifndef CLIB_UNIX +#error "unix only" +#endif + +typedef struct { + elf_main_t elf_main; + char * input_file; + char * output_file; + char * set_interpreter; + char * set_rpath; + int unset_rpath; + int verbose; + int quiet; + int allow_elf_shared; + /* for use in the optimized / simplified case */ + u64 file_size; + u64 interpreter_offset; + u64 rpath_offset; +} elf_tool_main_t; + +static clib_error_t * elf_set_interpreter (elf_main_t * em, + elf_tool_main_t * tm) +{ + elf_segment_t * g; + elf_section_t * s; + clib_error_t * error; + char * interp = tm->set_interpreter; + + switch (em->first_header.file_type) + { + case ELF_EXEC: + break; + + case ELF_SHARED: + if (tm->allow_elf_shared) + break; + /* Note flowthrough */ + default: + return clib_error_return (0, "unacceptable file_type"); + } + + vec_foreach (g, em->segments) + { + if (g->header.type == ELF_SEGMENT_INTERP) + break; + } + + if (g >= vec_end (em->segments)) + return clib_error_return (0, "interpreter not found"); + + if (g->header.memory_size < 1 + strlen (interp)) + return clib_error_return (0, "given interpreter does not fit; must be less than %d bytes (`%s' given)", + g->header.memory_size, interp); + + error = elf_get_section_by_start_address (em, g->header.virtual_address, &s); + if (error) + return error; + + /* Put in new null terminated string. */ + memset (s->contents, 0, vec_len (s->contents)); + clib_memcpy (s->contents, interp, strlen (interp)); + + return 0; +} + +static void +delete_rpath_for_section (elf_main_t * em, elf_section_t * s) +{ + elf64_dynamic_entry_t * e; + elf64_dynamic_entry_t * new_es = 0; + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + break; + + default: + vec_add1 (new_es, e[0]); + break; + } + } + + /* Pad so as to keep section size constant. */ + { + elf64_dynamic_entry_t e_end; + e_end.type = ELF_DYNAMIC_ENTRY_END; + e_end.data = 0; + while (vec_len (new_es) < vec_len (em->dynamic_entries)) + vec_add1 (new_es, e_end); + } + + vec_free (em->dynamic_entries); + em->dynamic_entries = new_es; + + elf_set_dynamic_entries (em); +} + +static void delete_rpath (elf_main_t * em) +{ + elf_section_t * s; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_DYNAMIC: + delete_rpath_for_section (em, s); + break; + + default: + break; + } + } +} + +static clib_error_t * +set_rpath_for_section (elf_main_t * em, elf_section_t * s, char * new_rpath) +{ + elf64_dynamic_entry_t * e; + char * old_rpath; + int old_len, new_len = strlen (new_rpath); + u8 * new_string_table = vec_dup (em->dynamic_string_table); + + vec_foreach (e, em->dynamic_entries) + { + switch (e->type) + { + case ELF_DYNAMIC_ENTRY_RPATH: + case ELF_DYNAMIC_ENTRY_RUN_PATH: + old_rpath = (char *) new_string_table + e->data; + old_len = strlen (old_rpath); + if (old_len < new_len) + return clib_error_return (0, "rpath of `%s' does not fit (old rpath `%s')", + new_rpath, old_rpath); + strcpy (old_rpath, new_rpath); + break; + + default: + break; + } + } + + elf_set_section_contents (em, em->dynamic_string_table_section_index, + new_string_table, + vec_bytes (new_string_table)); + + return 0; +} + +static clib_error_t * +set_rpath (elf_main_t * em, char * rpath) +{ + clib_error_t * error = 0; + elf_section_t * s; + + vec_foreach (s, em->sections) + { + switch (s->header.type) + { + case ELF_SECTION_DYNAMIC: + error = set_rpath_for_section (em, s, rpath); + if (error) + return error; + break; + + default: + break; + } + } + + return error; +} + +static clib_error_t * +set_interpreter_rpath (elf_tool_main_t * tm) +{ + int ifd = -1, ofd = -1; + struct stat fd_stat; + u8 *idp = 0; /* warning be gone */ + u64 mmap_length = 0, i; + u32 run_length; + u8 in_run; + u64 offset0 = 0, offset1 = 0; + clib_error_t * error = 0; + int fix_in_place = 0; + + if (!strcmp (tm->input_file, tm->output_file)) + fix_in_place = 1; + + ifd = open (tm->input_file, O_RDWR); + if (ifd < 0) + { + error = clib_error_return_unix (0, "open `%s'", tm->input_file); + goto done; + } + + if (fstat (ifd, &fd_stat) < 0) + { + error = clib_error_return_unix (0, "fstat `%s'", tm->input_file); + goto done; + } + + if (!(fd_stat.st_mode & S_IFREG)) + { + error = clib_error_return (0, "%s is not a regular file", tm->input_file); + goto done; + } + + mmap_length = fd_stat.st_size; + if (mmap_length < 4) + { + error = clib_error_return (0, "%s too short", tm->input_file); + goto done; + } + + /* COW-mapping, since we intend to write the fixups */ + if (fix_in_place) + idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_SHARED, + ifd, /* offset */ 0); + else + idp = mmap (0, mmap_length, PROT_READ | PROT_WRITE, MAP_PRIVATE, + ifd, /* offset */ 0); + if (~pointer_to_uword (idp) == 0) + { + mmap_length = 0; + error = clib_error_return_unix (0, "mmap `%s'", tm->input_file); + goto done; + } + + if (idp[0] != 0x7f || idp[1] != 'E' || idp[2] != 'L' || idp[3] != 'F') + { + error = clib_error_return (0, "not an ELF file '%s'", tm->input_file); + goto done; + } + + in_run = 0; + run_length = 0; + + for (i = 0; i < mmap_length; i++) + { + if (idp[i] == '/') + { + if (in_run) + run_length++; + else + { + in_run = 1; + run_length = 1; + } + } + else + { + if (in_run && run_length >= 16) + { + if (offset0 == 0) + offset0 = (i - run_length); + else if (offset1 == 0) + { + offset1 = (i - run_length); + goto found_both; + } + } + in_run = 0; + run_length = 0; + } + } + + if (offset0 == 0) + { + error = clib_error_return (0, "no fixup markers in %s", + tm->input_file); + goto done; + } + + found_both: + if (0) + clib_warning ("offset0 %lld (0x%llx), offset1 %lld (0x%llx)", + offset0, offset0, offset1, offset1); + + /* Executable file case */ + if (offset0 && offset1) + { + tm->interpreter_offset = offset0; + tm->rpath_offset = offset1; + } + else /* shared library case */ + { + tm->interpreter_offset = 0; + tm->rpath_offset = offset0; + } + + if (tm->interpreter_offset) + clib_memcpy (&idp[tm->interpreter_offset], tm->set_interpreter, + strlen (tm->set_interpreter)+1); + + if (tm->rpath_offset) + clib_memcpy (&idp[tm->rpath_offset], tm->set_rpath, + strlen (tm->set_rpath)+1); + + /* Write the output file... */ + if (fix_in_place == 0) + { + ofd = open (tm->output_file, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (ofd < 0) + { + error = clib_error_return_unix (0, "create `%s'", tm->output_file); + goto done; + } + + if (write (ofd, idp, mmap_length) != mmap_length) + error = clib_error_return_unix (0, "write `%s'", tm->output_file); + } + + done: + if (mmap_length > 0 && idp) + munmap (idp, mmap_length); + if (ifd >= 0) + close (ifd); + if (ofd >= 0) + close (ofd); + return error; +} + + +int main (int argc, char * argv[]) +{ + elf_tool_main_t _tm, * tm = &_tm; + elf_main_t * em = &tm->elf_main; + unformat_input_t i; + clib_error_t * error = 0; + + memset (tm, 0, sizeof (tm[0])); + unformat_init_command_line (&i, argv); + + while (unformat_check_input (&i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (&i, "in %s", &tm->input_file)) + ; + else if (unformat (&i, "out %s", &tm->output_file)) + ; + else if (unformat (&i, "set-interpreter %s", &tm->set_interpreter)) + ; + else if (unformat (&i, "set-rpath %s", &tm->set_rpath)) + ; + else if (unformat (&i, "unset-rpath")) + tm->unset_rpath = 1; + else if (unformat (&i, "verbose")) + tm->verbose = ~0; + else if (unformat (&i, "verbose-symbols")) + tm->verbose |= FORMAT_ELF_MAIN_SYMBOLS; + else if (unformat (&i, "verbose-relocations")) + tm->verbose |= FORMAT_ELF_MAIN_RELOCATIONS; + else if (unformat (&i, "verbose-dynamic")) + tm->verbose |= FORMAT_ELF_MAIN_DYNAMIC; + else if (unformat (&i, "quiet")) + tm->quiet = 1; + else if (unformat (&i, "allow-elf-shared")) + tm->allow_elf_shared = 1; + else + { + error = unformat_parse_error (&i); + goto done; + } + } + + if (! tm->input_file) + { + error = clib_error_return (0, "no input file"); + goto done; + } + + /* Do the typical case a stone-simple way... */ + if (tm->quiet && tm->set_interpreter && tm->set_rpath && tm->output_file) + { + error = set_interpreter_rpath (tm); + goto done; + } + + error = elf_read_file (em, tm->input_file); + + if (error) + goto done; + + if (tm->verbose) + fformat (stdout, "%U", format_elf_main, em, tm->verbose); + + if (tm->set_interpreter) + { + error = elf_set_interpreter (em, tm); + if (error) + goto done; + } + + if (tm->set_rpath) + { + error = set_rpath (em, tm->set_rpath); + if (error) + goto done; + } + + if (tm->unset_rpath) + delete_rpath (em); + + if (tm->output_file) + error = elf_write_file (em, tm->output_file); + + elf_main_free (em); + + done: + if (error) + { + if (tm->quiet == 0) + clib_error_report (error); + return 1; + } + else + return 0; +} diff --git a/src/tools/g2/clib.c b/src/tools/g2/clib.c new file mode 100644 index 00000000000..6454c84d42d --- /dev/null +++ b/src/tools/g2/clib.c @@ -0,0 +1,154 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2009-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include "g2.h" + +int widest_track_format; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +elog_main_t elog_main; + +void *get_clib_event (unsigned int datum) +{ + elog_event_t *ep = vec_elt_at_index (elog_main.events, datum); + return (void *)ep; +} + +/* + * read_clib_file + */ +int read_clib_file(char *clib_file) +{ + static FILE *ofp; + clib_error_t *error = 0; + int i; + elog_main_t *em = &elog_main; + double starttime, delta; + + vec_free(em->events); + vec_free(em->event_types); + if (the_trackdef_hash) + hash_free(the_trackdef_hash); + + the_trackdef_hash = hash_create (0, sizeof (uword)); + + error = elog_read_file (&elog_main, clib_file); + + if (error) { + fformat(stderr, "%U", format_clib_error, error); + return (1); + } + + if (ofp == NULL) { + ofp = fdopen(2, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(2)?\n"); + exit(1); + } + } + + em = &elog_main; + + for (i = 0; i < vec_len (em->tracks); i++) { + u32 track_code; + bound_track_t * btp; + elog_track_t * t; + uword * p; + int track_strlen; + + t = &em->tracks[i]; + track_code = i; + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = (u8 *) t->name; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + track_strlen = strlen((char *)btp->track_str); + if (track_strlen > widest_track_format) + widest_track_format = track_strlen; + } + + initialize_events(); + + for (i = 0; i < vec_len (em->event_types); i++) { + elog_event_type_t *ep; + u8 *tmp; + + ep = vec_elt_at_index(em->event_types, i); + tmp = (u8 *) vec_dup(ep->format); + vec_add1(tmp,0); + add_event_from_clib_file (ep->type_index_plus_one, (char *) tmp, i); + vec_free(tmp); + } + + finalize_events(); + + em->events = elog_get_events (em); + + cpel_event_init(vec_len(em->events)); + + starttime = em->events[0].time; + + for (i = 0; i < vec_len (em->events); i++) { + elog_event_t *ep; + + ep = vec_elt_at_index(em->events, i); + + delta = ep->time - starttime; + + add_clib_event (delta, ep->track, ep->type + 1, i); + } + + cpel_event_finalize(); + + set_pid_ax_width(8*widest_track_format); + + return(0); +} diff --git a/src/tools/g2/configure.ac b/src/tools/g2/configure.ac new file mode 100644 index 00000000000..c8af7747b89 --- /dev/null +++ b/src/tools/g2/configure.ac @@ -0,0 +1,12 @@ +AC_INIT(g2, 3.0) +AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) + +AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, + AC_MSG_ERROR([Please install the vpp-lib package])) +AC_CHECK_HEADER([vppinfra/clib.h],, + AC_MSG_ERROR([Please install the vpp-dev package])) + +PKG_CHECK_MODULES(g2, gtk+-2.0) + +AC_OUTPUT([Makefile]) diff --git a/src/tools/g2/cpel.c b/src/tools/g2/cpel.c new file mode 100644 index 00000000000..8bcc91e674e --- /dev/null +++ b/src/tools/g2/cpel.c @@ -0,0 +1,470 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include "g2.h" + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; +} bound_event_t; + +bound_event_t *bound_events; + +int widest_track_format=8; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ +u8 *event_strtab; /* event string-table */ + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + initialize_events(); + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + add_event_from_cpel_file(event_code, (char *) bp->event_str, + (char *)bp->datum_str); + + ep++; + } + + finalize_events(); + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int track_strlen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + track_strlen = strlen((char *)btp->track_str); + if (track_strlen > widest_track_format) + widest_track_format = track_strlen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + u32 event_code, track_code, datum; + u64 starttime = ~0ULL; + int nevents; + int i; + event_entry_t *ep; + u64 now; + u64 delta; + u32 time0, time1; + double d; + uword *p; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9; + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + event_strtab = (u8 *)p[0]; + + cpel_event_init(nevents); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_ns; + + now = d; + + if (starttime == ~0ULL) + starttime = now; + + delta = now - starttime; + + /* Delta = time since first event, in usec */ + event_code = ntohl(ep->event_code); + track_code = ntohl(ep->track); + datum = ntohl(ep->event_datum); + + add_cpel_event(delta, track_code, event_code, datum); + + ep++; + } + cpel_event_finalize(); + return(0); +} + +char *strtab_ref(unsigned long datum) +{ + return ((char *)(event_strtab + datum)); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + } + + return(0); +} + + +int cpel_process(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + + return(0); +} + +/* + * read_cpel_file + */ +int read_cpel_file(char *cpel_file) +{ + int verbose = 0; + int rv; + static u8 *cpel; + static unsigned long size; + static FILE *ofp; + + if (cpel) { + unmapfile((char *)cpel, size); + hash_free(the_strtab_hash); + the_strtab_hash = 0; + hash_free(the_evtdef_hash); + the_evtdef_hash = 0; + hash_free(the_trackdef_hash); + the_trackdef_hash = 0; + } + + cpel = (u8 *)mapfile((char *)cpel_file, &size); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (ofp == NULL) { + ofp = fdopen(2, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(2)?\n"); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + + rv = cpel_process(cpel, verbose, ofp); + + set_pid_ax_width(8*widest_track_format); + + return(rv); +} + +static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"}; +static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"}; + +/* + * get_track_label + */ +char *get_track_label(unsigned long track) +{ + uword *p; + bound_track_t *tp; + + p = hash_get(the_trackdef_hash, track); + if (p) { + tp = &bound_tracks[p[0]]; + } else { + if (track > 65535) + tp = &generic_hex_track; + else + tp = &generic_decimal_track; + } + return((char *)tp->track_str); +} diff --git a/src/tools/g2/cpel.h b/src/tools/g2/cpel.h new file mode 100644 index 00000000000..73e4aea5755 --- /dev/null +++ b/src/tools/g2/cpel.h @@ -0,0 +1,83 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CPEL_H_ +#define _CPEL_H_ 1 + +typedef struct cpel_file_header_ { + unsigned char endian_version; + unsigned char pad; + unsigned short nsections; + unsigned file_date; +} cpel_file_header_t; + +#define CPEL_FILE_LITTLE_ENDIAN 0x80 +#define CPEL_FILE_VERSION 0x01 +#define CPEL_FILE_VERSION_MASK 0x7F + +typedef struct cpel_section_header_ { + unsigned int section_type; + unsigned int data_length; /* does NOT include type and itself */ +} cpel_section_header_t; + +#define CPEL_SECTION_STRTAB 1 +/* string at offset 0 is the name of the table */ + +#define CPEL_SECTION_SYMTAB 2 +#define CPEL_SECTION_EVTDEF 3 + +typedef struct event_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_event_definitions; +} event_definition_section_header_t; + +typedef struct event_definition_ { + unsigned int event; + unsigned int event_format; + unsigned int datum_format; +} event_definition_t; + +#define CPEL_SECTION_TRACKDEF 4 + +typedef struct track_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_track_definitions; +} track_definition_section_header_t; + +typedef struct track_definition_ { + unsigned int track; + unsigned int track_format; +} track_definition_t; + +#define CPEL_SECTION_EVENT 5 + +typedef struct event_section_header_ { + char string_table_name[64]; + unsigned int number_of_events; + unsigned int clock_ticks_per_second; +} event_section_header_t; + +typedef struct event_entry_ { + unsigned int time[2]; + unsigned int track; + unsigned int event_code; + unsigned int event_datum; +} event_entry_t; + +#define CPEL_NUM_SECTION_TYPES 5 + +#endif /* _CPEL_H_ */ + diff --git a/src/tools/g2/events.c b/src/tools/g2/events.c new file mode 100644 index 00000000000..d4333bb05d1 --- /dev/null +++ b/src/tools/g2/events.c @@ -0,0 +1,475 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "g2.h" +#include +#include +#include +#include + +/* + * globals + */ +boolean g_little_endian; +event_t *g_events; +ulong g_nevents; +pid_sort_t *g_pids; +pid_sort_t *g_original_pids; +int g_npids; +pid_data_t *g_pid_data_list; + +/* + * locals + */ +pid_data_t **s_pidhash; + +/* + * config parameters + */ + +double ticks_per_ns=1000.0; +boolean ticks_per_ns_set; + +/**************************************************************************** +* event_init +****************************************************************************/ + +void event_init(void) +{ + ulong endian; + char *ep; + char *askstr; + int tmp; + + ep = (char *)&endian; + endian = 0x12345678; + if (*ep != 0x12) + g_little_endian = TRUE; + else + g_little_endian = FALSE; + + askstr = getprop("dont_ask_ticks_per_ns_initially"); + + if (askstr && (*askstr == 't' || *askstr == 'T')) { + tmp = atol(getprop_default("ticks_per_ns", 0)); + if (tmp > 0) { + ticks_per_ns = tmp; + ticks_per_ns_set = TRUE; + } + } +} + +/**************************************************************************** +* find_or_add_pid +****************************************************************************/ + +pid_data_t *find_or_add_pid (ulong pid) +{ + pid_data_t *pp; + ulong bucket; + + bucket = pid % PIDHASH_NBUCKETS; + + pp = s_pidhash[bucket]; + + if (pp == 0) { + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); + } + while (pp) { + if (pp->pid_value == pid) + return(pp); + pp = pp->next; + } + + pp = g_malloc0(sizeof(pid_data_t)); + pp->pid_value = pid; + pp->next = s_pidhash[bucket]; + s_pidhash[bucket] = pp; + g_npids++; + return(pp); +} + +/**************************************************************************** +* pid_cmp +****************************************************************************/ + +int pid_cmp(const void *a1, const void *a2) +{ + pid_sort_t *p1 = (pid_sort_t *)a1; + pid_sort_t *p2 = (pid_sort_t *)a2; + + if (p1->pid_value < p2->pid_value) + return(-1); + else if (p1->pid_value == p2->pid_value) + return(0); + else + return(1); +} + +/**************************************************************************** +* make_sorted_pid_vector +****************************************************************************/ + +static void make_sorted_pid_vector(void) +{ + pid_data_t *pp; + pid_data_t **p_previous; + pid_sort_t *psp; + int i; + + psp = g_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + + for (i = 0; i < PIDHASH_NBUCKETS; i++) { + pp = s_pidhash[i]; + while(pp) { + psp->pid = pp; + psp->pid_value = pp->pid_value; + psp++; + pp = pp->next; + } + } + + qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); + + /* put the sort order into the pid objects */ + psp = g_pids; + + /* + * This is rather gross. + * + * We happen to know that whenever this function is called, the hash table + * structure itself is immediately torn down. So the "next" pointers in the + * pid_data_t elements are about to become useless. + * + * So we re-use them, to link all the pid_data_t elements together into a + * single unified linked list, with g_pid_data_list pointing to the head. + * This means we can walk all the pid_data_t objects if we really want to. + * Reading snapshots from disk is one example. + * + * Alternatively we could just leave the hash table in place; this is + * far nicer, but as it happens, trading O(n) lookups for O(1) lookups + * isn't actually a problem for the restricted post-tear-down usage. So for + * now we take the memory savings and swap our hash table for a list. + */ + p_previous = &g_pid_data_list; + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + *p_previous = pp; + p_previous = &pp->next; + psp++; + } + *p_previous = NULL; + + /* + * Squirrel away original (sorted) vector, so we can + * toggle between "chase" mode, snapshots, and the original + * display method on short notice + */ + g_original_pids = g_malloc(sizeof(pid_sort_t)*g_npids); + memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); +} + +/**************************************************************************** +* read_events +****************************************************************************/ + +void read_events(char *filename) +{ + ulong *ulp; + ulong size; + event_t *ep; + raw_event_t *rep; + ulonglong start_time=0ULL; + ulonglong low_time; + boolean once=TRUE; + int i; + char tmpbuf [128]; + + ulp = (ulong *)mapfile(filename, &size); + + if (ulp == NULL) { + sprintf(tmpbuf, "Couldn't open %s\n", filename); + infobox("Read Event Log Failure", tmpbuf); + return; + } + + g_nevents = ntohl(*ulp); + + if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { + sprintf(tmpbuf, "%s was damaged, or isn't an event log.\n", filename); + infobox("Bad Input File", tmpbuf); + g_nevents = 0; + unmapfile((char *)ulp, size); + return; + } + + rep = (raw_event_t *)(ulp+1); + + if (g_events) + g_free(g_events); + + g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + ep = g_events; + + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); + + /* $$$ add a SEGV handler... */ + for (i = 0; i < g_nevents; i++) { + if (once) { + once = FALSE; + start_time = ((ulonglong)ntohl(rep->time[0])); + start_time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + start_time |= low_time; + ep->time = 0LL; + } else { + ep->time = ((ulonglong)ntohl(rep->time[0])); + ep->time <<= 32; + low_time = ntohl(rep->time[1]); + low_time &= 0xFFFFFFFF; + ep->time |= low_time; + ep->time -= start_time; + ep->time /= ticks_per_ns; + } + ep->code = ntohl(rep->code); + ep->pid = find_or_add_pid(ntohl(rep->pid)); + ep->datum = ntohl(rep->datum); + ep->flags = 0; + ep++; + rep++; + } + + unmapfile((char *)ulp, size); + + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +static event_t *add_ep; + +/**************************************************************************** +* cpel_event_init +****************************************************************************/ +void cpel_event_init (ulong nevents) +{ + g_nevents = nevents; + if (g_events) + g_free(g_events); + add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); + while (g_npids > 0) { + g_free((g_pids + g_npids-1)->pid); + g_npids--; + } + if (g_pids) { + g_free(g_pids); + g_free(g_original_pids); + g_pids = 0; + g_original_pids = 0; + } + s_pidhash = (pid_data_t **)g_malloc0( + PIDHASH_NBUCKETS*sizeof(pid_data_t *)); +} + +/**************************************************************************** +* add_cpel_event +****************************************************************************/ + +void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) +{ + event_t *ep; + + ep = add_ep++; + ep->time = delta; + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = datum; + ep->flags = 0; +} + +/**************************************************************************** +* add_clib_event +****************************************************************************/ + +void add_clib_event(double delta, unsigned short track, + unsigned short event, unsigned int index) +{ + event_t *ep; + + ep = add_ep++; + ep->time = (ulonglong) (delta * 1e9); /* time in intger nanoseconds */ + ep->pid = find_or_add_pid(track); + ep->code = event; + ep->datum = index; + ep->flags = EVENT_FLAG_CLIB; +} + +/**************************************************************************** +* cpel_event_finalize +****************************************************************************/ + +void cpel_event_finalize(void) +{ + make_sorted_pid_vector(); + g_free(s_pidhash); + s_pidhash = 0; + + /* Give the view-1 world a chance to reset a few things... */ + view1_read_events_callback(); +} + +/**************************************************************************** +* mapfile +****************************************************************************/ + +char *mapfile (char *file, ulong *sizep) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + return (NULL); + + if (fstat (maphfile, &statb) < 0) { + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) { + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) { + g_error ("%s mapping problem, I quit...\n", file); + } + + close (maphfile); + + if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { + return (rv); + } + + if (sizep) { + *sizep = mapfsize; + } + return (rv); +} + +/**************************************************************************** +* unmapfile +****************************************************************************/ + +boolean unmapfile (char *addr, ulong size) +{ + if (munmap (addr, size) < 0) { + g_warning("Unmap error, addr 0x%lx size 0x%x\n", + (unsigned long) addr, (unsigned int)size); + return(FALSE); + } + return(TRUE); +} + +/**************************************************************************** +* find_event_index +* Binary search for first event whose time is >= t +****************************************************************************/ + +int find_event_index (ulonglong t) +{ + int index, bottom, top; + event_t *ep; + + bottom = g_nevents-1; + top = 0; + + while (1) { + index = (bottom + top) / 2; + + ep = (g_events + index); + + if (ep->time == t) + return(index); + + if (top >= bottom) { + while (index > 0 && ep->time > t) { + ep--; + index--; + } + while (index < g_nevents && ep->time < t) { + ep++; + index++; + } + return(index); + } + + if (ep->time < t) + top = index + 1; + else + bottom = index - 1; + } +} + +/**************************************************************************** +* events_about +****************************************************************************/ + +void events_about (char *tmpbuf) +{ + sprintf(tmpbuf+strlen(tmpbuf), "%d total events, %.3f ticks per us\n", + (int)g_nevents, ticks_per_ns); +} diff --git a/src/tools/g2/g2.h b/src/tools/g2/g2.h new file mode 100644 index 00000000000..1ab42191ca9 --- /dev/null +++ b/src/tools/g2/g2.h @@ -0,0 +1,195 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * typedefs and so forth + */ +#include +#include +#include +#include "props.h" + +typedef char boolean; +typedef unsigned long long ulonglong; + +/* + * main.c + */ + +GtkWidget *g_mainwindow; +GtkWidget *g_mainvbox; +GtkWidget *g_mainhbox; + +/* + * pointsel.c + */ +void point_selector_init(void); +boolean read_event_definitions (char *filename); +char *sxerox(char *); +void pointsel_about(char *); +void pointsel_next_snapshot(void); +void initialize_events(void); +void finalize_events(void); + +#define NEVENTS 100000 + +typedef struct event_def_ { + ulong event; + char *name; + char *format; + boolean selected; + boolean is_clib; + char pad[2]; +} event_def_t; + +event_def_t *find_event_definition (ulong code); + +event_def_t g_eventdefs[NEVENTS]; + +/* + * config params + */ +int c_maxpointsel; /* max # points shown in selector dlg */ +gint c_view1_draw_width; +gint c_view1_draw_height; + +/* + * menu1.c + */ + +void menu1_init(void); +void modal_dialog (char *label_text, char *retry_text, char *default_value, + boolean (*cb)(char *)); +void infobox(char *label_text, char *text); +/* + * view1.c + */ +GdkFont *g_font; +GdkColor fg_black, bg_white; +void view1_init(void); +void view1_display(void); +void view1_read_events_callback(void); +void view1_display_when_idle(void); +void view1_print_callback(GtkToggleButton *item, gpointer data); +void view1_about(char *); +void set_pid_ax_width(int width); +void set_window_title(const char *filename); + +enum view1_tbox_fn { + TBOX_DRAW_BOXED = 1, /* note: order counts */ + TBOX_DRAW_EVENT, + TBOX_DRAW_PLAIN, + TBOX_PRINT_BOXED, + TBOX_PRINT_EVENT, + TBOX_PRINT_PLAIN, /* end restriction */ + TBOX_GETRECT_BOXED, + TBOX_GETRECT_EVENT, + TBOX_GETRECT_PLAIN, +}; + +enum view1_line_fn { + LINE_DRAW_BLACK = 1, + LINE_DRAW_WHITE, + LINE_PRINT, +}; + +GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function); +void line (int x1, int y1, int x2, int y2, enum view1_line_fn function); +gint view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event); + +/* + * events.c + */ + +void events_about (char *); + +typedef struct raw_event { + unsigned long time[2]; + unsigned long pid; + unsigned long code; + unsigned long datum; +} raw_event_t; + +void event_init(void); +char *mapfile (char *file, ulong *sizep); +boolean unmapfile (char *addr, ulong size); +void read_events (char *); +int find_event_index (ulonglong t); +int read_cpel_file(char *file); +int read_clib_file(char *file); +void cpel_event_init(ulong); +void add_event_from_cpel_file(ulong, char * , char *); +void add_event_from_clib_file(unsigned int event, char *name, + unsigned int vec_index); +void add_cpel_event(ulonglong delta, ulong, ulong, ulong); +void add_clib_event(double delta, unsigned short track, + unsigned short event, unsigned int index); +void cpel_event_finalize(void); +void *get_clib_event (unsigned int datum); + +typedef struct pid_data { + struct pid_data *next; + ulong pid_value; /* The actual pid value */ + ulong pid_index; /* Index in pid sort order */ +} pid_data_t; + +#define EVENT_FLAG_SELECT 0x00000001 /* This event is selected */ +#define EVENT_FLAG_SEARCHRSLT 0x00000002 /* This event is the search rslt */ +#define EVENT_FLAG_CLIB 0x00000004 /* clib event */ + +typedef struct pid_sort { + struct pid_data *pid; + ulong pid_value; + /* + * This is a bit of a hack, since this is used only by the view: + */ + unsigned color_index; +} pid_sort_t; + +typedef struct event { + ulonglong time; + ulong code; + pid_data_t *pid; + ulong datum; + ulong flags; +} event_t; + + +boolean g_little_endian; +event_t *g_events; +ulong g_nevents; +pid_sort_t *g_pids; +pid_sort_t *g_original_pids; +int g_npids; +pid_data_t *g_pid_data_list; + +#define PIDHASH_NBUCKETS 20021 /* Should be prime */ + +boolean ticks_per_ns_set; +double ticks_per_ns; + +/* + * version.c + */ +const char *version_string; +const char *minor_v_string; + +/* + * cpel.c + */ +char *get_track_label(unsigned long); +int widest_track_format; +char *strtab_ref(unsigned long); diff --git a/src/tools/g2/g2version.c b/src/tools/g2/g2version.c new file mode 100644 index 00000000000..4b6f9313fee --- /dev/null +++ b/src/tools/g2/g2version.c @@ -0,0 +1,19 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const char *version_string = "G2 (x86_64 GNU/Linux) major version 3.0"; +const char *minor_v_string = + "Built Wed Feb 3 10:58:12 EST 2016"; diff --git a/src/tools/g2/main.c b/src/tools/g2/main.c new file mode 100644 index 00000000000..a782e17f2ef --- /dev/null +++ b/src/tools/g2/main.c @@ -0,0 +1,196 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "g2.h" +#include "props.h" +#include +#include +#include +#include +#include + +/* + * globals + */ + +GtkWidget *g_mainwindow; /* The main window */ + +/* Graphical object heirarchy + * + * [main window] + * [main vbox] + * [main (e.g. file) menubar] + * [view hbox] + * [view bottom menu] + */ + +GtkWidget *g_mainvbox; +GtkWidget *g_mainhbox; + +gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + /* Allow window to be destroyed */ + return(FALSE); +} + +void destroy(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +int main (int argc, char **argv) +{ + char tmpbuf [128]; + struct passwd *pw; + char *event_file = 0; + char *cpel_file = 0; + char *clib_file =0; + char *title = "none"; + int curarg=1; + char *homedir; + + gtk_init(&argc, &argv); + + homedir = getenv ("HOME"); + tmpbuf[0] = 0; + + if (homedir) { + sprintf(tmpbuf, "%s/.g2", homedir); + } else { + pw = getpwuid(geteuid()); + if (pw) { + sprintf(tmpbuf, "%s/.g2", pw->pw_dir); + } + } + if (tmpbuf[0]) + readprops(tmpbuf); + + g_mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT(g_mainwindow), "delete_event", + GTK_SIGNAL_FUNC (delete_event), NULL); + + gtk_signal_connect (GTK_OBJECT(g_mainwindow), "destroy", + GTK_SIGNAL_FUNC (destroy), NULL); + + gtk_container_set_border_width(GTK_CONTAINER(g_mainwindow), 5); + + g_mainvbox = gtk_vbox_new(FALSE, 0); + g_mainhbox = gtk_hbox_new(FALSE, 0); + + /* + * init routines + */ + + menu1_init(); + point_selector_init(); + view1_init(); + event_init(); + + /* + * Now that we're ready to rock 'n roll, see if we've been asked to + * press a few buttons... + */ + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--cpel-input", 4)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + break; + } + g_error("Missing filename after --cpel-input"); + } + if (!strncmp(argv[curarg], "--clib-input", 4)) { + curarg++; + if (curarg < argc) { + clib_file = argv[curarg]; + curarg++; + break; + } + g_error("Missing filename after --cpel-input"); + } + + if (!strncmp(argv[curarg], "--pointdefs", 3)) { + curarg++; + if (curarg < argc) { + read_event_definitions(argv[curarg]); + curarg++; + continue; + } + g_error ("Missing filename after --pointdefs\n"); + } + if (!strncmp(argv[curarg], "--event-log", 3)) { + curarg++; + if (curarg < argc) { + event_file = argv[curarg]; + curarg++; + continue; + } + g_error ("Missing filename after --event-log\n"); + } + + if (!strncmp(argv[curarg], "--ticks-per-us", 3)) { + curarg++; + if (curarg < argc) { + ticks_per_ns = 0.0; + ticks_per_ns = atof(argv[curarg]); + if (ticks_per_ns == 0.0) { + g_error("ticks-per-ns (%s) didn't convert properly\n", + argv[curarg]); + } + ticks_per_ns_set = TRUE; + curarg++; + continue; + } + g_error ("Missing filename after --event-log\n"); + } + + fprintf(stderr, + "g2 [--pointdefs ] [--event-log ]\n"); + fprintf(stderr, " [--ticks-per-us ]\n"); + fprintf(stderr, + " [--cpel-input ] [--clib-input \n"); + fprintf(stderr, + "%s\n%s\n", version_string, minor_v_string); + exit(0); + } + + if (clib_file) { + read_clib_file (clib_file); + title = clib_file; + } else if (cpel_file) { + read_cpel_file(cpel_file); + title = cpel_file; + } else if (event_file) { + read_events(event_file); + title = event_file; + } + + set_window_title(title); + + gtk_signal_connect (GTK_OBJECT (g_mainwindow), "key_press_event", + (GtkSignalFunc) view1_handle_key_press_event, NULL); + gtk_container_add(GTK_CONTAINER(g_mainvbox), g_mainhbox); + gtk_widget_show(g_mainhbox); + gtk_container_add(GTK_CONTAINER(g_mainwindow), g_mainvbox); + gtk_widget_show(g_mainvbox); + gtk_widget_show(g_mainwindow); + + gtk_main(); + return(0); +} diff --git a/src/tools/g2/menu1.c b/src/tools/g2/menu1.c new file mode 100644 index 00000000000..fce81fa66b2 --- /dev/null +++ b/src/tools/g2/menu1.c @@ -0,0 +1,565 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#define GTK_ENABLE_BROKEN // DGMS +#include +#include +#include "g2.h" +#include + +/* + * locals + */ +static GtkWidget *s_mainmenubar; +static GtkWidget *s_filemenu; +static GtkWidget *s_readdefs; +static GtkWidget *s_readevents; +static GtkWidget *s_readeventsclock; +static GtkWidget *s_readcpel; +static GtkWidget *s_readclib; +static GtkWidget *s_print; +static GtkWidget *s_quit; + +static GtkWidget *s_mainfilemenu; +static GtkWidget *s_help_general; +static GtkWidget *s_help_about; +static GtkWidget *s_mainhelpmenu; +static GtkWidget *s_helpmenu; + +static GtkWidget *s_filesel; +static GtkWidget *s_eventsel; + +typedef struct md_ { + GtkWidget *entry; + GtkWidget *label; + GtkWidget *dialog; + boolean (*callback)(char *); + char *retry_text; +} md_t; + +char *general_help = "\n" +"G2 is a performance event visualization tool.\n" +"\n" +"To view CPEL-format event data:\n" +"g2 --cpel \n" +"or use the File Menu->Read CPEL file option.\n" +"\n" +"To view vppinfra-format (.../open-repo/vppinfra/vppinfra/elog.h) event data:\n" +"g2 --clib \n" +"or use the File Menu->Read clib file option.\n" +"\n" +"To toggle event detail boxes, left-mouse-click on an event.\n" +"\n" +"To zoom to an area, depress the left mouse button. Move the\n" +"mouse. Release the mouse.\n" +"\n" +"To use the time ruler, depress the right mouse button. Move the\n" +"mouse. Release when done.\n" +"\n" +"To push a track to the bottom, \n" +"\n" +"To pull a track to the top, \n" +"\n" +"To selectively color/uncolor a track, \n" +"\n" +"To make the mouse scrollwheel faster, press \n" +"\n" +"Hotkeys, supposedly Quake-like:\n" +" w - zoom-in\n" +" s - zoom-out\n" +" a - pan-left\n" +" d - pan-right\n" +" r - pan-up\n" +" f - pan-down\n" +" t - less traces\n" +" g - more traces\n" +"\n" +" e - toggle summary-mode\n" +" c - toggle color-mode\n" +"\n" +" x - take snapshot\n" +" z - go to next snapshot\n" +" p - put snapshots to snapshots.g2 \n" +" l - load snapshots from snapshots.g2\n" +"\n" +"q - quit\n" +"Send comments / bug reports to the \"fd.io\" mailing list.\n"; + +/**************************************************************************** +* debug_dialog_callback +****************************************************************************/ + +boolean debug_dialog_callback (char *s) +{ + g_print("Dialog result: %s", s); + return (TRUE); +} + +/**************************************************************************** +* get_dialog_value +****************************************************************************/ + +static void get_dialog_value (GtkWidget *dialog, gpointer user_data) +{ + md_t *md = (md_t *)user_data; + char * cb_arg; + + cb_arg = (char *) gtk_entry_get_text(GTK_ENTRY(md->entry)); + + if ((*md->callback)(cb_arg)) { + gtk_grab_remove(md->dialog); + gtk_widget_destroy(md->dialog); + } else { + gtk_label_set_text (GTK_LABEL(md->label), md->retry_text); + } +} + +/**************************************************************************** +* modal_dialog +****************************************************************************/ + +void modal_dialog (char *label_text, char *retry_text, char *default_value, + boolean (*cb)(char *)) +{ + GtkWidget *dialog, *label, *ok_button, *entry; + static md_t dlg; + md_t *md = &dlg; + + dialog = gtk_dialog_new(); + label = gtk_label_new(label_text); + + entry = gtk_entry_new(); + if (default_value) + gtk_entry_set_text(GTK_ENTRY(entry), default_value); + + ok_button = gtk_button_new_with_label("OK"); + + md->entry = entry; + md->label = label; + md->retry_text = retry_text; + md->dialog = dialog; + if (cb) + md->callback = cb; + else + md->callback = debug_dialog_callback; + + gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", + GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); + + gtk_signal_connect (GTK_OBJECT (entry), "activate", + GTK_SIGNAL_FUNC(get_dialog_value), (gpointer) md); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + entry); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + ok_button); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show_all(dialog); + gtk_widget_grab_focus(entry); + gtk_grab_add(dialog); +} + +/**************************************************************************** +* get_eventdef_name +****************************************************************************/ + +static void get_eventdef_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_event_definitions(filename); + set_window_title(filename); +} + +/**************************************************************************** +* read_eventdef_callback +****************************************************************************/ + +static void read_eventdef_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read Event Definitions From..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "../h/elog.h"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_eventdef_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* get_events_name +****************************************************************************/ + +static void get_events_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_eventsel)); + read_events(filename); + view1_display_when_idle(); +} + + +/**************************************************************************** +* get_ticks_per_ns +****************************************************************************/ + +static boolean get_ticks_per_ns (char *value) +{ + double rv; + + rv = atof (value); + + if (rv == 0.0 || rv > 100000) + return(FALSE); + + ticks_per_ns = rv; + ticks_per_ns_set = TRUE; + + gtk_widget_show(s_eventsel); + return(TRUE); +} + +/**************************************************************************** +* read_events_callback +****************************************************************************/ + +static void read_events_callback(GtkToggleButton *item, gpointer data) +{ + char tmpbuf [32]; + + s_eventsel = gtk_file_selection_new("Read Events From..."); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_events_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_eventsel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_eventsel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_eventsel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_eventsel)); + + if (ticks_per_ns_set) + gtk_widget_show (s_eventsel); + else { + sprintf(tmpbuf, "%.3f", ticks_per_ns); + modal_dialog ("Please enter clock ticks per nanosecond", + "Invalid: Please enter clock ticks per nanosecond", + tmpbuf, get_ticks_per_ns); + } +} + +/**************************************************************************** +* read_eventclock_callback +****************************************************************************/ + +static void read_eventsclock_callback(GtkToggleButton *item, gpointer data) +{ + ticks_per_ns_set = FALSE; + read_events_callback(item, data); +} + +/**************************************************************************** +* infobox_size_request +****************************************************************************/ + +void infobox_size_request (GtkWidget *widget, GtkRequisition *req, + gpointer user_data) +{ + char *text = (char *)user_data; + char *cp; + int widest_line_in_chars; + int w; + int nlines; + + /* + * You'd think that the string extent function would work here. + * You'd be wrong. + */ + nlines = w = widest_line_in_chars = 0; + for (cp = text; *cp; cp++) { + if (*cp == '\n') { + if (w > widest_line_in_chars) { + widest_line_in_chars = w; + } + w = 0; + nlines++; + } + w++; + } + + nlines++; + + req->width = (widest_line_in_chars * 8) + 20; + req->height = (nlines * 13) + 10; +} + +/**************************************************************************** +* infobox +****************************************************************************/ + +void infobox(char *label_text, char *text) +{ + GtkWidget *dialog, *label, *ok_button, *entry; + GtkWidget *box; + + dialog = gtk_dialog_new(); + label = gtk_label_new(label_text); + + entry = gtk_text_new(NULL, NULL); + + gtk_signal_connect (GTK_OBJECT (entry), "size-request", + GTK_SIGNAL_FUNC(infobox_size_request), + (gpointer) text); + + gtk_text_insert(GTK_TEXT(entry), g_font, &fg_black, &bg_white, + text, -1); + + gtk_text_set_editable(GTK_TEXT(entry), FALSE); + + ok_button = gtk_button_new_with_label("OK"); + + gtk_signal_connect_object (GTK_OBJECT (ok_button), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + (gpointer) GTK_OBJECT(dialog)); + + box = gtk_vbox_new(FALSE, 5); + + + gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), ok_button, FALSE, FALSE, 0); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area), + box); + + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); + gtk_widget_show_all(dialog); +} + +/**************************************************************************** +* help_general_callback +****************************************************************************/ + +static void help_general_callback(GtkToggleButton *item, gpointer data) +{ + infobox("General Help", general_help); +} + +/**************************************************************************** +* help_about_callback +****************************************************************************/ + +static void help_about_callback(GtkToggleButton *item, gpointer data) +{ + char tmpbuf [1024]; + sprintf (tmpbuf, "G2 -- Graphical Event Viewer\n\n"); + view1_about(tmpbuf); + pointsel_about(tmpbuf); + events_about(tmpbuf); + sprintf (tmpbuf+strlen(tmpbuf), "\n%s\n", version_string); + sprintf (tmpbuf+strlen(tmpbuf), "%s\n", minor_v_string); + infobox("About", tmpbuf); +} + + +/**************************************************************************** +* get_cpel_name +****************************************************************************/ + +static void get_cpel_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *)gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_cpel_file(filename); + set_window_title(filename); +} + +/**************************************************************************** +* get_clib_name +****************************************************************************/ + +static void get_clib_name (GtkFileSelection *sel, gpointer user_data) +{ + char *filename = (char *) gtk_file_selection_get_filename ( + GTK_FILE_SELECTION(s_filesel)); + read_clib_file(filename); + set_window_title(filename); +} + +/**************************************************************************** +* read_cpel_callback +****************************************************************************/ + +static void read_cpel_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read CPEL data from..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "cpel.out"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_cpel_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* read_clib_callback +****************************************************************************/ + +static void read_clib_callback(GtkToggleButton *item, gpointer data) +{ + + s_filesel = gtk_file_selection_new("Read clib data From..."); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(s_filesel), + "clib.out"); + + gtk_signal_connect (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC(get_clib_name), NULL); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + + gtk_signal_connect_object (GTK_OBJECT ( + GTK_FILE_SELECTION(s_filesel)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) s_filesel); + gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(s_filesel)); + gtk_widget_show (s_filesel); +} + +/**************************************************************************** +* menu1_init +****************************************************************************/ + +void menu1_init(void) +{ + + s_filemenu = gtk_menu_new(); + + s_readcpel = gtk_menu_item_new_with_label + ("Read CPEL file"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readcpel); + gtk_signal_connect(GTK_OBJECT(s_readcpel), "activate", + GTK_SIGNAL_FUNC(read_cpel_callback), 0); + + s_readclib = gtk_menu_item_new_with_label + ("Read CLIB file"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readclib); + gtk_signal_connect(GTK_OBJECT(s_readclib), "activate", + GTK_SIGNAL_FUNC(read_clib_callback), 0); + + s_readdefs = gtk_menu_item_new_with_label ("Read Event Definitions"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readdefs); + gtk_signal_connect(GTK_OBJECT(s_readdefs), "activate", + GTK_SIGNAL_FUNC(read_eventdef_callback), 0); + + s_readevents = gtk_menu_item_new_with_label ("Read Event Log"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readevents); + gtk_signal_connect(GTK_OBJECT(s_readevents), "activate", + GTK_SIGNAL_FUNC(read_events_callback), 0); + + s_readeventsclock = gtk_menu_item_new_with_label + ("Read Event Log with Different Clock Rate"); + gtk_menu_append(GTK_MENU(s_filemenu), s_readeventsclock); + gtk_signal_connect(GTK_OBJECT(s_readeventsclock), "activate", + GTK_SIGNAL_FUNC(read_eventsclock_callback), 0); + + s_print = gtk_menu_item_new_with_label ("Print"); + gtk_menu_append(GTK_MENU(s_filemenu), s_print); + gtk_signal_connect(GTK_OBJECT(s_print), "activate", + GTK_SIGNAL_FUNC(view1_print_callback), 0); + + s_quit = gtk_menu_item_new_with_label ("Exit"); + gtk_menu_append(GTK_MENU(s_filemenu), s_quit); + gtk_signal_connect(GTK_OBJECT(s_quit), "activate", + GTK_SIGNAL_FUNC(gtk_main_quit), 0); + + s_mainfilemenu = gtk_menu_item_new_with_label("File"); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainfilemenu), s_filemenu); + + s_helpmenu = gtk_menu_new(); + + s_help_general = gtk_menu_item_new_with_label ("General"); + gtk_menu_append(GTK_MENU(s_helpmenu), s_help_general); + gtk_signal_connect(GTK_OBJECT(s_help_general), "activate", + GTK_SIGNAL_FUNC(help_general_callback), 0); + + s_help_about = gtk_menu_item_new_with_label ("About"); + gtk_menu_append(GTK_MENU(s_helpmenu), s_help_about); + gtk_signal_connect(GTK_OBJECT(s_help_about), "activate", + GTK_SIGNAL_FUNC(help_about_callback), 0); + + s_mainhelpmenu = gtk_menu_item_new_with_label("Help"); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(s_mainhelpmenu), s_helpmenu); + + s_mainmenubar = gtk_menu_bar_new(); + gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainfilemenu); + gtk_menu_bar_append(GTK_MENU_BAR(s_mainmenubar), s_mainhelpmenu); + gtk_widget_show_all(s_mainmenubar); + + gtk_box_pack_start(GTK_BOX(g_mainvbox), s_mainmenubar, FALSE, FALSE, 0); +} diff --git a/src/tools/g2/mkversion.c b/src/tools/g2/mkversion.c new file mode 100644 index 00000000000..3523fbe6c6d --- /dev/null +++ b/src/tools/g2/mkversion.c @@ -0,0 +1,77 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +int main (int argc, char **argv) +{ + time_t now; + FILE *ofp; + char *dateval; + char *username; + char *userstr; + char *datestr; + int i; + char propname[32]; + char *propvalue; + char timestr[64]; + char *cp; + + if (argc < 4) { + printf ("usage: mkversion ostype version outputfile\n"); + exit (1); + } + + ofp = fopen (argv[3], "w"); + if (ofp == NULL) { + printf ("Couldn't create %s\n", argv[3]); + exit (1); + } + + now = time (0); + + fprintf (ofp, "/*\n"); + fprintf (ofp, " * G2 Version Stamp, %s", + ctime (&now)); + fprintf (ofp, " * Automatically generated, hand edits are pointless.\n"); + fprintf (ofp, " */\n\n"); + + fprintf (ofp, + "const char *version_string = \"G2 (%s) major version %s\";\n", + argv[1], argv[2]); + + username = (char *) cuserid (0); + + strcpy(timestr, ctime(&now)); + + cp = timestr; + + while (*cp) { + cp++; + } + if (*--cp == '\n') + *cp = 0; + + fprintf (ofp, + "const char *minor_v_string = \"Built by %s at %s\";\n", + username, timestr); + + exit (0); +} + + diff --git a/src/tools/g2/pointsel.c b/src/tools/g2/pointsel.c new file mode 100644 index 00000000000..018dc2139e6 --- /dev/null +++ b/src/tools/g2/pointsel.c @@ -0,0 +1,854 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "g2.h" + +/* + * globals + */ +event_def_t g_eventdefs[NEVENTS]; + +/* + * locals + */ +static GtkWidget *s_pointselbox; +static FILE *s_hfp; +static FILE *s_elog_hfp; +static int s_basenum; +static GtkWidget *s_event_buttons[NEVENTS]; +static int s_min_shown_pointsel; +static int s_max_shown_pointsel; +static GtkWidget *s_allbutton; +static GtkWidget *s_nonebutton; +static GtkWidget *s_pointselbuttons; +static GtkWidget *s_ps_vscroll; +static GtkObject *s_ps_vsadj; +static int g_neventdefs; + +enum button_click { + ALL_BUTTON=1, + NONE_BUTTON, +}; + +/* + * config params + */ +int c_maxpointsel; + +/**************************************************************************** +* recompute_vscrollbar +****************************************************************************/ + +static void recompute_ps_vscrollbar (void) +{ + GtkAdjustment *adj; + ulong limit; + + adj = GTK_ADJUSTMENT(s_ps_vsadj); + +#ifdef NOTDEF + /* This seems like the right calculation, but seems not to work */ + if (g_neventdefs > c_maxpointsel) + limit = g_neventdefs - c_maxpointsel; + else + limit = g_neventdefs; +#else + limit = g_neventdefs-1; +#endif + + adj->lower = (gfloat)0.00; + adj->upper = (gfloat)limit; + adj->value = (gfloat)0.00; + adj->step_increment = (gfloat)1.00; + adj->page_increment = (gfloat)(c_maxpointsel / 3); + adj->page_size = (gfloat)c_maxpointsel; + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); + gtk_widget_show(s_ps_vscroll); +} + +/**************************************************************************** +* point_select_callback +****************************************************************************/ + +static void point_select_callback(GtkToggleButton *item, gpointer data) +{ + int i = (int) (unsigned long long) data; + + g_eventdefs[i].selected = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(s_event_buttons[i])); + view1_display_when_idle(); +} + +/**************************************************************************** +* up_button +****************************************************************************/ + +static void up_button(void) +{ + int i; + int increment = c_maxpointsel/4; + + if (s_min_shown_pointsel == 0) + return; + + s_min_shown_pointsel -= increment; + + if (s_min_shown_pointsel < 0) + s_min_shown_pointsel = 0; + + s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } + +} + +#ifdef NOTDEF +/**************************************************************************** +* down_button +****************************************************************************/ + +static void down_button(void) +{ + int i; + int increment = c_maxpointsel/4; + + if (s_max_shown_pointsel == g_neventdefs) + return; + + s_max_shown_pointsel += increment; + + if (s_max_shown_pointsel >= g_neventdefs) + s_max_shown_pointsel = (g_neventdefs-1); + + s_min_shown_pointsel = s_max_shown_pointsel - c_maxpointsel; + + if (s_min_shown_pointsel < 0) + s_min_shown_pointsel = 0; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } + +} +#endif + +/**************************************************************************** +* button_click_callback +****************************************************************************/ + +static void button_click_callback(GtkButton *item, gpointer data) +{ + int i; + enum button_click click = (enum button_click)data; + + switch (click) { + case ALL_BUTTON: + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), TRUE); + g_eventdefs[i].selected = TRUE; + } + break; + + case NONE_BUTTON: + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), FALSE); + g_eventdefs[i].selected = FALSE; + } + break; + } +} + +/**************************************************************************** +* scroll_callback +****************************************************************************/ + +static void scroll_callback (GtkAdjustment *adj, GtkWidget *notused) +{ + int i; + + s_min_shown_pointsel = (int)adj->value; + s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; + + for (i = 0; i < g_neventdefs; i++) { + if (i >= s_min_shown_pointsel && + i <= s_max_shown_pointsel) + gtk_widget_show(s_event_buttons[i]); + else + gtk_widget_hide(s_event_buttons[i]); + } +} + +/**************************************************************************** +* point_selector_init +****************************************************************************/ + +void point_selector_init(void) +{ + + c_maxpointsel = atol(getprop_default("event_selector_lines", "20")); + + s_pointselbox = gtk_vbox_new(FALSE,5); + + s_pointselbuttons = gtk_hbox_new(FALSE,5); + + s_allbutton = gtk_button_new_with_label("ALL"); + gtk_widget_show(s_allbutton); + s_nonebutton = gtk_button_new_with_label("NONE"); + gtk_widget_show(s_nonebutton); + + gtk_signal_connect (GTK_OBJECT(s_allbutton), "clicked", + GTK_SIGNAL_FUNC(button_click_callback), + (gpointer) ALL_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_nonebutton), "clicked", + GTK_SIGNAL_FUNC(button_click_callback), + (gpointer) NONE_BUTTON); + + gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_allbutton, FALSE, + FALSE, 0); + gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_nonebutton, FALSE, + FALSE, 0); + + gtk_widget_show(s_pointselbuttons); + gtk_widget_ref(s_pointselbuttons); + + gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, + FALSE, 0); + + gtk_box_pack_end (GTK_BOX(g_mainhbox), s_pointselbox, + FALSE, FALSE, 0); + + s_ps_vsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_ps_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_ps_vsadj)); + gtk_signal_connect (GTK_OBJECT (s_ps_vsadj), "value-changed", + GTK_SIGNAL_FUNC (scroll_callback), + (gpointer)s_ps_vscroll); + gtk_box_pack_end(GTK_BOX(g_mainhbox), s_ps_vscroll, FALSE, FALSE, 0); +} + +/**************************************************************************** +* sxerox +****************************************************************************/ + +char *sxerox (char *s) +{ + char *rv; + + /* Note: g_malloc does or dies... */ + rv = (char *)g_malloc(strlen(s)+1); + strcpy (rv, s); + return (rv); +} + +/**************************************************************************** +* reset_point_selector +****************************************************************************/ + +static void reset_point_selector(void) +{ + int i; + + gtk_widget_hide(s_pointselbox); + gtk_widget_hide(s_pointselbuttons); + gtk_widget_hide(s_ps_vscroll); + gtk_container_remove(GTK_CONTAINER(s_pointselbox), + s_pointselbuttons); + + for (i = 0; i < g_neventdefs; i++) { + if (s_event_buttons[i]) { + gtk_container_remove(GTK_CONTAINER(s_pointselbox), + s_event_buttons[i]); + s_event_buttons[i] = 0; + } + } +} + +/**************************************************************************** +* create_point_selector +****************************************************************************/ + +static void create_point_selector(void) +{ + int i; + char tmpbuf [1024]; + event_def_t *ep; + GtkWidget *wp; + + for (i = 0; i < g_neventdefs; i++) { + ep = &g_eventdefs[i]; + sprintf(tmpbuf, "[%lu] %s", ep->event, + ep->name ? ep->name : "(none)"); + /* Hack to reduce width of point selectors */ + if (strlen(tmpbuf) > 50) { + tmpbuf[50] = 0; + } + + wp = gtk_check_button_new_with_label (tmpbuf); + s_event_buttons[i] = wp; + gtk_signal_connect (GTK_OBJECT(wp), "toggled", + GTK_SIGNAL_FUNC(point_select_callback), + (gpointer) (unsigned long long) i); + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(wp), TRUE); + gtk_box_pack_start(GTK_BOX(s_pointselbox), wp, FALSE, FALSE, 0); + } + + /* set up scroll parameters by faking an up-button */ + s_min_shown_pointsel = 1; + up_button(); + + gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, + FALSE, 0); + gtk_widget_show(s_pointselbuttons); + gtk_widget_show(s_pointselbox); + gtk_widget_show(s_ps_vscroll); +} + +/**************************************************************************** +* remove_all_events +****************************************************************************/ + +static void remove_all_events(void) +{ + event_def_t *ep; + int i; + + for (i = 0; i < g_neventdefs; i++) { + ep = &g_eventdefs[i]; + if (!ep->is_clib) { + if (ep->name) + g_free(ep->name); + if(ep->format) + g_free(ep->format); + } + } + g_neventdefs = 0; +} + +/**************************************************************************** +* add_event +****************************************************************************/ + +static void add_event(ulong event, char *name, char *format) +{ + int i; + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + /* Simple dup check, probably not needed very often */ + for (i = 0; i < g_neventdefs; i++) { + if (g_eventdefs[i].event == event) { + g_warning("Duplicate def event %lu: first definition retained\n", + event); + return; + } + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + ep->name = sxerox(name); + ep->format = sxerox(format); + ep->selected = TRUE; +} + +/**************************************************************************** +* add_event_from_cpel_file +****************************************************************************/ + +void add_event_from_cpel_file(ulong event, char *event_format, + char *datum_format) +{ + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + /* + * Duplicate the strings for backward compatibility. Otherwise, + * the g_free above will barf because the name/format strings are + * actually in mmap'ed memory + */ + ep->name = sxerox(event_format); + ep->format = sxerox(datum_format); + ep->selected = TRUE; +} + +/**************************************************************************** +* add_event_from_clib_file +****************************************************************************/ + +void add_event_from_clib_file(unsigned int event, char *name, + unsigned int vec_index) +{ + event_def_t *ep; + + if (g_neventdefs >= NEVENTS) { + g_error("Too many event definitions, increase NEVENTS!"); + /*NOTREACHED*/ + } + + ep = &g_eventdefs[g_neventdefs++]; + + ep->event = event; + + ep->name = sxerox(name); + ep->format = (void *)(unsigned long long) vec_index; + ep->selected = TRUE; + ep->is_clib = TRUE; +} + +/**************************************************************************** +* read_header_file - eats header file lines of the form +* +* #define EVENT_FOO 123 / * name: %d * / +* +****************************************************************************/ + +static void read_header_file (void) +{ + char tmpbuf [1024]; + char *name, *format; + char *cp; + unsigned long event; + int ev_num_flag; + + while (fgets (tmpbuf, sizeof (tmpbuf), s_hfp)) + { + cp = tmpbuf; + ev_num_flag = 0; + + if (strncmp (cp, "#define", 7)) + continue; + + /* skip #define */ + while (*cp && !(isspace ((int)*cp))) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after #define */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip symbolic name */ + while (*cp && !(isspace ((int)*cp))) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after symbolic name */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + event = 0; + + if (!strncmp(cp, "EV_NUM", 6)) { + cp += 6; + ev_num_flag = 1; + + while (*cp && *cp != '(') + cp++; + + if (*cp == 0) + continue; + + cp++; + + while (*cp && isspace ((int)*cp)) + cp++; + + } + + /* eat event code. */ + while (*cp && isdigit ((int)*cp)) + { + event = event * 10 + (*cp - '0'); + cp++; + } + + if (*cp == 0) + continue; + + if (ev_num_flag) { + while (*cp && *cp != ')') + cp++; + if (*cp == 0) + continue; + cp++; + event += s_basenum; + } + + /* skip ws after event code */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp != '/') + continue; + + cp++; + + if (*cp != '*') + continue; + + cp++; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + name = cp; + + /* accumulate name */ + while (*cp && *cp != ':' && *cp != '*') + cp++; + + if (*cp == 0) + continue; + + *cp++ = 0; + + /* skip ws after name: */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0 || *cp == '/') + { + format = " "; + goto write_it; + } + + format = cp; + + /* accumulate format string */ + while (*cp && !isspace ((int)*cp)) + cp++; + + *cp = 0; + + write_it: + + add_event (event, name, format); + } +} + +/**************************************************************************** +* read_header_files - eats header file lines of the form +* +* #define FILE1_BASE 100 / * pointdefs: ../vpn/vpn_points.h * / +* +****************************************************************************/ + +static boolean read_header_files (void) +{ + char *cp, *name; + char tmpbuf [1024]; + int basenum; + boolean rv=FALSE; + + while (fgets (tmpbuf, sizeof (tmpbuf), s_elog_hfp)) + { + cp = tmpbuf; + + if (strncmp (cp, "#define", 7)) + continue; + + cp += 7; + + /* skip ws after #define */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip EV_COMPxxx_START */ + while (*cp && !isspace((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + /* skip ws after EV_COMPxxx_START */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + basenum = atol (cp); + + /* skip #define */ + while (*cp && (*cp != '/')) + cp++; + + if (*cp == 0) + continue; + + cp++; + if (*cp != '*') + continue; + + cp++; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + if (*cp == 0) + continue; + + if (strncmp (cp, "pointdefs:", 10)) + continue; + + cp += 10; + + /* skip ws after comment start */ + while (*cp && isspace ((int)*cp)) + cp++; + + name = cp; + + while (*cp && !isspace ((int)*cp)) + cp++; + + *cp = 0; + + s_hfp = fopen (name, "rt"); + + if (s_hfp == NULL) { + g_warning ("Couldn't open header file %s\n", name); + continue; + } + rv = TRUE; + + s_basenum = basenum; + + read_header_file(); + + fclose (s_hfp); + } + return(rv); +} + +/**************************************************************************** +* event_def_cmp +****************************************************************************/ + +int event_def_cmp(const void *a1, const void *a2) +{ + event_def_t *e1 = (event_def_t *)a1; + event_def_t *e2 = (event_def_t *)a2; + + if (e1->event < e2->event) + return(-1); + else if (e1->event == e2->event) + return(0); + else + return(1); +} + +/**************************************************************************** +* sort_event_definitions +****************************************************************************/ + +void sort_event_definitions(void) +{ + qsort(&g_eventdefs[0], g_neventdefs, sizeof(event_def_t), event_def_cmp); +} + +static boolean remove_needed=TRUE; + +void finalize_events(void) +{ + sort_event_definitions(); + create_point_selector(); + recompute_ps_vscrollbar(); + view1_display_when_idle(); + remove_needed = TRUE; +} + +void initialize_events(void) +{ + if (remove_needed) { + reset_point_selector(); + remove_all_events(); + remove_needed = FALSE; + } +} + +/**************************************************************************** +* read_event_definitions +****************************************************************************/ + +boolean read_event_definitions (char *filename) +{ + char tmpbuf [128]; + + initialize_events(); + + s_elog_hfp = fopen (filename, "rt"); + if (s_elog_hfp == NULL) { + sprintf (tmpbuf, "Couldn't open %s\n", filename); + infobox ("Open Failed", tmpbuf); + return(FALSE); + } + /* Presume "elog.h". Note fallthrough... */ + if (read_header_files()) { + sort_event_definitions(); + create_point_selector(); + recompute_ps_vscrollbar(); + fclose(s_elog_hfp); + view1_display_when_idle(); + remove_needed = TRUE; + return(TRUE); + } + fclose(s_elog_hfp); + + s_hfp = fopen (filename, "rt"); + if (s_hfp == NULL) { + sprintf (tmpbuf, "Couldn't open %s\n", filename); + infobox ("Read Event Definition Failure", tmpbuf); + return(FALSE); + } + + read_header_file(); + + /* Happens if the user feeds us the wrong file, for example */ + if (g_neventdefs == 0) { + sprintf (tmpbuf, "No event definitions found in %s\n", filename); + infobox ("No Event Definitions?", tmpbuf); + return(FALSE); + } + finalize_events(); + return(TRUE); +} + +static event_def_t dummy_event; +static char dummy_string[32]; + +/**************************************************************************** +* find_event_definition +* Binary search for first event whose time is >= t +****************************************************************************/ + +event_def_t *find_event_definition (ulong code) +{ + int index, bottom, top; + event_def_t *edp; + + if (g_neventdefs == 0) + goto use_dummy; + + bottom = g_neventdefs-1; + top = 0; + + while (1) { + index = (bottom + top) / 2; + + edp = (g_eventdefs + index); + + if (edp->event == code) + return(edp); + + if (top >= bottom) { + use_dummy: + edp = &dummy_event; + edp->selected = TRUE; + edp->event = code; + edp->format = "0x%x"; + sprintf (dummy_string, "E%lu", code); + edp->name = &dummy_string[0]; + return(edp); + } + + if (edp->event < code) + top = index + 1; + else + bottom = index - 1; + } +} + +/**************************************************************************** +* pointsel_next_snapshot +* Set dialog buttons from snapshot +****************************************************************************/ + +void pointsel_next_snapshot(void) +{ + int i; + + for (i = 0; i < g_neventdefs; i++) { + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON(s_event_buttons[i]), + g_eventdefs[i].selected); + } +} + +/**************************************************************************** +* pointsel_about +****************************************************************************/ + +void pointsel_about (char *tmpbuf) +{ + sprintf (tmpbuf+strlen(tmpbuf), "%d event definitions\n", + g_neventdefs); +} diff --git a/src/tools/g2/props.c b/src/tools/g2/props.c new file mode 100644 index 00000000000..a23dc0504d2 --- /dev/null +++ b/src/tools/g2/props.c @@ -0,0 +1,279 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include + +static char *sxerox (char *s); +void exit(int); + +#define NBUCKETS 97 + +typedef struct prop_ { + struct prop_ *next; + char *name; + char *value; +} prop_t; + +static prop_t *buckets [NBUCKETS]; +static int hash_shifts[4] = {24, 16, 8, 0}; + +/* + * getprop + */ + +char *getprop (char *name) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t *bp; + int i=0; + + for (cp = (unsigned char *) name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bp = buckets [hash%NBUCKETS]; + + while (bp && strcmp (bp->name, name)) { + bp = bp->next; + } + + if (bp == NULL) + return (0); + else + return (bp->value); +} + +/* + * getprop_default + */ + +char *getprop_default (char *name, char *def) +{ + char *rv; + rv = getprop (name); + if (rv) + return (rv); + else + return (def); +} + +/* + * addprop + */ + +void addprop (char *name, char *value) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t **bpp; + prop_t *bp; + int i=0; + + bp = (prop_t *)g_malloc (sizeof (prop_t)); + + bp->next = 0; + bp->name = sxerox (name); + bp->value = sxerox (value); + + for (cp = (unsigned char *)name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bpp = &buckets [hash%NBUCKETS]; + + if (*bpp == NULL) + *bpp = bp; + else { + bp->next = *bpp; + *bpp = bp; + } +} + +/* + * sxerox + */ + +static char *sxerox (char *s) +{ + char *rv = (char *) g_malloc (strlen (s) + 1); + strcpy (rv, s); + return rv; +} + +/* + * readprops + */ + +#define START 0 +#define READNAME 1 +#define READVALUE 2 +#define C_COMMENT 3 +#define CPP_COMMENT 4 + +int readprops (char *filename) +{ + FILE *ifp; + unsigned char c; + int state=START; + int linenum=1; + char namebuf [128]; + char valbuf [512]; + int i; + + ifp = fopen (filename, "r"); + + if (ifp == NULL) + return (-1); + + while (1) { + + readchar: + c = getc (ifp); + + again: + switch (state) { + case START: + if (feof (ifp)) { + fclose (ifp); + return (0); + } + + if (c == ' ' || c == '\t') + goto readchar; + + if (c == '\n') { + linenum++; + goto readchar; + } + if (isalpha (c) || (c == '_')) { + state = READNAME; + goto again; + } + if (c == '/') { + c = getc (ifp); + if (c == '/') { + state = CPP_COMMENT; + goto readchar; + } else if (c == '*') { + state = C_COMMENT; + goto readchar; + } else { + fprintf (stderr, "unknown token '/' line %d\n", + linenum); + exit (1); + } + } + fprintf (stderr, "unknown token '%c' line %d\n", + c, linenum); + exit (1); + break; + + case CPP_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) + return (0); + if (c == '\n') { + linenum++; + state = START; + goto readchar; + } + } + break; + + case C_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "unterminated comment, line %d\n", + linenum); + exit (1); + } + if (c == '*') { + staragain: + c = getc (ifp); + if (c == '/') { + state = START; + goto readchar; + } + if (c == '*') + goto staragain; + } + } + break; + + case READNAME: + i = 0; + namebuf[i++] = c; + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a name, line %d\n", + linenum); + exit (1); + } + if ((!isalnum (c)) && (c != '_')) { + namebuf [i] = 0; + state = READVALUE; + goto again; + } + namebuf [i++] = c; + } + break; + + case READVALUE: + i = 0; + while ((c == ' ') || (c == '\t') || (c == '=')) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a value, line %d\n", + linenum); + exit (1); + } + } + goto firsttime; + while (1) { + c = getc (ifp); + + firsttime: + if (c == '\\') { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF after '\\', line %d\n", + linenum); + exit (1); + } + valbuf[i++] = c; + continue; + } + if (c == '\n') { + linenum++; + while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') + i--; + valbuf[i] = 0; + addprop (namebuf, valbuf); + state = START; + goto readchar; + } + valbuf[i++] = c; + } + + } + } +} diff --git a/src/tools/g2/props.h b/src/tools/g2/props.h new file mode 100644 index 00000000000..6289941dd4d --- /dev/null +++ b/src/tools/g2/props.h @@ -0,0 +1,21 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 1997-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern char *getprop (char *name); +extern char *getprop_default (char *name, char *def); +extern void addprop (char *name, char *value); +extern int readprops (char *filename); +extern int writeprops (char *filename); diff --git a/src/tools/g2/view1.c b/src/tools/g2/view1.c new file mode 100644 index 00000000000..ec394cc3d53 --- /dev/null +++ b/src/tools/g2/view1.c @@ -0,0 +1,3077 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "g2.h" +#include +#include +#include +#include + +/* + * The main event display view. + * + * Important variables: + * + * "da" -- the drawing area, aka the screen representation of the + * event view. + * + * "pm" -- the backing pixmap for the drawing area. Note that + * all graphics operations target this backing + * store, then call gtk_widget_draw to copy a rectangle from + * the backing store onto the screen. + * + * "s_v1" -- pointer to the current v1_geometry_t object. + * + * Box heirarchy: + * s_view1_vbox + * s_view1_hbox + * da s_view1_vmenubox + * s_view1_topbutton("Top") + * s_view1_vscroll (vertical scrollbar) + * s_view1_bottombutton("Bottom") + * s_view1_hmenubox + * s_view1_startbutton("Start"); + * s_view1_hscroll(horizontal scrollbar) + * s_view1_endbutton("End") + * s_view1_zoominbutton("Zoomin") + * s_view1_searchbutton("Search") + * s_view1_searchagainbutton("Search Again") + * s_view1_zoomoutbutton("Zoomout") + * s_view1_label + */ + +/* + * Globals + */ + +GdkFont *g_font; /* a fixed-width font to use */ +GdkColor fg_black = {0, 0, 0, 0}; +GdkColor bg_white = {0, 65535, 65535, 65535}; +static boolean summary_mode = TRUE; /* start out in summary mode */ +static boolean color_mode = FALSE; /* start out in color mode */ + +/* + * Locals + */ + +/* + * user_data values passed to view1_button_click_callback, + * which is used by the various action buttons noted above + */ +enum view1_button_click { + TOP_BUTTON=1, + BOTTOM_BUTTON, + START_BUTTON, + ZOOMIN_BUTTON, + SEARCH_BUTTON, + SEARCH_AGAIN_BUTTON, + ZOOMOUT_BUTTON, + END_BUTTON, + MORE_TRACES_BUTTON, + LESS_TRACES_BUTTON, + SNAP_BUTTON, + NEXT_BUTTON, + DEL_BUTTON, + CHASE_EVENT_BUTTON, + CHASE_DATUM_BUTTON, + CHASE_TRACK_BUTTON, + UNCHASE_BUTTON, + FORWARD_BUTTON, + BACKWARD_BUTTON, + SUMMARY_BUTTON, + NOSUMMARY_BUTTON, +}; + +enum chase_mode { + CHASE_EVENT=1, + CHASE_DATUM, + CHASE_TRACK, +}; + +enum sc_dir { + SRCH_CHASE_FORWARD = 0, + SRCH_CHASE_BACKWARD = 1, +}; + +static GtkWidget *s_view1_hbox; /* see box heirarchy chart */ +static GtkWidget *s_view1_vbox; /* see box heirarchy chart */ +static GtkWidget *da; /* main drawing area */ +static GdkPixmap *pm; /* and its backing pixmap */ +static GdkCursor *norm_cursor; /* the "normal" cursor */ + +/* + * view geometry parameters + * + * Remember: + * Y increases down the page. + * Strip origin is at the top + * Payday is Friday + * Don't put your fingers in your mouth. + * + * Most of these values are in pixels + */ + +typedef struct v1_geometry { + int pid_ax_width; /* Width of the PID axis */ + int time_ax_height; /* Height of the time axis */ + int time_ax_spacing; /* TimeAxis: Space between tick-marks */ + int strip_height; /* Height of a regular PID trace */ + int pop_offset; /* Vertical offset of the detail box */ + int pid_ax_offset; /* Vertical offset of the PID axis */ + int event_offset; /* Vertical offset of the event boxes */ + int total_height; /* total height of da, see configure_event */ + int total_width; /* ditto, for width */ + + /* Derived values */ + int first_pid_index; /* Index of first displayed PID */ + int npids; /* Max number of displayed pids */ + ulonglong minvistime; /* in usec */ + ulonglong maxvistime; /* in usec */ +} v1_geometry_t; + + +/* The active geometry object */ +static v1_geometry_t s_v1record; +static v1_geometry_t *s_v1 = &s_v1record; + +/* The color array */ +static GdkColor *s_color; + +/* Snapshot ring */ +typedef struct snapshot { + struct snapshot *next; + /* Screen geometry */ + v1_geometry_t geometry; + boolean show_event[NEVENTS]; + pid_sort_t *pidvec; + /* + * Note: not worth recomputing the vertical scrollbar, just save + * its value here + */ + gfloat vscroll_value; + boolean summary_mode; + boolean color_mode; +} snapshot_t; + +static snapshot_t *s_snapshots; +static snapshot_t *s_cursnap; +static event_t *s_last_selected_event; + +/* + * various widgets, see the box heirarchy chart above + * The toolkit keeps track of these things, we could lose many of + * these pointers. + */ +static GtkWidget *s_view1_vmenubox; +static GtkWidget *s_view1_topbutton; +static GtkWidget *s_view1_bottombutton; +static GtkWidget *s_view1_more_traces_button; +static GtkWidget *s_view1_less_traces_button; + +static GtkWidget *s_view1_hmenubox; +static GtkWidget *s_view1_hmenubox2; +static GtkWidget *s_view1_startbutton; +static GtkWidget *s_view1_zoominbutton; +static GtkWidget *s_view1_searchbutton; +static GtkWidget *s_view1_srchagainbutton; +static GtkWidget *s_view1_zoomoutbutton; +static GtkWidget *s_view1_endbutton; + +static GtkWidget *s_view1_snapbutton; +static GtkWidget *s_view1_nextbutton; +static GtkWidget *s_view1_delbutton; + +static GtkWidget *s_view1_chase_event_button; +static GtkWidget *s_view1_chase_datum_button; +static GtkWidget *s_view1_chase_track_button; +static GtkWidget *s_view1_unchasebutton; + +static GtkWidget *s_view1_forward_button; +static GtkWidget *s_view1_backward_button; + +static GtkWidget *s_view1_summary_button; +static GtkWidget *s_view1_nosummary_button; + +static GtkWidget *s_view1_hscroll; +static GtkObject *s_view1_hsadj; + +static GtkWidget *s_view1_vscroll; +static GtkObject *s_view1_vsadj; + +static GtkWidget *s_view1_label; + +/* + * Search context + */ +static ulong s_srchcode; /* search event code */ +static int s_srchindex; /* last hit was at this event index */ +static boolean s_result_up; /* The SEARCH RESULT dongle is displayed */ +static boolean s_srchfail_up; /* The status line "Search Failed" is up */ +static int srch_chase_dir; /* search/chase dir, 0=>forward */ + + +/* + * Print context + */ +static int s_print_offset; /* Magic offset added to line, tbox fn codes */ +static FILE *s_printfp; + +/* + * Forward reference prototypes + */ +static void display_pid_axis(v1_geometry_t *vp); +static void display_event_data(v1_geometry_t *vp); +static void display_time_axis(v1_geometry_t *vp); +static void view1_button_click_callback(GtkButton *item, gpointer data); + +/* + * config params + */ + +gint c_view1_draw_width; +gint c_view1_draw_height; + +/* + * Zoom-In / Time Ruler cursor + */ + +#define zi_width 32 +#define zi_height 32 +#define zi_x_hot 22 +#define zi_y_hot 14 +static unsigned char zi_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static unsigned char zi_bkgd[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x88, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x00, + 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static GdkCursor *zi_cursor; +static GdkPixmap *zi_source, *zi_mask; + +/* + * Frequently-used small computations, best + * done correctly once and instantiated. + */ + +/**************************************************************************** +* dtime_per_pixel +****************************************************************************/ + +static inline double dtime_per_pixel(v1_geometry_t *vp) +{ + return ((double)(vp->maxvistime - vp->minvistime)) / + ((double)(vp->total_width - vp->pid_ax_width)); +} + +/**************************************************************************** +* message_line +* Changes the status line. Pass "" to clear the status line. +****************************************************************************/ + +void message_line (char *s) +{ + gtk_label_set_text (GTK_LABEL(s_view1_label), s); +} + +/**************************************************************************** +* set_window_title +* Changes the window title to include the specified filename. +****************************************************************************/ + +void set_window_title (const char *filename) +{ + char title[128]; + snprintf(title, sizeof(title), "g2 (%s)", filename); + gtk_window_set_title(GTK_WINDOW(g_mainwindow), title); +} + +/**************************************************************************** +* recompute_hscrollbar +* Adjust the horizontal scrollbar's adjustment object. +* +* GtkAdjustments are really cool, but have to be set up exactly +* right or the various client objects screw up completely. +* +* Note: this function is *not* called when the user clicks the scrollbar. +****************************************************************************/ + +static void recompute_hscrollbar (void) +{ + ulonglong current_width; + ulonglong event_incdec; + GtkAdjustment *adj; + event_t *ep; + + if (g_nevents == 0) + return; + + ep = (g_events + (g_nevents-1)); + current_width = s_v1->maxvistime - s_v1->minvistime; + event_incdec = (current_width) / 6; + + adj = GTK_ADJUSTMENT(s_view1_hsadj); + + /* + * Structure member decoder ring + * ----------------------------- + * lower the minimum possible value + * value the current value + * upper the maximum possible value + * step_increment end button click increment + * page_increment click in trough increment + * page_size size of currently visible area + */ + + adj->lower = (gfloat)0.00; + adj->value = (gfloat)s_v1->minvistime; + + /* Minor click: move about 1/6 of a page */ + adj->step_increment = (gfloat)event_incdec; + + /* Major click: move about 1/3 of a page. */ + adj->page_increment = (gfloat)(2*event_incdec); + + /* allow the user to go a bit past the end */ + adj->upper = adj->page_increment/3 + (gfloat)(ep->time); + adj->page_size = (gfloat)(current_width); + + /* + * Tell all clients (e.g. the visible scrollbar) to + * make themselves look right + */ + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); +} + +/**************************************************************************** +* recompute_vscrollbar +* Ditto, for the vertical scrollbar +****************************************************************************/ + +static void recompute_vscrollbar (void) +{ + GtkAdjustment *adj; + + adj = GTK_ADJUSTMENT(s_view1_vsadj); + + adj->lower = (gfloat)0.00; + adj->upper = (gfloat)g_npids; + adj->value = (gfloat)0.00; + adj->step_increment = 1.00; + adj->page_increment = (gfloat)(s_v1->npids / 3); + adj->page_size = (gfloat)s_v1->npids; + gtk_adjustment_changed(adj); + gtk_adjustment_value_changed(adj); +} + +/**************************************************************************** +* format_popbox_string +****************************************************************************/ + +elog_main_t elog_main; + +void format_popbox_string (char *tmpbuf, int len, event_t *ep, event_def_t *edp) +{ + char *fp; + +#ifdef NOTDEF + sprintf(tmpbuf,"%d:", ep->code); +#endif + if (ep->flags & EVENT_FLAG_CLIB) { + elog_event_t *eep; + u8 *s; + + eep = get_clib_event (ep->datum); + + s = format (0, "%U", format_elog_event, &elog_main, eep); + memcpy (tmpbuf, s, vec_len(s)); + tmpbuf[vec_len(s)] = 0; + vec_free(s); + return; + } + + snprintf(tmpbuf, len, "%s", edp->name); + fp = edp->format; + /* Make sure there's a real format string. If so, add it */ + while (fp && *fp) { + if (*fp != ' ') { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), ": "); + /* %s only supported for cpel files */ + if (fp[1] == 's') { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), + edp->format, strtab_ref(ep->datum)); + } else { + snprintf(tmpbuf+strlen(tmpbuf), len - strlen(tmpbuf), + edp->format, ep->datum); + } + return; + } + fp++; + } +} + +/**************************************************************************** + * add_snapshot + ****************************************************************************/ + +static void add_snapshot(void) +{ + int i; + snapshot_t *new = g_malloc(sizeof(snapshot_t)); + + memcpy(&new->geometry, s_v1, sizeof(new->geometry)); + for (i = 0; i < NEVENTS; i++) { + new->show_event[i] = g_eventdefs[i].selected; + } + new->pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + memcpy(new->pidvec, g_pids, sizeof(pid_sort_t)*g_npids); + new->vscroll_value = GTK_ADJUSTMENT(s_view1_vsadj)->value; + new->summary_mode = summary_mode; + new->color_mode = color_mode; + + if (s_snapshots) { + new->next = s_snapshots; + s_snapshots = new; + } else { + new->next = 0; + s_snapshots = new; + } + s_cursnap = new; +} + +/**************************************************************************** + * next_snapshot + ****************************************************************************/ + +static void next_snapshot(void) +{ + snapshot_t *next; + int i; + pid_sort_t *psp; + pid_data_t *pp; + + if (!s_snapshots) { + infobox("No snapshots", "\nNo snapshots in the ring...\n"); + return; + } + + next = s_cursnap->next; + if (next == 0) + next = s_snapshots; + + s_cursnap = next; + + memcpy(s_v1, &next->geometry, sizeof(next->geometry)); + for (i = 0; i < NEVENTS; i++) { + g_eventdefs[i].selected = next->show_event[i]; + } + memcpy(g_pids, next->pidvec, sizeof(pid_sort_t)*g_npids); + color_mode = next->color_mode; + /* + * Update summary mode via a button push so that the button state is + * updated accordingly. (Should ideally clean up the view/controller + * separation properly one day.) + */ + if (summary_mode != next->summary_mode) { + view1_button_click_callback + (NULL, (gpointer)(unsigned long long) + (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); + } + + /* Fix the pid structure index mappings */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + GTK_ADJUSTMENT(s_view1_vsadj)->value = next->vscroll_value; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + recompute_hscrollbar(); + pointsel_next_snapshot(); + view1_display_when_idle(); +} + + +/**************************************************************************** + * del_snapshot + ****************************************************************************/ + +static void del_snapshot(void) +{ + snapshot_t *prev; + snapshot_t *this; + + if (!s_snapshots) { + infobox("No snapshots", "\nNo snapshots to delete...\n"); + return; + } + + prev = NULL; + this = s_snapshots; + + while (this && this != s_cursnap) { + prev = this; + this = this->next; + } + + if (this != s_cursnap) { + infobox("BUG", "\nSnapshot AWOL!\n"); + return; + } + + s_cursnap = this->next; + + /* middle of the list? */ + if (prev) { + prev->next = this->next; + g_free(this->pidvec); + g_free(this); + } else { /* start of the list */ + s_snapshots = this->next; + g_free(this->pidvec); + g_free(this); + } + + /* Note: both will be NULL after last delete */ + if (s_cursnap == NULL) + s_cursnap = s_snapshots; +} + +/**************************************************************************** + * write_snapshot + * + * VERY primitive right now - not endian or version independent, and only + * writes to "snapshots.g2" in the current directory + ****************************************************************************/ +static void write_snapshot(void) +{ + FILE *file = NULL; + snapshot_t *snap; + char *error = NULL; + int records = 0; + + if (s_snapshots == NULL) { + error = "No snapshots defined"; + errno = 0; + } + + if (!error) { + file = fopen("snapshots.g2", "w"); + if (file == NULL) { + error = "Unable to open snapshots.g2"; + } + } + + /* + * Simply serialize the arch-dependent binary data, without a care in the + * world. Don't come running to me if you try to read it and crash. + */ + for (snap = s_snapshots; !error && snap != NULL; snap = snap->next) { + if (fwrite(&snap->geometry, + sizeof(snap->geometry), 1, file) != 1 || + fwrite(&snap->show_event, + sizeof(snap->show_event), 1, file) != 1 || + fwrite(snap->pidvec, + sizeof(pid_sort_t) * g_npids, 1, file) != 1 || + fwrite(&snap->vscroll_value, + sizeof(snap->vscroll_value), 1, file) != 1 || + fwrite(&snap->summary_mode, + sizeof(snap->summary_mode), 1, file) != 1 || + fwrite(&snap->color_mode, + sizeof(snap->color_mode), 1, file) != 1) { + error = "Error writing data"; + } + records++; + } + + if (!error) { + if (fclose(file)) { + error = "Unable to close file"; + } + } + + if (error) { + infobox(error, strerror(errno)); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), "Wrote %d snapshots to snapshots.g2", + records); + message_line(buf); + } +} + +/**************************************************************************** + * read_snapshot + * + * VERY primitive right now - not endian or version independent, and only reads + * from "snapshots.g2" in the current directory + ****************************************************************************/ +static void read_snapshot(void) +{ + FILE *file; + snapshot_t *snap, *next_snap; + snapshot_t *new_snaps = NULL; + char *error = NULL; + int len, i, records = 0; + pid_data_t *pp; + + file = fopen("snapshots.g2", "r"); + if (file == NULL) { + error = "Unable to open snapshots.g2"; + } + + /* + * Read in the snapshots and link them together. We insert them backwards, + * but that's tolerable. If the data is in anyway not what we expect, we'll + * probably crash. Sorry. + */ + while (!error && !feof(file)) { + snap = g_malloc(sizeof(*snap)); + snap->pidvec = NULL; /* so we can free this if there's an error */ + + len = fread(&snap->geometry, sizeof(snap->geometry), 1, file); + if (len == 0) { + /* EOF */ + g_free(snap); + break; + } else { + /* insert into list straight away */ + snap->next = new_snaps; + new_snaps = snap; + } + if (len != 1) { + error = "Problem reading first item from file"; + break; + } + if (fread(&snap->show_event, sizeof(snap->show_event), 1, file) != 1) { + error = "Problem reading second item from file"; + break; + } + len = sizeof(pid_sort_t) * g_npids; + snap->pidvec = g_malloc(len); + if (fread(snap->pidvec, len, 1, file) != 1) { + error = "Problem reading third item from file"; + break; + } + if (fread(&snap->vscroll_value, + sizeof(snap->vscroll_value), 1, file) != 1 || + fread(&snap->summary_mode, + sizeof(snap->summary_mode), 1, file) != 1 || + fread(&snap->color_mode, + sizeof(snap->color_mode), 1, file) != 1) { + error = "Problem reading final items from file"; + break; + } + + /* + * Fix up the pointers from the sorted pid vector back into our pid + * data objects, by walking the linked list of pid_data_t objects for + * every one looking for a match. This is O(n^2) grossness, but in real + * life there aren't that many pids, and it seems zippy enough. + */ + for (i = 0; i < g_npids; i++) { + for (pp = g_pid_data_list; pp != NULL; pp = pp->next) { + if (pp->pid_value == snap->pidvec[i].pid_value) { + break; + } + } + if (pp != NULL) { + snap->pidvec[i].pid = pp; + } else { + error = "Snapshot file referenced unknown pids"; + break; + } + } + + records++; + } + + if (!error) { + if (fclose(file)) { + error = "Unable to close file"; + } + } + + if (error) { + /* + * Problem - clear up any detritus + */ + infobox(error, strerror(errno)); + for (snap = new_snaps; snap != NULL; snap = next_snap) { + next_snap = snap->next; + g_free(snap); + g_free(snap->pidvec); + } + } else { + /* + * Success! trash the old snapshots and replace with the new + */ + for (snap = s_snapshots; snap != NULL; snap = next_snap) { + next_snap = snap->next; + g_free(snap->pidvec); + g_free(snap); + } + + s_cursnap = s_snapshots = new_snaps; + } + + if (error) { + infobox(error, strerror(errno)); + } else { + char buf[64]; + snprintf(buf, sizeof(buf), + "Read %d snapshots from snapshots.g2", records); + message_line(buf); + } +} + +/**************************************************************************** +* set_color +* +* Set the color for the specified pid_index, or COLOR_DEFAULT to return it +* to the usual black. +****************************************************************************/ +#define COLOR_DEFAULT (-1) +static void set_color(int pid_index) +{ + if (pid_index == COLOR_DEFAULT || !color_mode) { + gdk_gc_set_foreground(da->style->black_gc, &fg_black); + } else { + gdk_gc_set_foreground(da->style->black_gc, + &s_color[g_pids[pid_index].color_index]); + } +} + +/**************************************************************************** +* toggle_event_select +****************************************************************************/ + +static void toggle_event_select(GdkEventButton *event, v1_geometry_t *vp) +{ + int pid_index, start_index; + int x, y; + GdkRectangle *rp; + GdkRectangle hit_rect; + GdkRectangle dummy; + event_t *ep; + event_def_t *edp; + char tmpbuf [1024]; + double time_per_pixel; + + if (g_nevents == 0) + return; + + time_per_pixel = dtime_per_pixel(vp); + + start_index = find_event_index (vp->minvistime); + + /* Too far right? */ + if (start_index >= g_nevents) + return; + + /* + * To see if the mouse hit a visible event, use a variant + * of the event display loop. + */ + + hit_rect.x = (int)event->x; + hit_rect.y = (int)event->y; + hit_rect.width = 1; + hit_rect.height = 1; + + ep = (g_events + start_index); + + while ((ep->time < vp->maxvistime) && + (ep < (g_events + g_nevents))) { + pid_index = ep->pid->pid_index; + + /* First filter: pid out of range */ + if ((pid_index < vp->first_pid_index) || + (pid_index >= vp->first_pid_index + vp->npids)) { + ep++; + continue; + } + + /* Second filter: event hidden */ + edp = find_event_definition (ep->code); + if (!edp->selected) { + ep++; + continue; + } + + /* + * At this point, we know that the point is at least on the + * screen. See if the mouse hit within the bounding box + */ + + /* + * $$$$ maybe keep looping until off the edge, + * maintain a "best hit", then declare that one the winner? + */ + + pid_index -= vp->first_pid_index; + + y = pid_index*vp->strip_height + vp->event_offset; + + x = vp->pid_ax_width + + (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); + + /* Perhaps we're trying to toggle the detail box? */ + if (ep->flags & EVENT_FLAG_SELECT) { + /* Figure out the dimensions of the detail box */ + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); + rp = tbox(tmpbuf, x, y - vp->pop_offset, TBOX_GETRECT_BOXED); + if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { + ep->flags &= ~EVENT_FLAG_SELECT; + view1_display_when_idle(); + break; + } + } + + sprintf(tmpbuf, "%ld", ep->code); + + /* Figure out the dimensions of the regular box */ + rp = tbox(tmpbuf, x, y, TBOX_GETRECT_EVENT); + + if (gdk_rectangle_intersect(rp, &hit_rect, &dummy)) { + /* we hit the rectangle. */ + if (ep->flags & EVENT_FLAG_SELECT) { + ep->flags &= ~EVENT_FLAG_SELECT; + view1_display_when_idle(); + break; + } else { + set_color(ep->pid->pid_index); + + /* It wasn't selected, so put up the detail box */ + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); + tbox(tmpbuf, x, y - vp->pop_offset, TBOX_DRAW_BOXED); + line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK); + ep->flags |= EVENT_FLAG_SELECT; + ep->flags &= ~EVENT_FLAG_SEARCHRSLT; + s_last_selected_event = ep; + } + break; + } + ep++; + } +} + +/**************************************************************************** +* move_current_track +****************************************************************************/ + +typedef enum { MOVE_TOP, MOVE_BOTTOM } move_type; + +static void move_current_track(GdkEventButton *event, + v1_geometry_t *vp, + move_type type) +{ + int i; + int pid_index; + int y, delta_y; + pid_sort_t *new_pidvec; + pid_sort_t *psp; + pid_sort_t *pold, *pnew; + pid_data_t *pp; + + if (g_nevents == 0) + return; + + /* Scan pid/track axis locations, looking for a match */ + for (i = 0; i < vp->npids; i++) { + y = i*vp->strip_height + vp->pid_ax_offset; + delta_y = y - event->y; + if (delta_y < 0) + delta_y = -delta_y; + if (delta_y < 10) { + goto found; + } + + } + infobox("NOTE", "\nNo PID/Track In Range\nPlease Try Again"); + return; + + found: + pid_index = i + vp->first_pid_index; + + new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + pold = g_pids; + pnew = new_pidvec; + + if (type == MOVE_TOP) { + /* move to top */ + *pnew++ = g_pids[pid_index]; + for (i = 0; i < pid_index; i++) + *pnew++ = *pold++; + pold++; + i++; + for (; i < g_npids; i++) + *pnew++ = *pold++; + } else { + /* move to bottom */ + for (i = 0; i < pid_index; i++) + *pnew++ = *pold++; + pold++; + i++; + for (; i < g_npids; i++) + *pnew++ = *pold++; + *pnew = g_pids[pid_index]; + } + + g_free(g_pids); + g_pids = new_pidvec; + + /* + * Revert the pid_index mapping to an identity map, + */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + view1_display_when_idle(); +} + +/**************************************************************************** +* zoom_event +* Process a zoom gesture. The use of doubles is required to avoid +* truncating the various variable values, which in turn would lead to +* some pretty random-looking zoom responses. +****************************************************************************/ + +void zoom_event(GdkEventButton *e1, GdkEventButton *e2, v1_geometry_t *vp) +{ + double xrange; + double time_per_pixel; + double width_in_pixels; + double center_on_time, width_in_time; + double center_on_pixel; + + /* + * Clip the zoom area to the event display area. + * Otherwise, center_on_time - width_in_time is in hyperspace + * to the left of zero + */ + + if (e1->x < vp->pid_ax_width) + e1->x = vp->pid_ax_width; + + if (e2->x < vp->pid_ax_width) + e2->x = vp->pid_ax_width; + + if (e2->x == e1->x) + goto loser_zoom_repaint; + + xrange = (double) (e2->x - e1->x); + if (xrange < 0.00) + xrange = -xrange; + + /* Actually, width in pixels of half the zoom area */ + width_in_pixels = xrange / 2.00; + time_per_pixel = dtime_per_pixel(vp); + width_in_time = width_in_pixels * time_per_pixel; + + /* Center the screen on the center of the zoom area */ + center_on_pixel = (double)((e2->x + e1->x) / 2.00) - + (double)vp->pid_ax_width; + center_on_time = center_on_pixel*time_per_pixel + (double)vp->minvistime; + + /* + * Transform back to 64-bit integer microseconds, reset the + * scrollbar, schedule a repaint. + */ + vp->minvistime = (ulonglong)(center_on_time - width_in_time); + vp->maxvistime = (ulonglong)(center_on_time + width_in_time); + +loser_zoom_repaint: + recompute_hscrollbar(); + + view1_display_when_idle(); +} + +/**************************************************************************** +* scroll_y +* +* Scroll up or down by the specified delta +* +****************************************************************************/ +static void scroll_y(int delta) +{ + int new_index = s_v1->first_pid_index + delta; + if (new_index + s_v1->npids > g_npids) + new_index = g_npids - s_v1->npids; + if (new_index < 0) + new_index = 0; + + if (new_index != s_v1->first_pid_index) { + s_v1->first_pid_index = new_index; + GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)new_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + view1_display_when_idle(); + } +} + +/**************************************************************************** +* view1_handle_key_press_event +* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h +* +* This routine implements hotkeys for the Quake generation: +* +* W - zoom in +* S - zoom out +* A - pan left +* D - pan right +* R - pan up +* F - pan down +* T - more traces +* G - fewer traces +* +* E - toggle summary mode +* C - toggle color mode +* +* X - take snapshot +* Z - next snapshot +* P - persist snapshots to file +* L - load snapshots from file +* +* ctrl-Q - exit +* +****************************************************************************/ +gint +view1_handle_key_press_event (GtkWidget *widget, GdkEventKey *event) +{ + long long delta; + + switch (event->keyval) { + case GDK_w: // zoom in + view1_button_click_callback(NULL, (gpointer)ZOOMIN_BUTTON); + break; + + case GDK_s: // zoom out + view1_button_click_callback(NULL, (gpointer)ZOOMOUT_BUTTON); + break; + + case GDK_a: // pan left + delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + if (s_v1->minvistime < delta) { + delta = s_v1->minvistime; + } + s_v1->minvistime -= delta; + s_v1->maxvistime -= delta; + recompute_hscrollbar(); + break; + + case GDK_d: // pan right + delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + if (s_v1->maxvistime + delta > g_events[g_nevents - 1].time) { + /* + * @@@ this doesn't seem to quite reach the far right hand + * side correctly - not sure why. + */ + delta = g_events[g_nevents - 1].time - s_v1->maxvistime; + } + s_v1->minvistime += delta; + s_v1->maxvistime += delta; + recompute_hscrollbar(); + break; + + case GDK_r: // pan up + scroll_y(-1); + break; + + case GDK_f: // pan down + scroll_y(+1); + break; + + case GDK_t: // fewer tracks + view1_button_click_callback(NULL, (gpointer)LESS_TRACES_BUTTON); + break; + + case GDK_g: // more tracks + view1_button_click_callback(NULL, (gpointer)MORE_TRACES_BUTTON); + break; + + case GDK_e: // toggle summary mode + view1_button_click_callback + (NULL, (gpointer)(unsigned long long) + (summary_mode ? NOSUMMARY_BUTTON : SUMMARY_BUTTON)); + break; + + case GDK_c: // toggle color mode + color_mode ^= 1; + view1_display_when_idle(); + break; + + case GDK_p: // persist snapshots + write_snapshot(); + break; + + case GDK_l: // load snapshots + read_snapshot(); + break; + + case GDK_x: // take snapshot + view1_button_click_callback(NULL, (gpointer)SNAP_BUTTON); + break; + + case GDK_z: // next snapshot + view1_button_click_callback(NULL, (gpointer)NEXT_BUTTON); + break; + + case GDK_q: // ctrl-q is exit + if (event->state & GDK_CONTROL_MASK) { + gtk_main_quit(); + } + break; + } + return TRUE; +} + +/**************************************************************************** +* button_press_event +* Relevant definitions in: /usr/include/gtk-1.2/gdk/gdktypes.h +* +* This routine implements three functions: zoom-to-area, time ruler, and +* show/hide event detail popup. +* +* The left mouse button (button 1) has two simultaneous functions: event +* detail popup, and zoom-to-area. If the press and release events occur +* within a small delta-x, it's a detail popup event. Otherwise, it's +* an area zoom. +* +* The right mouse button (button 3) implements the time ruler. +****************************************************************************/ + +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + static GdkEventButton press1_event; + static boolean press1_valid; + static GdkEventButton press3_event; + static guint32 last_truler_time; + static boolean press3_valid; + static boolean zoom_bar_up; + int time_ax_y, xdelta; + char tmpbuf [128]; + double time_per_pixel; + + time_ax_y = 0; + + switch(event->type) { + case GDK_BUTTON_PRESS: + /* Capture the appropriate starting point */ + if (event->button == 1) { + press1_valid = TRUE; + press1_event = *event; + return(TRUE); + } + if (event->button == 3) { + press3_valid = TRUE; + press3_event = *event; + return(TRUE); + } + return(TRUE); + + case GDK_BUTTON_RELEASE: + /* Time ruler */ + if (press3_valid) { + press3_valid = FALSE; + /* Fix the cursor, and repaint the screen from scratch */ + gdk_window_set_cursor (da->window, norm_cursor); + view1_display_when_idle(); + return(TRUE); + } + /* Event select / zoom-to-area */ + if (press1_valid) { + press1_valid = FALSE; + xdelta = (int)(press1_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + /* is the mouse more or less where it started? */ + if (xdelta < 10) { + /* Control-left-mouse => sink the track */ + /* Shift-left-mouse => raise the track */ + if ((press1_event.state & GDK_CONTROL_MASK) == + GDK_CONTROL_MASK) { + move_current_track(event, s_v1, MOVE_BOTTOM); + } else if ((press1_event.state & GDK_SHIFT_MASK) == + GDK_SHIFT_MASK) { + move_current_track(event, s_v1, MOVE_TOP); + } else { + /* No modifiers: toggle the event */ + toggle_event_select(event, s_v1); + } + /* Repaint to get rid of the zoom bar */ + if (zoom_bar_up) { + /* Fix the cursor and leave. No zoom */ + gdk_window_set_cursor (da->window, norm_cursor); + zoom_bar_up = FALSE; + break; + } + } else { /* mouse moved enough to zoom */ + zoom_event(&press1_event, event, s_v1); + gdk_window_set_cursor (da->window, norm_cursor); + zoom_bar_up = FALSE; + } + } else if (event->button == 4) { + /* scroll wheel up */ + scroll_y(event->state & GDK_SHIFT_MASK ? -10 : -1); + } else if (event->button == 5) { + /* scroll wheel down */ + scroll_y(event->state & GDK_SHIFT_MASK ? +10 : +1); + } + return(TRUE); + + case GDK_MOTION_NOTIFY: + /* Button one followed by motion: draw zoom fence and fix cursor */ + if (press1_valid) { + /* Fence, cursor already set */ + if (zoom_bar_up) + return(TRUE); + + xdelta = (int)(press1_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + /* Haven't moved enough to declare a zoom sequence yet */ + if (xdelta < 10) + return(TRUE); + + /* Draw the zoom fence, use the key-down X coordinate */ + time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; + + line((int)(press1_event.x), s_v1->pop_offset, + (int)(press1_event.x), time_ax_y, LINE_DRAW_BLACK); + tbox("Zoom From Here...", (int)(press1_event.x), s_v1->pop_offset, + TBOX_DRAW_BOXED); + gdk_window_set_cursor(da->window, zi_cursor); + zoom_bar_up = TRUE; + return(TRUE); + } + if (press3_valid) { + double nsec; + + gdk_window_set_cursor(da->window, zi_cursor); + + /* + * Some filtration is needed on Solaris, or the server will hang + */ + if (event->time - last_truler_time < 75) + return(TRUE); + + last_truler_time = event->time; + + line((int)(press3_event.x), s_v1->pop_offset, + (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); + + xdelta = (int)(press3_event.x - event->x); + if (xdelta < 0) + xdelta = -xdelta; + + time_per_pixel = ((double)(s_v1->maxvistime - s_v1->minvistime)) / + ((double)(s_v1->total_width - s_v1->pid_ax_width)); + + time_ax_y = s_v1->npids * s_v1->strip_height + s_v1->pid_ax_offset; + + line((int)(press3_event.x), s_v1->pop_offset, + (int)(press3_event.x), time_ax_y, LINE_DRAW_BLACK); + /* + * Note: use a fixed-width format so it looks like we're + * erasing and redrawing the box. + */ + nsec = ((double)xdelta)*time_per_pixel; + if (nsec >1e9) { + sprintf(tmpbuf, "%8.3f sec ", nsec/1e9); + } else if (nsec > 1e6) { + sprintf(tmpbuf, "%8.3f msec", nsec/1e6); + } else if (nsec > 1e3) { + sprintf(tmpbuf, "%8.3f usec", nsec/1e3); + } else { + sprintf(tmpbuf, "%8.0f nsec", nsec); + } + tbox(tmpbuf, (int)(press3_event.x), s_v1->pop_offset, + TBOX_DRAW_BOXED); + return(TRUE); + } + + default: + break; +#ifdef DEBUG + g_print("button:\ttype = %d\n", event->type); + g_print("\twindow = 0x%x\n", event->window); + g_print("\tsend_event = %d\n", event->send_event); + g_print("\ttime = %d\n", event->time); + g_print("\tx = %6.2f\n", event->x); + g_print("\ty = %6.2f\n", event->y); + g_print("\tpressure = %6.2f\n", event->pressure); + g_print("\txtilt = %6.2f\n", event->xtilt); + g_print("\tytilt = %6.2f\n", event->ytilt); + g_print("\tstate = %d\n", event->state); + g_print("\tbutton = %d\n", event->button); + g_print("\tsource = %d\n", event->source); + g_print("\tdeviceid = %d\n", event->deviceid); + g_print("\tx_root = %6.2f\n", event->x_root); + g_print("\ty_root = %6.2f\n", event->y_root); + return(TRUE); +#endif + } + + view1_display_when_idle(); + + return(TRUE); +} + +/**************************************************************************** +* configure_event +* Happens when the window manager resizes the viewer's main window. +****************************************************************************/ + +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + /* Toss the previous drawing area backing store pixmap */ + if (pm) + gdk_pixmap_unref(pm); + + /* Create a new pixmap, paint it */ + pm = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pm, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + /* Reset the view geometry parameters, as required */ + s_v1->total_width = widget->allocation.width; + s_v1->total_height = widget->allocation.height; + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + + /* Schedule a repaint */ + view1_display_when_idle(); + return(TRUE); +} + +/**************************************************************************** +* expose_event +* Use backing store to fix the screen. +****************************************************************************/ +static gint expose_event (GtkWidget *widget, GdkEventExpose *event) +{ + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pm, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return(FALSE); +} + +/**************************************************************************** +* event_search_internal +* This routine searches forward from s_srchindex, looking for s_srchcode; +* wraps at the end of the buffer. +****************************************************************************/ + +boolean event_search_internal (void) +{ + event_t *ep; + int i; + int index; + int pid_index; + boolean full_redisplay = FALSE; + ulonglong current_width; + char tmpbuf [64]; + + /* No events yet? Act like the search worked, to avoid a loop */ + if (g_nevents == 0) + return(TRUE); + + ep = (g_events + s_srchindex); + ep->flags &= ~EVENT_FLAG_SEARCHRSLT; + + /* + * Assume the user wants to search [plus or minus] + * from where they are. + */ +#ifdef notdef + if (ep->time < s_v1->minvistime) + s_srchindex = find_event_index (s_v1->minvistime); +#endif + + for (i = 1; i <= g_nevents; i++) { + index = (srch_chase_dir == SRCH_CHASE_BACKWARD) ? + (s_srchindex - i) % g_nevents : + (i + s_srchindex) % g_nevents; + + ep = (g_events + index); + + if (ep->code == s_srchcode) { + if (s_srchfail_up) + message_line(""); + s_srchindex = index; + pid_index = ep->pid->pid_index; + + /* Need a vertical scroll? */ + if ((pid_index < s_v1->first_pid_index) || + (pid_index >= s_v1->first_pid_index + s_v1->npids)) { + if (pid_index > (g_npids - s_v1->npids)) + pid_index = (g_npids - s_v1->npids); + s_v1->first_pid_index = pid_index; + GTK_ADJUSTMENT(s_view1_vsadj)->value = + (gdouble)s_v1->first_pid_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + full_redisplay = TRUE; + } + + /* Need a horizontal scroll? */ + if (ep->time < s_v1->minvistime || ep->time > s_v1->maxvistime) { + current_width = (s_v1->maxvistime - s_v1->minvistime); + if (ep->time < ((current_width+1) / 2)) { + s_v1->minvistime = 0ll; + s_v1->maxvistime = current_width; + } else { + s_v1->minvistime = ep->time - ((current_width+1)/2); + s_v1->maxvistime = ep->time + ((current_width+1)/2); + } + recompute_hscrollbar(); + full_redisplay = TRUE; + } + ep->flags |= EVENT_FLAG_SEARCHRSLT; + full_redisplay = TRUE; + +#ifdef NOTDEF + if (!full_redisplay){ + if (!s_result_up) { + s_result_up = TRUE; + time_per_pixel = dtime_per_pixel(s_v1); + + y = pid_index*s_v1->strip_height + s_v1->event_offset; + x = s_v1->pid_ax_width + + (int)(((double)(ep->time - s_v1->minvistime)) / + time_per_pixel); + sprintf(tmpbuf, "SEARCH RESULT"); + tbox(tmpbuf, x, y - s_v1->pop_offset, TBOX_DRAW_BOXED); + line(x, y-s_v1->pop_offset, x, y, LINE_DRAW_BLACK); + } else { + full_redisplay = TRUE; + } + } +#endif + + if (full_redisplay) + view1_display_when_idle(); + return(TRUE); + } + } + sprintf (tmpbuf, "Search for event %ld failed...\n", s_srchcode); + message_line(tmpbuf); + s_srchfail_up = TRUE; + return(TRUE); +} + +/**************************************************************************** +* event_search_callback +****************************************************************************/ + +boolean event_search_callback (char *s) +{ + /* No events yet? Act like the search worked, to avoid a loop */ + if (g_nevents == 0) + return(TRUE); + + s_srchcode = atol(s); + + if (s_srchcode == 0) + return(FALSE); + + return(event_search_internal()); +} + +/**************************************************************************** +* event_search +****************************************************************************/ + +static void event_search (void) +{ + modal_dialog ("Event Search: Please Enter Event Code", + "Invalid: Please Reenter Event Code", NULL, + event_search_callback); +} + +/**************************************************************************** +* init_track_colors +****************************************************************************/ +static void init_track_colors(void) +{ + int i; + unsigned hash; + char *label_char; + unsigned RGB[3]; + gboolean dont_care[g_npids]; + + /* + * If we've already allocated the colors once, then in theory we should + * just be able to re-order the GCs already created to match the new track + * order; the track -> color mapping doesn't currently change at runtime. + * However, it's easier just to allocate everything from fresh. As a nod in + * the direction of politeness towards our poor abused X server, we at + * least mop up the previously allocated GCs first, although in practice + * even omitting this didn't seem to cause a problem. + */ + if (s_color != NULL ) { + gdk_colormap_free_colors(gtk_widget_get_colormap(da), + s_color, g_npids); + memset(s_color, 0, sizeof(GdkColor) * g_npids); + } else { + /* + * First time through: allocate the array to hold the GCs. + */ + s_color = g_malloc(sizeof(GdkColor) * g_npids); + } + + /* + * Go through and assign a color for each track. + */ + for (i = 0; i < g_npids; i++) { + /* + * We compute the color from a hash of the thread name. That way we get + * a distribution of different colors, and the same thread has the same + * color across multiple data sets. Unfortunately, even though the + * process name and thread id are invariant across data sets, the + * process id isn't, so we want to exclude that from the hash. Since + * the pid appears in parentheses after the process name and tid, we + * can just stop at the '(' character. + * + * We could create a substring and use the CLIB Jenkins hash, but given + * we're hashing ascii data, a suitable Bernstein hash is pretty much + * just as good, and it's easiest just to compute it inline. + */ + label_char = get_track_label(g_pids[i].pid_value); + hash = 0; + while (*label_char != '\0' && *label_char != '(') { + hash = hash * 33 + *label_char++; + } + hash += hash >> 5; /* even out the lower order bits a touch */ + + /* + * OK, now we have our hash. We get the color by using the first three + * bytes of the hash for the RGB values (expanded from 8 to 16 bits), + * and then use the fourth byte to choose one of R, G, B and mask this + * one down. This ensures the color can't be too close to white and + * therefore hard to see. + * + * We also drop the top bit of the green, since bright green on its own + * is hard to see against white. Generally we err on the side of + * keeping it dark, rather than using the full spectrum of colors. This + * does result in something of a preponderance of muddy colors and a + * bit of a lack of cheery bright ones, but at least you can read + * everything. It would be nice to do better. + */ + RGB[0] = (hash & 0xff000000) >> 16; + RGB[1] = (hash & 0x007f0000) >> 8; + RGB[2] = (hash & 0x0000ff00); + RGB[hash % 3] &= 0x1fff; + + { + GdkColor color = {0, RGB[0], RGB[1], RGB[2]}; + s_color[i] = color; + g_pids[i].color_index = i; + } + } + + /* + * Actually allocate the colors in one bulk operation. We ignore the return + * values. + */ + gdk_colormap_alloc_colors(gtk_widget_get_colormap(da), + s_color, g_npids, FALSE, TRUE, dont_care); +} + + +/**************************************************************************** +* chase_event_etc +* Reorder the pid_index fields so the viewer "chases" the last selected +* event. +****************************************************************************/ + +static void chase_event_etc(enum chase_mode mode) +{ + pid_sort_t *psp, *new_pidvec; + pid_data_t *pp; + event_t *ep; + int pids_mapped; + ulong code_to_chase; + ulong datum_to_chase; + ulong pid_to_chase; + int i; + int winner; + + if (!s_last_selected_event) { + infobox("No selected event", + "\nPlease select an event and try again...\n"); + return; + } + + /* Clear all index assignments */ + psp = g_pids; + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = 0xFFFFFFFF; + psp++; + } + + ep = s_last_selected_event; + code_to_chase = ep->code; + datum_to_chase = ep->datum; + pid_to_chase = ep->pid->pid_value; + pids_mapped = 0; + new_pidvec = g_malloc(sizeof(pid_sort_t)*g_npids); + + while (1) { + if (srch_chase_dir == SRCH_CHASE_FORWARD) { + if (ep >= g_events + g_nevents) + break; + } else { + if (ep < g_events) + break; + } + + winner = 0; + switch(mode) { + case CHASE_EVENT: + if (ep->code == code_to_chase) { + winner = 1; + } + break; + + case CHASE_DATUM: + if (ep->datum == datum_to_chase) { + winner = 1; + } + break; + + case CHASE_TRACK: + if (ep->pid->pid_value == pid_to_chase) { + winner = 1; + } + break; + + default: + infobox("BUG", "unknown mode in chase_event_etc\n"); + break; + } + + if (winner) { + if (ep->pid->pid_index == 0xFFFFFFFF) { + ep->pid->pid_index = pids_mapped; + new_pidvec[pids_mapped].pid = ep->pid; + new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; + new_pidvec[pids_mapped].color_index = 0; + pids_mapped++; + if (pids_mapped == g_npids) + break; + } + } + if (srch_chase_dir == SRCH_CHASE_FORWARD) + ep++; + else + ep--; + } + + /* Pass 2, first-to-last, to collect stragglers */ + ep = g_events; + + while (ep < g_events + g_nevents) { + if (ep->pid->pid_index == 0xFFFFFFFF) { + ep->pid->pid_index = pids_mapped; + new_pidvec[pids_mapped].pid = ep->pid; + new_pidvec[pids_mapped].pid_value = ep->pid->pid_value; + new_pidvec[pids_mapped].color_index = 0; + pids_mapped++; + if (pids_mapped == g_npids) + break; + } + ep++; + } + + if (pids_mapped != g_npids) { + infobox("BUG", "\nDidn't map all pids in chase_event_etc\n"); + } + + g_free (g_pids); + g_pids = new_pidvec; + + /* + * The new g_pids vector contains the "chase" sort, so we revert + * the pid_index mapping to an identity map + */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + + /* AutoScroll the PID axis so we show the first "chased" event */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + init_track_colors(); + view1_display_when_idle(); +} + +/**************************************************************************** +* unchase_event_etc +* Copy g_original_pids to g_pids, revert index mapping +****************************************************************************/ +static void unchase_event_etc(void) +{ + int i; + pid_sort_t *psp; + pid_data_t *pp; + + memcpy (g_pids, g_original_pids, sizeof(pid_sort_t)*g_npids); + + /* Fix the pid structure index mappings */ + psp = g_pids; + + for (i = 0; i < g_npids; i++) { + pp = psp->pid; + pp->pid_index = i; + psp++; + } + + /* Scroll PID axis to the top */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + init_track_colors(); + view1_display_when_idle(); +} + +/**************************************************************************** +* print_ps_header +* To fit a reasonable-sized landscape mode plot onto letter-size paper, +* scale everything by .75. +****************************************************************************/ + +static void print_ps_header (v1_geometry_t *vp, char *filename) +{ + time_t now; + + now = time(0); + + fprintf(s_printfp, "%%%%!PS-Adobe-3.0 EPSF-3.0\n"); + fprintf(s_printfp, "%%%%Creator: G2 Event Viewer\n"); + fprintf(s_printfp, "%%%%Title: %s\n", filename); + fprintf(s_printfp, "%%%%CreationDate: %s", ctime(&now)); + fprintf(s_printfp, "%%%%DocumentData: Clean7Bit\n"); + fprintf(s_printfp, "%%%%Origin: 0 0\n"); + fprintf(s_printfp, "%%%%BoundingBox: 0 0 %d %d\n", vp->total_height, + vp->total_width); + fprintf(s_printfp, "%%%%LanguageLevel: 2\n"); + fprintf(s_printfp, "%%%%Pages: 1\n"); + fprintf(s_printfp, "%%%%Page: 1 1\n"); + fprintf(s_printfp, "%%%%EOF\n"); + fprintf(s_printfp, "/Times-Roman findfont\n"); + fprintf(s_printfp, "12 scalefont\n"); + fprintf(s_printfp, "setfont\n"); + fprintf(s_printfp, ".75 .75 scale\n"); +} + +/**************************************************************************** +* xrt +* Xcoordinate rotate and translate. We need to emit postscript that +* has a reasonable aspect ratio for printing. To do that, we rotate the +* intended picture by 90 degrees, using the standard 2D rotation +* formula: +* +* Xr = x*cos(theta) - y*sin(theta); +* Yr = x*sin(theta) + y*cos(theta); +* +* If we let theta = 90, this reduces to +* Xr = -y +* Yr = x +* +* Translate back to the origin in X by adding Ymax, yielding +* Xrt = Ymax - y +****************************************************************************/ + +static inline int xrt(int x, int y) +{ + return (s_v1->total_height - y); +} + +static inline int yrt(int x, int y) +{ + return(x); +} + +/**************************************************************************** +* print_screen_callback +****************************************************************************/ + +static boolean print_screen_callback(char *filename) +{ + s_printfp = fopen (filename, "wt"); + + if (s_printfp == NULL) + return(FALSE); + + /* + * This variable allows us to magically turn the view1 display + * code into a print-driver, with a minimum of fuss. The idea is to + * magically change TBOX_DRAW_XXX into TBOX_PRINT_XXX by adding + * the required value, aka s_print_offset. + * Make sure to fix g2.h if you mess here, or vice versa. + */ + s_print_offset = TBOX_PRINT_PLAIN - TBOX_DRAW_PLAIN; + + print_ps_header(s_v1, filename); + + display_pid_axis(s_v1); + display_event_data(s_v1); + display_time_axis(s_v1); + + fclose (s_printfp); + s_printfp = 0; + s_print_offset = 0; + + /* For tactile feedback */ + view1_display_when_idle(); + return(TRUE); +} + +/**************************************************************************** +* view1_button_click_callback +****************************************************************************/ + +static void view1_button_click_callback(GtkButton *item, gpointer data) +{ + enum view1_button_click click = (enum view1_button_click) data; + event_t *ep; + ulonglong event_incdec; + ulonglong current_width; + ulonglong zoom_delta; + + + current_width = s_v1->maxvistime - s_v1->minvistime; + event_incdec = (current_width) / 3; + + if (event_incdec == 0LL) + event_incdec = 1; + + zoom_delta = (s_v1->maxvistime - s_v1->minvistime) / 6; + + switch(click) { + case TOP_BUTTON: + /* First PID to top of window */ + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = 0.00; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + break; + + case BOTTOM_BUTTON: + s_v1->first_pid_index = g_npids - s_v1->npids; + if (s_v1->first_pid_index < 0) + s_v1->first_pid_index = 0; + GTK_ADJUSTMENT(s_view1_vsadj)->value = (gdouble)s_v1->first_pid_index; + gtk_adjustment_value_changed(GTK_ADJUSTMENT(s_view1_vsadj)); + break; + + case SNAP_BUTTON: + add_snapshot(); + break; + + case NEXT_BUTTON: + next_snapshot(); + break; + + case DEL_BUTTON: + del_snapshot(); + break; + + case CHASE_EVENT_BUTTON: + chase_event_etc(CHASE_EVENT); + break; + + case CHASE_DATUM_BUTTON: + chase_event_etc(CHASE_DATUM); + break; + + case CHASE_TRACK_BUTTON: + chase_event_etc(CHASE_TRACK); + break; + + case UNCHASE_BUTTON: + unchase_event_etc(); + break; + + case START_BUTTON: + start_button: + s_v1->minvistime = 0LL; + s_v1->maxvistime = current_width; + recompute_hscrollbar(); + break; + + case ZOOMIN_BUTTON: + s_v1->minvistime += zoom_delta; + s_v1->maxvistime -= zoom_delta; + recompute_hscrollbar(); + break; + + case SEARCH_AGAIN_BUTTON: + if (s_srchcode) { + event_search_internal(); + break; + } + /* NOTE FALLTHROUGH */ + + case SEARCH_BUTTON: + event_search(); + break; + + case ZOOMOUT_BUTTON: + if (zoom_delta == 0LL) + zoom_delta = 1; + + if (s_v1->minvistime >= zoom_delta) { + s_v1->minvistime -= zoom_delta; + s_v1->maxvistime += zoom_delta; + } else { + s_v1->minvistime = 0; + s_v1->maxvistime += zoom_delta*2; + } + + if ((s_v1->maxvistime - s_v1->minvistime) * 8 > + g_events[g_nevents-1].time * 9) { + s_v1->minvistime = 0; + s_v1->maxvistime = g_events[g_nevents-1].time * 9 / 8; + } + recompute_hscrollbar(); + break; + + case END_BUTTON: + ep = (g_events + g_nevents - 1); + s_v1->maxvistime = ep->time + event_incdec/3; + s_v1->minvistime = s_v1->maxvistime - current_width; + if (s_v1->minvistime > s_v1->maxvistime) + goto start_button; + recompute_hscrollbar(); + break; + + case MORE_TRACES_BUTTON: + /* Reduce the strip height to fit more traces on screen */ + s_v1->strip_height -= 1; + + if (s_v1->strip_height < 1) { + s_v1->strip_height = 1; + } + + /* Recalculate the number of strips on the screen */ + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + recompute_vscrollbar(); + break; + + case LESS_TRACES_BUTTON: + /* Increase the strip height to fit fewer on the screen */ + s_v1->strip_height += 1; + if (s_v1->strip_height > 80) { + s_v1->strip_height = 80; + } + + /* Recalculate the number of strips on the screen */ + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + recompute_vscrollbar(); + break; + + case FORWARD_BUTTON: + srch_chase_dir = SRCH_CHASE_FORWARD; + gtk_widget_hide (s_view1_forward_button); + gtk_widget_show (s_view1_backward_button); + break; + + case BACKWARD_BUTTON: + srch_chase_dir = SRCH_CHASE_BACKWARD; + gtk_widget_show (s_view1_forward_button); + gtk_widget_hide (s_view1_backward_button); + break; + + case SUMMARY_BUTTON: + summary_mode = TRUE; + gtk_widget_hide (s_view1_summary_button); + gtk_widget_show (s_view1_nosummary_button); + break; + + case NOSUMMARY_BUTTON: + summary_mode = FALSE; + gtk_widget_show (s_view1_summary_button); + gtk_widget_hide (s_view1_nosummary_button); + break; + } + + view1_display_when_idle(); +} + +/**************************************************************************** +* view1_print_callback +****************************************************************************/ + +void view1_print_callback (GtkToggleButton *notused, gpointer nu2) +{ + modal_dialog("Print Screen (PostScript format) to file:", + "Invalid file: Print Screen to file:", + "g2.ps", print_screen_callback); +} + +/**************************************************************************** +* view1_hscroll +****************************************************************************/ + +static void view1_hscroll (GtkAdjustment *adj, GtkWidget *notused) +{ + ulonglong current_width; + + current_width = (s_v1->maxvistime - s_v1->minvistime); + + s_v1->minvistime = (ulonglong)(adj->value); + s_v1->maxvistime = s_v1->minvistime + current_width; + + view1_display_when_idle(); + +#ifdef NOTDEF + g_print ("adj->lower = %.2f\n", adj->lower); + g_print ("adj->upper = %.2f\n", adj->upper); + g_print ("adj->value = %.2f\n", adj->value); + g_print ("adj->step_increment = %.2f\n", adj->step_increment); + g_print ("adj->page_increment = %.2f\n", adj->page_increment); + g_print ("adj->page_size = %.2f\n", adj->page_size); +#endif +} + +/**************************************************************************** +* view1_vscroll +****************************************************************************/ + +static void view1_vscroll (GtkAdjustment *adj, GtkWidget *notused) +{ + s_v1->first_pid_index = (int)adj->value; + view1_display_when_idle(); +} + +void set_pid_ax_width(int width) +{ + s_v1->pid_ax_width = width; + view1_display_when_idle(); +} + +/**************************************************************************** +* view1_init +****************************************************************************/ + +void view1_init(void) +{ + + c_view1_draw_width = atol(getprop_default("drawbox_width", "700")); + c_view1_draw_height = atol(getprop_default("drawbox_height", "400")); + + s_v1->pid_ax_width = 80; + s_v1->time_ax_height = 80; + s_v1->time_ax_spacing = 100; + s_v1->strip_height = 25; + s_v1->pop_offset = 20; + s_v1->pid_ax_offset = 34; + s_v1->event_offset = 40; + s_v1->total_height = c_view1_draw_height; + s_v1->total_width = c_view1_draw_width; + s_v1->first_pid_index = 0; + + s_v1->npids = (s_v1->total_height - s_v1->time_ax_height) / + s_v1->strip_height; + + s_v1->minvistime = 0; + s_v1->maxvistime = 200; + + s_view1_vbox = gtk_vbox_new(FALSE, 5); + + s_view1_hbox = gtk_hbox_new(FALSE, 5); + + da = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(da), c_view1_draw_width, + c_view1_draw_height); + +#ifdef NOTDEF + gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); +#endif + + gtk_signal_connect (GTK_OBJECT (da), "expose_event", + (GtkSignalFunc) expose_event, NULL); + + gtk_signal_connect (GTK_OBJECT(da),"configure_event", + (GtkSignalFunc) configure_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "button_release_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_signal_connect (GTK_OBJECT (da), "motion_notify_event", + (GtkSignalFunc) button_press_event, NULL); + + gtk_widget_set_events (da, GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK + | GDK_BUTTON_MOTION_MASK); + + + gtk_box_pack_start(GTK_BOX(s_view1_hbox), da, TRUE, TRUE, 0); + + g_font = gdk_font_load ("8x13"); + if (g_font == NULL) { + g_error("Couldn't load 8x13 font...\n"); + } + gdk_font_ref(g_font); + + /* PID axis menu */ + s_view1_vmenubox = gtk_vbox_new(FALSE, 5); + + s_view1_vsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_view1_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_view1_vsadj)); + + gtk_signal_connect (GTK_OBJECT (s_view1_vsadj), "value-changed", + GTK_SIGNAL_FUNC (view1_vscroll), + (gpointer)s_view1_vscroll); + + s_view1_topbutton = gtk_button_new_with_label("Top"); + s_view1_bottombutton = gtk_button_new_with_label("Bottom"); + + gtk_signal_connect (GTK_OBJECT(s_view1_topbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) TOP_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_bottombutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) BOTTOM_BUTTON); + + /* More Traces button and Less Traces button */ + s_view1_more_traces_button = gtk_button_new_with_label("More Traces"); + s_view1_less_traces_button = gtk_button_new_with_label("Less Traces"); + gtk_signal_connect (GTK_OBJECT(s_view1_more_traces_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) MORE_TRACES_BUTTON); + gtk_signal_connect (GTK_OBJECT(s_view1_less_traces_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) LESS_TRACES_BUTTON); + +#ifdef NOTDEF + /* Trick to bottom-justify the menu: */ + s_view1_pad1 = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_pad1, + TRUE, FALSE, 0); + +#endif + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_topbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_vscroll, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_bottombutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_more_traces_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vmenubox), s_view1_less_traces_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hbox), s_view1_vmenubox, + FALSE, FALSE, 0); + + /* Time axis menu */ + + s_view1_hmenubox = gtk_hbox_new(FALSE, 5); + + s_view1_startbutton = gtk_button_new_with_label("Start"); + + s_view1_zoominbutton = gtk_button_new_with_label("ZoomIn"); + + s_view1_searchbutton = gtk_button_new_with_label("Search"); + + s_view1_srchagainbutton = gtk_button_new_with_label("Search Again"); + + s_view1_zoomoutbutton = gtk_button_new_with_label("ZoomOut"); + + s_view1_endbutton = gtk_button_new_with_label("End"); + + gtk_signal_connect (GTK_OBJECT(s_view1_startbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) START_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_zoominbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) ZOOMIN_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_searchbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SEARCH_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_srchagainbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SEARCH_AGAIN_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_zoomoutbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) ZOOMOUT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_endbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) END_BUTTON); + + s_view1_hsadj = gtk_adjustment_new(0.0 /* initial value */, + 0.0 /* minimum value */, + 2000.0 /* maximum value */, + 0.1 /* step increment */, + 10.0/* page increment */, + 10.0/* page size */); + + s_view1_hscroll = gtk_hscrollbar_new (GTK_ADJUSTMENT(s_view1_hsadj)); + + gtk_signal_connect (GTK_OBJECT (s_view1_hsadj), "value-changed", + GTK_SIGNAL_FUNC (view1_hscroll), + (gpointer)s_view1_hscroll); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_startbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_hscroll, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_endbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoominbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_searchbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_srchagainbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox), s_view1_zoomoutbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hbox, + TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox, + FALSE, FALSE, 0); + + + s_view1_hmenubox2 = gtk_hbox_new(FALSE, 5); + + s_view1_snapbutton = gtk_button_new_with_label("Snap"); + + s_view1_nextbutton = gtk_button_new_with_label("Next"); + + s_view1_delbutton = gtk_button_new_with_label("Del"); + + s_view1_chase_event_button = gtk_button_new_with_label("ChaseEvent"); + + s_view1_chase_datum_button = gtk_button_new_with_label("ChaseDatum"); + + s_view1_chase_track_button = gtk_button_new_with_label("ChaseTrack"); + + s_view1_unchasebutton = gtk_button_new_with_label("NoChase"); + + s_view1_forward_button = gtk_button_new_with_label("->SrchChase(is<-)"); + s_view1_backward_button = gtk_button_new_with_label("<-SrchChase(is->)"); + + s_view1_summary_button = gtk_button_new_with_label("Summary"); + s_view1_nosummary_button = gtk_button_new_with_label("NoSummary"); + + gtk_signal_connect (GTK_OBJECT(s_view1_snapbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SNAP_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_nextbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) NEXT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_delbutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) DEL_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_event_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_EVENT_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_datum_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_DATUM_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_chase_track_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) CHASE_TRACK_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_unchasebutton), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) UNCHASE_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_forward_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) FORWARD_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_backward_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) BACKWARD_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_summary_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) SUMMARY_BUTTON); + + gtk_signal_connect (GTK_OBJECT(s_view1_nosummary_button), "clicked", + GTK_SIGNAL_FUNC(view1_button_click_callback), + (gpointer) NOSUMMARY_BUTTON); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_hmenubox2, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_snapbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nextbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_delbutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_event_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_datum_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_chase_track_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_unchasebutton, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_forward_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_backward_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_summary_button, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(s_view1_hmenubox2), s_view1_nosummary_button, + FALSE, FALSE, 0); + + s_view1_label = gtk_label_new(NULL); + + gtk_box_pack_start (GTK_BOX(s_view1_vbox), s_view1_label, + FALSE, FALSE, 0); + + gtk_box_pack_start (GTK_BOX(g_mainhbox), s_view1_vbox, + TRUE, TRUE, 0); + + gtk_widget_show_all (s_view1_vbox); + GTK_WIDGET_SET_FLAGS(da, GTK_CAN_FOCUS); + gtk_widget_grab_focus(da); + + gtk_widget_hide (s_view1_forward_button); + gtk_widget_hide (summary_mode ? s_view1_summary_button + : s_view1_nosummary_button); + + zi_source = gdk_bitmap_create_from_data (NULL, (char *)zi_bits, zi_width, + zi_height); + zi_mask = gdk_bitmap_create_from_data (NULL, (char *)zi_bkgd, zi_width, + zi_height); + + zi_cursor = (GdkCursor *) gdk_cursor_new_from_pixmap (zi_source, + zi_mask, &fg_black, + &bg_white, zi_x_hot, + zi_y_hot); + gdk_pixmap_unref (zi_source); + gdk_pixmap_unref (zi_mask); + + norm_cursor = (GdkCursor *) gdk_cursor_new (GDK_TOP_LEFT_ARROW); +} + +/**************************************************************************** +* line_print +****************************************************************************/ + +void line_print (int x1, int y1, int x2, int y2) +{ + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "%d %d moveto\n", xrt(x1, s_v1->total_height - y1), + yrt(x1, s_v1->total_height - y1)); + + fprintf(s_printfp, "%d %d lineto\n", xrt (x2, s_v1->total_height - y2), + yrt (x2, s_v1->total_height - y2)); + fprintf(s_printfp, "1 setlinewidth\n"); + fprintf(s_printfp, "stroke\n"); +} + +/**************************************************************************** +* tbox_print +****************************************************************************/ +GdkRectangle *tbox_print (char *s, int x, int y, enum view1_tbox_fn function, + GdkRectangle *rp) +{ + if (function == TBOX_PRINT_BOXED) { + rp->width -= 4; + } + + if ((function == TBOX_PRINT_BOXED) || + (function == TBOX_PRINT_EVENT)) { + + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "0 setlinewidth\n"); + fprintf(s_printfp, "%d %d moveto\n", + xrt(rp->x, s_v1->total_height - rp->y), + yrt(rp->x, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "%d %d lineto\n", + xrt (rp->x+rp->width, s_v1->total_height - rp->y), + yrt (rp->x+rp->width, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height)), + yrt(rp->x+rp->width, s_v1->total_height - (rp->y+rp->height))); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x, s_v1->total_height - (rp->y+rp->height)), + yrt(rp->x, s_v1->total_height - (rp->y+rp->height))); + + fprintf(s_printfp, "%d %d lineto\n", + xrt(rp->x, s_v1->total_height - rp->y), + yrt(rp->x, s_v1->total_height - rp->y)); + + fprintf(s_printfp, "stroke\n"); + } + + if ((function == TBOX_PRINT_BOXED) || + (function == TBOX_PRINT_PLAIN)) { + + fprintf(s_printfp, "newpath\n"); + fprintf(s_printfp, "%d %d moveto\n", + xrt(x, s_v1->total_height - (y-2)), + yrt(x, s_v1->total_height - (y-2))); + fprintf(s_printfp, "gsave\n"); + fprintf(s_printfp, "90 rotate\n"); + fprintf(s_printfp, "(%s) show\n", s); + fprintf(s_printfp, "grestore\n"); + } + + return(rp); +} + +/**************************************************************************** +* tbox - draws an optionally boxed string whose lower lefthand +* corner is at (x, y). As usual, Y is backwards. +****************************************************************************/ + +GdkRectangle *tbox (char *s, int x, int y, enum view1_tbox_fn function) +{ + static GdkRectangle update_rect; + gint lbearing, rbearing, width, ascent, descent; + + gdk_string_extents (g_font, s, + &lbearing, &rbearing, + &width, &ascent, &descent); + + /* + * If we have enough room to display full size events, then just + * use the BOXED function instead of the EVENT function. + */ + if (s_v1->strip_height > 9) { + switch (function) { + case TBOX_DRAW_EVENT: function = TBOX_DRAW_BOXED; break; + case TBOX_GETRECT_EVENT: function = TBOX_GETRECT_BOXED; break; + case TBOX_PRINT_EVENT: function = TBOX_PRINT_BOXED; break; + default: + break; + /* Nothing */ + } + } + + switch (function) { + case TBOX_DRAW_BOXED: + gdk_draw_rectangle (pm, da->style->white_gc, TRUE, + x, y - (ascent+descent+3), width + 2, + ascent + descent + 3); + + gdk_draw_rectangle (pm, da->style->black_gc, FALSE, + x, y - (ascent+descent+3), width + 2, + ascent + descent + 3); + + gdk_draw_string (pm, g_font, da->style->black_gc, + x + 1, y - 1, (const gchar *)s); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_BOXED: + update_rect.x = x; + update_rect.y = y -(ascent+descent+3); + update_rect.width = width + 3; + update_rect.height = ascent + descent + 4; + if (function == TBOX_DRAW_BOXED) + gtk_widget_draw (da, &update_rect); + break; + + case TBOX_DRAW_EVENT: + /* We have a small event to draw...no text */ + gdk_draw_rectangle (pm, da->style->black_gc, FALSE, + x, y - 1, 3, 3); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_EVENT: + update_rect.x = x; + update_rect.y = y - 1; + update_rect.width = 4; + update_rect.height = 4; + if (function == TBOX_DRAW_EVENT) + gtk_widget_draw (da, &update_rect); + break; + + + case TBOX_DRAW_PLAIN: + + gdk_draw_string (pm, g_font, da->style->black_gc, + x + 1, y - 1, (const gchar *)s); + /* NOTE FALLTHROUGH */ + case TBOX_GETRECT_PLAIN: + update_rect.x = x; + update_rect.y = y -(ascent+descent+1); + update_rect.width = width; + update_rect.height = ascent + descent; + if (function == TBOX_DRAW_PLAIN) + gtk_widget_draw (da, &update_rect); + break; + + case TBOX_PRINT_BOXED: + update_rect.x = x; + update_rect.y = y -(ascent+descent+3); + update_rect.width = width + 3; + update_rect.height = ascent + descent + 4; + /* note fallthrough */ + case TBOX_PRINT_PLAIN: + return(tbox_print(s, x, y, function, &update_rect)); + + case TBOX_PRINT_EVENT: + /* We have a small event box to print...no text */ + update_rect.x = x; + update_rect.y = y - 1; + update_rect.width = 4; + update_rect.height = 4; + return(tbox_print(s, x, y, function, &update_rect)); + } + return(&update_rect); +} + +/**************************************************************************** +* line +* +* For lines there is a primitive batching facility, that doesn't update +* the drawing area until the batch is complete. This is handy for drawing +* the pid axis and for summary mode. +* +* line_batch_mode contains the state for this: +* +* BATCH_OFF: no batching, update for every line +* BATCH_NEW: just entered a batch, so initialize the area to update from +* scratch +* BATCH_EXISTING: have drawn at least one line in batch mode, so the update +* area should only be expanded from now on to include the +* union of the "rectangular hull" of all lines +****************************************************************************/ + +static enum { BATCH_OFF, BATCH_NEW, BATCH_EXISTING } line_batch_mode; +static int line_batch_count; +static int line_minx, line_miny, line_maxx, line_maxy; + +void line_batch_start (void) +{ + line_batch_mode = BATCH_NEW; + line_batch_count = 0; +} + +void line_batch_end (void) +{ + GdkRectangle update_rect; + if (line_batch_count > 0) { + update_rect.x = line_minx; + update_rect.y = line_miny; + update_rect.width = (line_maxx - line_minx) + 1; + update_rect.height = (line_maxy - line_miny) + 1; + gtk_widget_draw (da, &update_rect); + } + line_batch_mode = BATCH_OFF; +} + +void line (int x1, int y1, int x2, int y2, enum view1_line_fn function) +{ + GdkRectangle update_rect; + GdkGC *gc = NULL; + + switch(function) { + case LINE_DRAW_BLACK: + gc = da->style->black_gc; + break; + + case LINE_DRAW_WHITE: + gc = da->style->white_gc; + break; + + case LINE_PRINT: + line_print (x1, y1, x2, y2); + return; + } + + gdk_draw_line (pm, gc, x1, y1, x2, y2); + + switch (line_batch_mode) { + case BATCH_OFF: + update_rect.x = x1; + update_rect.y = y1; + update_rect.width = (x2-x1) + 1; + update_rect.height = (y2-y1) + 1; + gtk_widget_draw (da, &update_rect); + break; + + case BATCH_NEW: + line_minx = x1; + line_maxx = x2; + line_miny = y1; + line_maxy = y2; + line_batch_mode = BATCH_EXISTING; + line_batch_count = 1; + break; + + case BATCH_EXISTING: + if (line_minx > x1) + line_minx = x1; + if (line_miny > y1) + line_miny = y1; + if (line_maxx < x2) + line_maxx = x2; + if (line_maxy < y2) + line_maxy = y2; + line_batch_count++; + break; + } +} + + +/**************************************************************************** +* display_pid_axis +****************************************************************************/ + +static void display_pid_axis(v1_geometry_t *vp) +{ + int y, i, label_tick; + int last_printed_y = -vp->strip_height; + pid_sort_t *pp; + int pid_index; + char *label_fmt; + char tmpbuf [128]; + + /* No pids yet? Outta here */ + if (g_pids == NULL) + return; + + line_batch_start(); + + for (i = 0; i < vp->npids; i++) { + pid_index = vp->first_pid_index + i; + if (pid_index >= g_npids) + break; + + set_color(pid_index); + pp = (g_pids + pid_index); + + label_fmt = get_track_label(pp->pid_value); + snprintf(tmpbuf, sizeof(tmpbuf)-1, label_fmt, pp->pid_value); + + y = i*vp->strip_height + vp->pid_ax_offset; + + /* + * Have we incremented enough space to have another label not + * overlap the previous label? + */ + if (y - last_printed_y > 9) { + /* Draw label */ + tbox(tmpbuf, 0, y +4, TBOX_DRAW_PLAIN+s_print_offset); + + last_printed_y = y; + + /* + * And let the line stick out a bit more to indicate this label + * relates to the following line. + */ + label_tick = 4; + } + else { + label_tick = 0; + } + + /* Draw axis line, but only if the lines aren't too close together */ + if (vp->strip_height > 4) { + line(vp->pid_ax_width - label_tick, y+4*s_print_offset, + vp->total_width, y+4*s_print_offset, + LINE_DRAW_BLACK+s_print_offset); + } + } + + set_color(COLOR_DEFAULT); + line_batch_end(); +} + +/**************************************************************************** +* view1_read_events_callback +* New event data just showed up, reset a few things. +****************************************************************************/ + +void view1_read_events_callback(void) +{ + int max_vis_index; + + s_v1->first_pid_index = 0; + + max_vis_index = 300; + if (max_vis_index > g_nevents) + max_vis_index = g_nevents-1; + + s_v1->minvistime = 0LL; + s_v1->maxvistime = (g_events[g_nevents - 1].time * 9)/ 8; + s_srchindex = 0; + s_srchcode = 0; + s_last_selected_event = 0; + + init_track_colors(); + + recompute_hscrollbar(); + recompute_vscrollbar(); +} + +/**************************************************************************** +* display_event_data +****************************************************************************/ + +static void display_event_data(v1_geometry_t *vp) +{ + int start_index; + int pid_index; + int x, y; + event_t *ep; + event_def_t *edp; + double time_per_pixel; + char tmpbuf[1024]; + GdkRectangle *print_rect; + int *last_x_used; + + /* Happens if one loads the event def header first, for example. */ + if (g_nevents == 0) + return; + + time_per_pixel = dtime_per_pixel(vp); + + start_index = find_event_index (vp->minvistime); + + /* Scrolled too far right? */ + if (start_index >= g_nevents) + return; + + ep = (g_events + start_index); + + if (s_print_offset || summary_mode) { + last_x_used = (int *)g_malloc0(vp->npids * sizeof(int)); + } else { + last_x_used = NULL; + } + + line_batch_start(); + + while (ep < (g_events + g_nevents) && + (ep->time < vp->maxvistime)) { + pid_index = ep->pid->pid_index; + set_color(pid_index); + + /* First filter: pid out of range */ + if ((pid_index < vp->first_pid_index) || + (pid_index >= vp->first_pid_index + vp->npids)) { + ep++; + continue; + } + + /* Second filter: event hidden */ + edp = find_event_definition (ep->code); + if (!edp->selected) { + ep++; + continue; + } + + /* Display it... */ + + pid_index -= vp->first_pid_index; + + y = pid_index*vp->strip_height + vp->event_offset; + + x = vp->pid_ax_width + + (int)(((double)(ep->time - vp->minvistime)) / time_per_pixel); + + if (last_x_used != NULL && x < last_x_used[pid_index]) { + ep++; + continue; + } + + if (ep->flags & (EVENT_FLAG_SELECT | EVENT_FLAG_SEARCHRSLT)) { + if (ep->flags & EVENT_FLAG_SELECT) { + format_popbox_string(tmpbuf, sizeof(tmpbuf), ep, edp); +#ifdef NOTDEF + sprintf(tmpbuf, edp->name); + sprintf(tmpbuf+strlen(tmpbuf), ": "); + sprintf(tmpbuf+strlen(tmpbuf), edp->format, ep->datum); +#endif + } else { + sprintf(tmpbuf, "SEARCH RESULT"); + } + print_rect = tbox(tmpbuf, x, y - vp->pop_offset, + TBOX_DRAW_BOXED+s_print_offset); + line(x, y-vp->pop_offset, x, y, LINE_DRAW_BLACK+s_print_offset); + if (last_x_used != NULL) + last_x_used[pid_index] = x + print_rect->width; + } + if (summary_mode) { + int delta = vp->strip_height / 3; + if (delta < 1) + delta = 1; + y = pid_index*vp->strip_height + vp->pid_ax_offset; + line(x, y - delta, x, y + delta, LINE_DRAW_BLACK); + last_x_used[pid_index] = x + 1; + } else { + sprintf(tmpbuf, "%ld", ep->code); + print_rect = tbox(tmpbuf, x, y, TBOX_DRAW_EVENT+s_print_offset); + if (last_x_used != NULL) + last_x_used[pid_index] = x + print_rect->width; + } + + ep++; + } + if (last_x_used) + g_free(last_x_used); + line_batch_end(); + set_color(COLOR_DEFAULT); +} + +/**************************************************************************** +* display_clear +****************************************************************************/ + +static void display_clear(void) +{ + GdkRectangle update_rect; + + gdk_draw_rectangle (pm, da->style->white_gc, TRUE, + 0, 0, da->allocation.width, + da->allocation.height); + + update_rect.x = 0; + update_rect.y = 0; + update_rect.width = da->allocation.width; + update_rect.height = da->allocation.height; + + gtk_widget_draw (da, &update_rect); +} + +/**************************************************************************** +* display_time_axis +****************************************************************************/ + +static void display_time_axis(v1_geometry_t *vp) +{ + int x, y, i; + int xoffset, nticks; + char tmpbuf [128]; + double unit_divisor; + double time; + char *units; + double time_per_pixel; + + y = vp->npids * vp->strip_height + vp->pid_ax_offset; + + x = vp->pid_ax_width; + + nticks = (vp->total_width - vp->pid_ax_width) / vp->time_ax_spacing; + + time_per_pixel = dtime_per_pixel(vp); + + units = "ns"; + unit_divisor = 1.00; + + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "us"; + unit_divisor = 1000.00; + } + + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "ms"; + unit_divisor = 1000.00*1000.00; + } + if ((vp->maxvistime / unit_divisor) > 1000) { + units = "s"; + unit_divisor = 1000.00*1000.00*1000.00; + } + + /* Draw line */ + line(x, y, vp->total_width, y, LINE_DRAW_BLACK+s_print_offset); + + xoffset = 0; + + for (i = 0; i < nticks; i++) { + /* Tick mark */ + line(x+xoffset, y-3, x+xoffset, y+3, LINE_DRAW_BLACK+s_print_offset); + + time = (double)(x + xoffset - vp->pid_ax_width); + time *= time_per_pixel; + time += (double)(vp->minvistime); + time /= unit_divisor; + + sprintf (tmpbuf, "%.2f%s", time, units); + + tbox(tmpbuf, x+xoffset, y+15, TBOX_DRAW_PLAIN+s_print_offset); + + xoffset += vp->time_ax_spacing; + } +} + +/**************************************************************************** +* clear_scoreboard +* Forget about any temporary displays, they're gone now... +****************************************************************************/ + +static void clear_scoreboard(void) +{ + s_result_up = FALSE; +} + +/**************************************************************************** +* view1_display +****************************************************************************/ + +void view1_display(void) +{ + display_clear(); + display_pid_axis(s_v1); + display_event_data(s_v1); + display_time_axis(s_v1); + clear_scoreboard(); +} + +static gint idle_tag; + +/**************************************************************************** +* view1_display_eventually +****************************************************************************/ + +static void view1_display_eventually(void) +{ + gtk_idle_remove(idle_tag); + idle_tag = 0; + view1_display(); +} + + +/**************************************************************************** +* view1_display_when_idle +****************************************************************************/ + +void view1_display_when_idle(void) +{ + if (idle_tag == 0) { + idle_tag = gtk_idle_add((GtkFunction) view1_display_eventually, 0); + } +} + +/**************************************************************************** +* view1_about +****************************************************************************/ + +void view1_about (char *tmpbuf) +{ + int nsnaps; + snapshot_t *snaps; + + sprintf(tmpbuf+strlen(tmpbuf), "Minvistime %lld\nMaxvistime %lld\n", + s_v1->minvistime, s_v1->maxvistime); + sprintf(tmpbuf+strlen(tmpbuf), "Strip Height %d\n", + s_v1->strip_height); + + for (nsnaps = 0, snaps = s_snapshots; snaps; snaps = snaps->next) { + nsnaps++; + } + sprintf(tmpbuf+strlen(tmpbuf), "%d snapshots in the ring\n", nsnaps); +} diff --git a/src/tools/perftool/c2cpel.c b/src/tools/perftool/c2cpel.c new file mode 100644 index 00000000000..38e6fe52e55 --- /dev/null +++ b/src/tools/perftool/c2cpel.c @@ -0,0 +1,248 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include "cpel_util.h" + +static elog_main_t elog_main; + +/* + * convert_clib_file + */ +void convert_clib_file(char *clib_file) +{ + clib_error_t *error = 0; + int i; + elog_main_t *em = &elog_main; + double starttime, delta; + + error = elog_read_file (&elog_main, clib_file); + + if (error) { + clib_warning("%U", format_clib_error, error); + exit (1); + } + + em = &elog_main; + + starttime = em->events[0].time; + + for (i = 0; i < vec_len (em->events); i++) { + elog_event_t *e; /* clib event */ + evt_t *ep; /* xxx2cpel event */ + u8 *s; + u64 timestamp; + elog_event_type_t *t; + u8 *brief_event_name; + u8 *track_name; + int j; + + e = vec_elt_at_index(em->events, i); + + /* Seconds since start of log */ + delta = e->time - starttime; + + /* u64 nanoseconds since start of log */ + timestamp = delta * 1e9; + + s = format (0, "%U%c", format_elog_event, em, e, 0); + + /* allocate an event instance */ + vec_add2(the_events, ep, 1); + ep->timestamp = timestamp; + + /* convert string event code to a real number */ + t = vec_elt_at_index (em->event_types, e->type); + + /* + * Construct a reasonable event name. + * Truncate the format string at the first whitespace break + * or printf format character. + */ + brief_event_name = format (0, "%s", t->format); + + for (j = 0; j < vec_len (brief_event_name); j++) { + if (brief_event_name[j] == ' ' || + brief_event_name[j] == '%' || + brief_event_name[j] == '(') { + brief_event_name[j] = 0; + break; + } + } + /* Throw away that much of the formatted event */ + vec_delete (s, j+1, 0); + + ep->event_id = find_or_add_event(brief_event_name, "%s"); + + track_name = format (0, "%U%c", format_elog_track, em, e, 0); + + ep->track_id = find_or_add_track (track_name); + + ep->datum = find_or_add_strtab(s); + + vec_free (track_name); + vec_free(brief_event_name); + vec_free(s); + } +} + +u8 *vec_basename (char *s) +{ + u8 * rv; + char *cp = s; + + while (*cp) + cp++; + + cp--; + + while (cp > s && *cp != '/') + cp--; + + if (cp > s) + cp++; + + rv = format (0, "%s", cp); + return rv; +} + + +int event_compare (const void *a0, const void *a1) +{ + evt_t *e0 = (evt_t *)a0; + evt_t *e1 = (evt_t *)a1; + + if (e0->timestamp < e1->timestamp) + return -1; + else if (e0->timestamp > e1->timestamp) + return 1; + return 0; +} + +int main (int argc, char **argv) +{ + int curarg=1; + char **inputfiles = 0; + char *outputfile = 0; + FILE *ofp; + + if (argc < 3) + goto usage; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + vec_add1 (inputfiles, argv[curarg]); + curarg++; + continue; + } + clib_warning("Missing filename after --input-file\n"); + exit (1); + } + + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + clib_warning("Missing filename after --output-file\n"); + exit(1); + } + vec_add1 (inputfiles, argv[curarg]); + curarg++; + continue; + + usage: + fformat(stderr, + "c2cpel [--input-file] --output-file \n"); + exit(1); + } + + if (vec_len(inputfiles) == 0 || outputfile == 0) + goto usage; + + if (vec_len(inputfiles) > 1) + goto usage; + + cpel_util_init(); + + convert_clib_file (inputfiles[0]); + + ofp = fopen (outputfile, "w"); + if (ofp == NULL) { + clib_unix_warning ("couldn't create %s", outputfile); + exit (1); + } + + alpha_sort_tracks(); + fixup_event_tracks(); + + /* + * Four sections: string-table, event definitions, track defs, events. + */ + if (!write_cpel_header(ofp, 4)) { + clib_warning ("Error writing cpel header to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_string_table(ofp)) { + clib_warning ("Error writing string table to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_event_defs(ofp)) { + clib_warning ("Error writing event defs to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_track_defs(ofp)) { + clib_warning ("Error writing track defs to %s...\n", outputfile); + unlink(outputfile); + exit(1); + } + + if (!write_events(ofp, (u64) 1e9)) { + clib_warning ("Error writing events to %s...\n", outputfile); + unlink(outputfile); + exit(1); + + } + fclose(ofp); + exit (0); +} diff --git a/src/tools/perftool/configure.ac b/src/tools/perftool/configure.ac new file mode 100644 index 00000000000..f4a986972c2 --- /dev/null +++ b/src/tools/perftool/configure.ac @@ -0,0 +1,12 @@ +AC_INIT(perftool, 2.0) +AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) + +AC_CHECK_LIB([vppinfra], [clib_mem_get_page_size],, + AC_MSG_ERROR([Please install the vpp-lib package])) +AC_CHECK_HEADER([vppinfra/clib.h],, + AC_MSG_ERROR([Please install the vpp-dev package])) + +AM_PROG_LIBTOOL + +AC_OUTPUT([Makefile]) diff --git a/src/tools/perftool/cpel.h b/src/tools/perftool/cpel.h new file mode 100644 index 00000000000..0bfb1a68ef2 --- /dev/null +++ b/src/tools/perftool/cpel.h @@ -0,0 +1,83 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2005-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CPEL_H_ +#define _CPEL_H_ 1 + +typedef struct cpel_file_header_ { + unsigned char endian_version; + unsigned char pad; + unsigned short nsections; + unsigned int file_date; +} cpel_file_header_t; + +#define CPEL_FILE_LITTLE_ENDIAN 0x80 +#define CPEL_FILE_VERSION 0x01 +#define CPEL_FILE_VERSION_MASK 0x7F + +typedef struct cpel_section_header_ { + unsigned int section_type; + unsigned int data_length; /* does NOT include type and itself */ +} cpel_section_header_t; + +#define CPEL_SECTION_STRTAB 1 +/* string at offset 0 is the name of the table */ + +#define CPEL_SECTION_SYMTAB 2 +#define CPEL_SECTION_EVTDEF 3 + +typedef struct event_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_event_definitions; +} event_definition_section_header_t; + +typedef struct event_definition_ { + unsigned int event; + unsigned int event_format; + unsigned int datum_format; +} event_definition_t; + +#define CPEL_SECTION_TRACKDEF 4 + +typedef struct track_definition_section_header_ { + char string_table_name[64]; + unsigned int number_of_track_definitions; +} track_definition_section_header_t; + +typedef struct track_definition_ { + unsigned int track; + unsigned int track_format; +} track_definition_t; + +#define CPEL_SECTION_EVENT 5 + +typedef struct event_section_header_ { + char string_table_name[64]; + unsigned int number_of_events; + unsigned int clock_ticks_per_second; +} event_section_header_t; + +typedef struct event_entry_ { + unsigned int time[2]; + unsigned int track; + unsigned int event_code; + unsigned int event_datum; +} event_entry_t; + +#define CPEL_NUM_SECTION_TYPES 5 + +#endif /* _CPEL_H_ */ + diff --git a/src/tools/perftool/cpel_util.c b/src/tools/perftool/cpel_util.c new file mode 100644 index 00000000000..7ee9b6e2a00 --- /dev/null +++ b/src/tools/perftool/cpel_util.c @@ -0,0 +1,456 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include "cpel_util.h" + +evt_t *the_events; + +track_t *the_tracks; +u32 *track_alpha_map; + +event_definition_t *the_event_definitions; +i64 min_timestamp; + +/* Hash tables, used to find previous instances of the same items */ +uword *the_track_hash; +uword *the_msg_event_hash; +uword *the_strtab_hash; +uword *the_pidtid_hash; +uword *the_pid_to_name_hash; +u8 *the_strtab; + +uword *the_event_id_bitmap; + +/* + * find_or_add_strtab + * Finds or adds a string to the string table + */ +u32 find_or_add_strtab(void *s_arg) +{ + uword *p; + int len; + u8 *this_string; + u8 *scopy=0; + char *s = s_arg; + + p = hash_get_mem(the_strtab_hash, s); + if (p) { + return (p[0]); + } + + /* + * Here's a CLIB bear-trap. We can't add the string-table + * strings to the to the hash table (directly), since it + * expands and moves periodically. All of the hash table + * entries turn into dangling references, yadda yadda. + */ + + len = strlen(s)+1; + vec_add2(the_strtab, this_string, len); + memcpy(this_string, s, len); + + /* Make a copy which won't be moving around... */ + vec_validate(scopy, len); + memcpy(scopy, s, len); + + hash_set_mem(the_strtab_hash, scopy, this_string - the_strtab); + + return(this_string - the_strtab); +} + +/* + * find_or_add_track + * returns index in track table + */ +u32 find_or_add_track(void *s_arg) +{ + uword *p; + track_t *this_track; + u8 *copy_s; + char *s=s_arg; + + p = hash_get_mem(the_track_hash, s); + if (p) { + return (p[0]); + } + vec_add2(the_tracks, this_track, 1); + + this_track->original_index = this_track - the_tracks; + this_track->strtab_offset = find_or_add_strtab(s); + + copy_s = (u8 *)vec_dup(s); + + hash_set_mem(the_track_hash, copy_s, this_track - the_tracks); + return(this_track - the_tracks); +} + +/* + * find_or_add_event + * Adds an event to the event definition vector and add it to + * the event hash table + */ + +u32 find_or_add_event(void *s_arg, char *datum_format) +{ + uword *p; + u8 *copy_s; + event_definition_t *this_event_definition; + u32 event_id; + char *s=s_arg; + + p = hash_get_mem(the_msg_event_hash, s); + if (p) { + return (p[0]); + } + vec_add2(the_event_definitions, this_event_definition, 1); + + /* Allocate a new event-id */ + event_id = clib_bitmap_first_clear (the_event_id_bitmap); + the_event_id_bitmap = clib_bitmap_set(the_event_id_bitmap, event_id, 1); + this_event_definition->event = event_id; + this_event_definition->event_format = find_or_add_strtab(s); + this_event_definition->datum_format = find_or_add_strtab(datum_format); + + copy_s = (u8 *)vec_dup(s); + + hash_set_mem(the_msg_event_hash, copy_s, event_id); + + return(event_id); +} + +/* + * write_string_table + */ +int write_string_table(FILE *ofp) +{ + cpel_section_header_t sh; + + /* Round up string table size */ + while (vec_len(the_strtab) & 0x7) + vec_add1(the_strtab, 0); + + sh.section_type = ntohl(CPEL_SECTION_STRTAB); + sh.data_length = ntohl(vec_len(the_strtab)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + if (fwrite(the_strtab, 1, vec_len(the_strtab), ofp) != + vec_len(the_strtab)) + return(0); + + return(1); +} + +/* + * write_cpel_header + */ +int write_cpel_header(FILE *ofp, u32 nsections) +{ + cpel_file_header_t h; + + h.endian_version = CPEL_FILE_VERSION; + h.pad = 0; + h.nsections = ntohs(nsections); + h.file_date = ntohl(time(0)); + if (fwrite(&h, sizeof(h), 1, ofp) != 1) + return (0); + + return(1); +} + +/* + * write_event_defs + */ +int write_event_defs(FILE *ofp) +{ + cpel_section_header_t sh; + event_definition_section_header_t edsh; + event_definition_t *this_event_definition; + int i; + + /* Next, the event definitions */ + sh.section_type = ntohl(CPEL_SECTION_EVTDEF); + sh.data_length = ntohl(vec_len(the_event_definitions) + *sizeof(the_event_definitions[0]) + + sizeof(event_definition_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&edsh, 0, sizeof(edsh)); + + strcpy(edsh.string_table_name, "FileStrtab"); + edsh.number_of_event_definitions = ntohl(vec_len(the_event_definitions)); + + if (fwrite(&edsh, sizeof(edsh), 1, ofp) != 1) + return(0); + + for (i = 0; i < vec_len(the_event_definitions); i++) { + this_event_definition = &the_event_definitions[i]; + /* Endian fixup */ + this_event_definition->event = ntohl(this_event_definition->event); + this_event_definition->event_format = + ntohl(this_event_definition->event_format); + this_event_definition->datum_format = + ntohl(this_event_definition->datum_format); + + if (fwrite(this_event_definition, sizeof(the_event_definitions[0]), + 1, ofp) != 1) + return(0); + } + return(1); +} + +/* + * ntohll + */ +u64 ntohll (u64 x) { + if (clib_arch_is_little_endian) + x = ((((x >> 0) & 0xff) << 56) + | (((x >> 8) & 0xff) << 48) + | (((x >> 16) & 0xff) << 40) + | (((x >> 24) & 0xff) << 32) + | (((x >> 32) & 0xff) << 24) + | (((x >> 40) & 0xff) << 16) + | (((x >> 48) & 0xff) << 8) + | (((x >> 56) & 0xff) << 0)); + + return x; +} + +/* + * write_events + */ +int write_events(FILE *ofp, u64 clock_ticks_per_second) +{ + cpel_section_header_t sh; + event_section_header_t eh; + u32 number_of_events; + int i; + event_entry_t e; + u64 net_timestamp; + evt_t *this_event; + u32 time0, time1; + + number_of_events = vec_len(the_events); + + sh.section_type = ntohl(CPEL_SECTION_EVENT); + sh.data_length = ntohl(number_of_events * sizeof(e) + + sizeof(event_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&eh, 0, sizeof(eh)); + strcpy(eh.string_table_name, "FileStrtab"); + eh.number_of_events = ntohl(number_of_events); + eh.clock_ticks_per_second = ntohl(clock_ticks_per_second); + + if (fwrite(&eh, sizeof(eh), 1, ofp) != 1) + return(0); + + for (i = 0; i < number_of_events; i++) { + this_event = &the_events[i]; + net_timestamp = ntohll(this_event->timestamp); + + time1 = net_timestamp>>32; + time0 = net_timestamp & 0xFFFFFFFF; + + e.time[0] = time0; + e.time[1] = time1; + e.track = ntohl(this_event->track_id); + e.event_code = ntohl(this_event->event_id); + e.event_datum = ntohl(this_event->datum); + + if (fwrite(&e, sizeof(e), 1, ofp) != 1) + return(0); + } + return(1); +} + +/* + * write_track_defs + */ +int write_track_defs(FILE *ofp) +{ + cpel_section_header_t sh; + track_definition_section_header_t tdsh; + track_definition_t record; + track_definition_t *this_track_definition = &record; + int i; + event_definition_section_header_t edsh; + + /* Next, the event definitions */ + sh.section_type = ntohl(CPEL_SECTION_TRACKDEF); + sh.data_length = ntohl(vec_len(the_tracks) + *sizeof(this_track_definition[0]) + + sizeof(track_definition_section_header_t)); + + if (fwrite(&sh, sizeof(sh), 1, ofp) != 1) + return(0); + + memset(&tdsh, 0, sizeof(tdsh)); + + strcpy(tdsh.string_table_name, "FileStrtab"); + tdsh.number_of_track_definitions = ntohl(vec_len(the_tracks)); + + if (fwrite(&tdsh, sizeof(edsh), 1, ofp) != 1) + return(0); + + for (i = 0; i < vec_len(the_tracks); i++) { + this_track_definition->track = ntohl(i); + this_track_definition->track_format = + ntohl(the_tracks[i].strtab_offset); + + if (fwrite(this_track_definition, sizeof(this_track_definition[0]), + 1, ofp) != 1) + return(0); + } + return(1); +} + +void cpel_util_init (void) +{ + u8 *eventstr; + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_msg_event_hash = hash_create_string (0, sizeof (uword)); + the_track_hash = hash_create_string (0, sizeof (uword)); + the_pidtid_hash = hash_create_string (0, sizeof(uword)); + the_pid_to_name_hash = hash_create(0, sizeof(uword)); + + /* Must be first, or no supper... */ + find_or_add_strtab("FileStrtab"); + + /* Historical canned events, no longer used. */ + if (0) { + /* event 0 (not used) */ + eventstr = format(0, "PlaceholderNotUsed"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 1 (thread on CPU) */ + eventstr = format(0, "THREAD/THRUNNING"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 2 (thread ready) */ + eventstr = format(0, "THREAD/THREADY"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "%s"); + vec_free(eventstr); + + /* event 3 (function enter) */ + eventstr = format(0, "FUNC/ENTER"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "0x%x"); + vec_free(eventstr); + + /* event 4 (function enter) */ + eventstr = format(0, "FUNC/EXIT"); + vec_add1(eventstr, 0); + find_or_add_event(eventstr, "0x%x"); + vec_free(eventstr); + } +} + +/* + * alpha_compare_tracks + */ +static int alpha_compare_tracks(const void *a1, const void *a2) +{ + int i; + track_t *t1 = (track_t *)a1; + track_t *t2 = (track_t *)a2; + u8 *s1 = &the_strtab[t1->strtab_offset]; + u8 *s2 = &the_strtab[t2->strtab_offset]; + + for (i = 0; s1[i] && s2[i]; i++) { + if (s1[i] < s2[i]) + return(-1); + if (s1[i] > s2[i]) + return(1); + } + return(0); +} + +/* + * alpha_sort_tracks + * Alphabetically sort tracks, set up a mapping + * vector so we can quickly map the original track index to + * the new/improved/alpha-sorted index + */ +void alpha_sort_tracks(void) +{ + track_t *this_track; + int i; + + qsort(the_tracks, vec_len(the_tracks), sizeof(track_t), + alpha_compare_tracks); + + vec_validate(track_alpha_map, vec_len(the_tracks)); + _vec_len(track_alpha_map) = vec_len(the_tracks); + + for (i = 0; i < vec_len(the_tracks); i++) { + this_track = &the_tracks[i]; + track_alpha_map[this_track->original_index] = i; + } +} + +/* + * fixup_event_tracks + * Use the track alpha mapping to account for the alphabetic + * sort performed by the previous routine + */ +void fixup_event_tracks(void) +{ + int i; + u32 old_track; + + for (i = 0; i < vec_len(the_events); i++) { + old_track = the_events[i].track_id; + the_events[i].track_id = track_alpha_map[old_track]; + } +} + +/* Indispensable for debugging in gdb... */ + +u32 vl(void *x) +{ + return vec_len(x); +} diff --git a/src/tools/perftool/cpel_util.h b/src/tools/perftool/cpel_util.h new file mode 100644 index 00000000000..b76f7a4b322 --- /dev/null +++ b/src/tools/perftool/cpel_util.h @@ -0,0 +1,68 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __cpel_util_h__ +#define __cpel_util_h__ + +/* + * Our idea of an event, as opposed to a CPEL event + */ +typedef struct evt_ { + u64 timestamp; + u32 track_id; + u32 event_id; + u32 datum; +} evt_t; + +evt_t *the_events; + +/* + * Track object, so we can sort the tracks alphabetically and + * fix the events later + */ +typedef struct track_ { + u32 original_index; + u32 strtab_offset; +} track_t; + +track_t *the_tracks; +u32 *track_alpha_map; + +event_definition_t *the_event_definitions; +i64 min_timestamp; + +/* Hash tables, used to find previous instances of the same items */ +uword *the_track_hash; +uword *the_msg_event_hash; +uword *the_strtab_hash; +uword *the_pidtid_hash; +uword *the_pid_to_name_hash; +u8 *the_strtab; + +u32 find_or_add_strtab(void *s_arg); +u32 find_or_add_track(void *s_arg); +u32 find_or_add_event(void *s_arg, char *datum_format); +int write_string_table(FILE *ofp); +int write_cpel_header(FILE *ofp, u32 nsections); +int write_event_defs(FILE *ofp); +u64 ntohll (u64 x); +int write_events(FILE *ofp, u64 clock_ticks_per_second); +int write_track_defs(FILE *ofp); +void cpel_util_init (void); +void alpha_sort_tracks(void); +void fixup_event_tracks(void); + +#endif /* __cpel_util_h__ */ diff --git a/src/tools/perftool/cpelatency.c b/src/tools/perftool/cpelatency.c new file mode 100644 index 00000000000..7b87d606cda --- /dev/null +++ b/src/tools/perftool/cpelatency.c @@ -0,0 +1,927 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpelatency 2.0"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ +uword *the_pidtid_hash; /* ("pid:xxx tid:yy", track-definition) hash */ + +f64 ticks_per_us; +u32 start_event_code = 2; /* default: XR thread ready event */ +u32 end_event_code = 1; /* default: XR thread running event */ +int exclude_kernel_from_summary_stats=1; +int summary_stats_only; +int scatterplot; +u8 *name_filter; +int have_trackdefs; + +typedef enum { + SORT_MAX_TIME=1, + SORT_MAX_OCCURRENCES, + SORT_NAME, +} sort_t; + +sort_t sort_type = SORT_MAX_TIME; + +int widest_name_format=5; +int widest_track_format=20; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; + u64 state_start_ticks; + u64 *ticks_in_state; /* vector of state occurrences */ + f64 mean_ticks_in_state; + f64 variance_ticks_in_state; + f64 total_ticks_in_state; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *) bp->datum_str); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *) bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + u8 *pidstr; + u8 *pidtid_str; + u8 *cp; + int tid, pid; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(stderr, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + if (verbose) { + fprintf(stderr, "adding track '%s'\n", btp->track_str); + } + + thislen = strlen((char *) btp->track_str); + if (thislen > widest_track_format) + widest_track_format = thislen; + + /* convert track_str "eth_server t11(20498)" to "pid:20498 tid:11" */ + cp = btp->track_str; + while (*cp && *cp != '(') + cp++; + if (!*cp) { + fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); + goto out; + } + pidstr = cp+1; /* remember location of PID */ + + while (cp > btp->track_str && *cp != 't') + cp--; + + if (cp == btp->track_str) { + fprintf(stderr, "error canonicalizing '%s'\n", btp->track_str); + goto out; + } + tid = atol((char *)(cp+1)); + pid = atol((char *) pidstr); + pidtid_str = format(0, "pid:%d tid:%d", pid, tid); + vec_add1(pidtid_str, 0); + + /* + * Note: duplicates are possible due to thread create / + * thread destroy operations. + */ + p = hash_get_mem(the_pidtid_hash, pidtid_str); + if (p) { + vec_free(pidtid_str); + goto out; + } + hash_set_mem(the_pidtid_hash, pidtid_str, btp - bound_tracks); + + out: + tp++; + } + have_trackdefs = 1; + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u32 time0, time1; + u32 track_code; + u8 *this_strtab; + u64 ticks_in_state; + bound_track_t *btp; + bound_track_t *state_track=0; + u8 *pidtid_str; + u8 *pidtid_dup; + u8 *ecp; + u32 event_code; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + /* + * Some logger implementation that doesn't produce + * trackdef sections, synthesize the bound_tracks vector + */ + if (!have_trackdefs) { + for (i = 0; i < nevents; i++) { + track_code = ntohl(ep->track); + pidtid_dup = format(0, "%d", track_code); + vec_add1(pidtid_dup, 0); + p = hash_get_mem(the_pidtid_hash, pidtid_dup); + if (!p) { + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = pidtid_dup; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + hash_set_mem(the_pidtid_hash, pidtid_dup, btp - bound_tracks); + } else { + vec_free(pidtid_dup); + } + ep++; + } + } + + ep = (event_entry_t *)(eh+1); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + event_code = ntohl(ep->event_code); + + /* Find the corresponding track via the pidtid hash table */ + if (event_code == start_event_code || event_code == end_event_code) { + if (have_trackdefs) { + pidtid_str = this_strtab + ntohl(ep->event_datum); + pidtid_dup = format(0, (char *) pidtid_str); + vec_add1(pidtid_dup, 0); + ecp = &pidtid_dup[vec_len(pidtid_dup)-1]; + while (*--ecp == ' ') + *ecp = 0; + } else { + pidtid_dup = format(0, "%d", ntohl(ep->track)); + vec_add1(pidtid_dup, 0); + } + + p = hash_get_mem(the_pidtid_hash, pidtid_dup); + if (!p) { + fprintf(stderr, "warning: couldn't find '%s'\n", + pidtid_dup); + vec_free(pidtid_dup); + ep++; + continue; + } + state_track = &bound_tracks[p[0]]; + } + /* Found the start-event code ? */ + if (event_code == start_event_code) { + state_track->state_start_ticks = now; + } else if (event_code == end_event_code) { + /* + * Add a ticks-in-state record, unless + * e.g. the log started with the exit event + */ + if (state_track->state_start_ticks) { + ticks_in_state = now - state_track->state_start_ticks; + vec_add1(state_track->ticks_in_state, ticks_in_state); + state_track->state_start_ticks = 0; + } + /* Otherwise, nothing */ + } + ep++; + } + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + fprintf(ofp, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + +void compute_state_statistics(int verbose, FILE *ofp) +{ + int i, j; + bound_track_t *bp; + f64 fticks; + + /* Across the bound tracks */ + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + bp->mean_ticks_in_state = 0.0; + bp->variance_ticks_in_state = 0.0; + bp->total_ticks_in_state = 0.0; + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; + } + /* Compute mean */ + if (vec_len(bp->ticks_in_state)) { + bp->mean_ticks_in_state = bp->total_ticks_in_state / + ((f64) vec_len(bp->ticks_in_state)); + } + /* Accumulate sum: (Xi-Xbar)**2 */ + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fticks = bp->ticks_in_state[j]; + bp->variance_ticks_in_state += + (fticks - bp->mean_ticks_in_state)* + (fticks - bp->mean_ticks_in_state); + } + /* Compute s**2, the unbiased estimator of sigma**2 */ + if (vec_len(bp->ticks_in_state) > 1) { + bp->variance_ticks_in_state /= (f64) + (vec_len(bp->ticks_in_state)-1); + } + } +} + +int track_compare_max (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = a1->total_ticks_in_state; + v2 = a2->total_ticks_in_state; + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_occurrences (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = (f64) vec_len(a1->ticks_in_state); + v2 = (f64) vec_len(a2->ticks_in_state); + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_name (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + + return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); +} + +void sort_state_statistics(sort_t type, FILE *ofp) +{ + int (*compare)(const void *, const void *) = 0; + + if (summary_stats_only) + return; + + switch(type) { + case SORT_MAX_TIME: + fprintf(ofp, "Results sorted by max time in state.\n\n"); + compare = track_compare_max; + break; + + case SORT_MAX_OCCURRENCES: + fprintf(ofp, "Results sorted by max occurrences of state.\n\n"); + compare = track_compare_occurrences; + break; + + case SORT_NAME: + compare = track_compare_name; + fprintf(ofp, "Results sorted by process name, thread ID, PID\n\n"); + break; + + default: + fatal("sort type not set?"); + } + + qsort (bound_tracks, vec_len(bound_tracks), + sizeof (bound_track_t), compare); +} + +void print_state_statistics(int verbose, FILE *ofp) +{ + int i,j; + u8 *trackpad; + bound_track_t *bp; + f64 total_time = 0.0; + f64 total_switches = 0.0; + + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + if (!summary_stats_only) { + fprintf(ofp, (char *)trackpad, "ProcName Thread(PID)"); + fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); + } + + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + if (bp->mean_ticks_in_state == 0.0) + continue; + + if (name_filter && + strncmp((char *)bp->track_str, (char *)name_filter, + strlen((char *)name_filter))) + continue; + + /* + * Exclude kernel threads (e.g. idle thread) from + * state statistics + */ + if (exclude_kernel_from_summary_stats && + !strncmp((char *) bp->track_str, "kernel ", 7)) + continue; + + total_switches += (f64) vec_len(bp->ticks_in_state); + + if (!summary_stats_only) { + fprintf(ofp, (char *) trackpad, bp->track_str); + fprintf(ofp, "%10.3f +- %10.3f", + bp->mean_ticks_in_state / ticks_per_us, + sqrt(bp->variance_ticks_in_state) + / ticks_per_us); + fprintf(ofp, "%12.3f", + bp->total_ticks_in_state / ticks_per_us); + fprintf(ofp, "%8d\n", vec_len(bp->ticks_in_state)); + } + + if (scatterplot) { + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fprintf(ofp, "%.3f\n", + (f64)bp->ticks_in_state[j] / ticks_per_us); + } + } + + total_time += bp->total_ticks_in_state; + } + + if (!summary_stats_only) + fprintf(ofp, "\n"); + fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", + exclude_kernel_from_summary_stats ? "exclude" : "include"); + if (name_filter) + fprintf(ofp, + "Note: only pid/proc/threads matching '%s' are included.\n", + name_filter); + + fprintf(ofp, + "Total time in state: %10.3f (us), Total state occurrences: %.0f\n", + total_time / ticks_per_us, total_switches); + fprintf(ofp, "Average time in state: %10.3f (us)\n", + (total_time / total_switches) / ticks_per_us); + fprintf(ofp, "State start event: %d, state end event: %d\n", + start_event_code, end_event_code); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose++; + continue; + } + if (!strncmp(argv[curarg], "--scatterplot", 4)) { + curarg++; + scatterplot=1; + continue; + } + + if (!strncmp(argv[curarg], "--start-event", 4)) { + curarg++; + if (curarg < argc) { + start_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --start-event\n"); + } + if (!strncmp(argv[curarg], "--end-event", 4)) { + curarg++; + if (curarg < argc) { + end_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --end-event\n"); + } + if (!strncmp(argv[curarg], "--max-time-sort", 7)) { + sort_type = SORT_MAX_TIME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { + sort_type = SORT_MAX_OCCURRENCES; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--name-sort", 3)) { + sort_type = SORT_NAME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--kernel-included", 3)) { + exclude_kernel_from_summary_stats = 0; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--summary", 3)) { + summary_stats_only=1; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--filter", 3)) { + curarg ++; + if (curarg < argc) { + name_filter = (u8 *) argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filter string after --filter\n"); + } + + + usage: + fprintf(stderr, + "cpelatency --input-file [--output-file ]\n"); + fprintf(stderr, + " [--start-event ] [--verbose]\n"); + fprintf(stderr, + " [--end-event ]\n"); + fprintf(stderr, + " [--max-time-sort(default) | --max-occurrence-sort |\n"); + + fprintf(stderr, + " --name-sort-sort] [--kernel-included]\n"); + + fprintf(stderr, + " [--summary-stats-only] [--scatterplot]\n"); + + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + the_pidtid_hash = hash_create_string (0, sizeof(uword)); + + if (cpel_dump((u8 *)cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + compute_state_statistics(verbose, ofp); + sort_state_statistics(sort_type, ofp); + print_state_statistics(verbose, ofp); + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/cpeldump.c b/src/tools/perftool/cpeldump.c new file mode 100644 index 00000000000..9011bd039ec --- /dev/null +++ b/src/tools/perftool/cpeldump.c @@ -0,0 +1,638 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpeldump 2.0"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +int widest_name_format=5; +int widest_track_format=5; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(stderr, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(stderr, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *)bp->datum_str); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *)bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(stderr, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + thislen = strlen((char *)btp->track_str); + if (thislen > widest_track_format) + widest_track_format = thislen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(stderr, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + f64 ticks_per_us; + u32 event_code, track_code; + u64 starttime = 0xFFFFFFFFFFFFFFFFULL; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u64 delta; + u32 hours, minutes, seconds, msec, usec; + u32 time0, time1; + double d; + bound_event_t *bp; + bound_event_t generic_event; + bound_track_t *tp=0; + bound_track_t generic_track; + u32 last_track_code; + u8 *s, *evtpad, *trackpad; + u8 *this_strtab; + + generic_event.event_str = (u8 *)"%d"; + generic_event.datum_str = (u8 *)"0x%08x"; + generic_event.is_strtab_ref = 0; + + generic_track.track_str = (u8 *)"%d"; + last_track_code = 0xdeadbeef; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second)) / 1e6; + + if (verbose) { + fprintf(stderr, "Event section: %d events, %.3f ticks_per_us\n", + nevents, ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + evtpad = format(0, "%%-%ds ", widest_name_format); + vec_add1(evtpad, 0); + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_us; + + now = d; + + if (starttime == 0xFFFFFFFFFFFFFFFFULL) + starttime = now; + + delta = now - starttime; + + /* Delta = time since first event, in usec */ + + hours = delta / USEC_PER_HOUR; + if (hours) + delta -= ((u64) hours * USEC_PER_HOUR); + minutes = delta / USEC_PER_MINUTE; + if (minutes) + delta -= ((u64) minutes * USEC_PER_MINUTE); + seconds = delta / USEC_PER_SECOND; + if (seconds) + delta -= ((u64) seconds * USEC_PER_SECOND); + msec = delta / USEC_PER_MS; + if (msec) + delta -= ((u64) msec * USEC_PER_MS); + + usec = delta; + + /* Output the timestamp */ + fprintf(ofp, time_format, hours, minutes, seconds, msec, usec); + + /* output the track */ + track_code = ntohl(ep->track); + + if (track_code != last_track_code) { + p = hash_get(the_trackdef_hash, track_code); + if (p) { + tp = &bound_tracks[p[0]]; + } else { + tp = &generic_track; + } + } + s = format(0, (char *)tp->track_str, track_code); + vec_add1(s, 0); + fprintf(ofp, (char *)trackpad, s); + vec_free(s); + + /* output the event and datum */ + if (0 && verbose) { + fprintf(stderr, "raw event code %d, raw event datum 0x%x\n", + ntohl(ep->event_code), ntohl(ep->event_datum)); + } + + event_code = ntohl(ep->event_code); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + bp = &bound_events[p[0]]; + } else { + bp = &generic_event; + } + s = format(0, (char *)bp->event_str, ntohl(ep->event_code)); + vec_add1(s, 0); + fprintf(ofp, (char *)evtpad, s); + vec_free(s); + if (bp->is_strtab_ref) { + fprintf(ofp, (char *) bp->datum_str, + &this_strtab[ntohl(ep->event_datum)]); + } else { + fprintf(ofp, (char *) bp->datum_str, ntohl(ep->event_datum)); + } + fputs("\n", ofp); + ep++; + } + vec_free(evtpad); + vec_free(trackpad); + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(stderr, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(stderr, "File created %s", ctime(&file_time)); + fprintf(stderr, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(stderr, + "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose = 1; + continue; + } + + usage: + fprintf(stderr, + "cpeldump --input-file [--output-file ]\n"); + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + +#ifdef TEST_TRACK_INFO + { + bound_track_t *btp; + vec_add2(bound_tracks, btp, 1); + btp->track = 0; + btp->track_str = "cpu %d"; + hash_set(the_trackdef_hash, 0, btp - bound_tracks); + hash_set(the_trackdef_hash, 1, btp - bound_tracks); + } +#endif + + if (cpel_dump((u8 *)cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/cpelinreg.c b/src/tools/perftool/cpelinreg.c new file mode 100644 index 00000000000..115afad7fb2 --- /dev/null +++ b/src/tools/perftool/cpelinreg.c @@ -0,0 +1,892 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2008-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Search for O(N**2) functions bracketed by before/after + * events. The "before" event's datum is used as a tag, e.g. which function + * did we call that's strongly O(N). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" + +FILE *g_ifp; +char *g_ifile; + +typedef unsigned long long ulonglong; + +void process_traces (void); +void record_instance (ulong tag, ulonglong time); +void report_actors (void); +void scatterplot_data(void); +int entry_event, exit_event; +int nokey; +char *version = "cpelinreg 2.0"; +int model_these[10]; +int model_index; +int summary_stats; +ulonglong first_start_time; +ulonglong last_end_time; +ulonglong total_time; +ulong scatterkey; +int inline_mokus; + +typedef struct bound_track_ { + u32 track_code; + u32 *start_datum; + u8 *dup_event; + int state; + u64 *start_time; + u64 thread_timestamp; + u64 time_thread_on_cpu; +} bound_track_t; + +bound_track_t *bound_tracks; +uword *the_trackdef_hash; + + +#define MAXSTACK 128 + +typedef struct instance_ { + struct instance_ *next; + ulonglong time; +}instance_t; + +typedef struct actor_ { + struct actor_ *next; + ulong key; + struct instance_ *first; + struct instance_ *last; + double a; + double b; + double min; + double max; + double mean; + double r; + ulong ninst; +} actor_t; + +#define NBUCKETS 1811 + +actor_t *hash[NBUCKETS]; + +actor_t *find_or_create_actor (ulong key) +{ + ulong bucket; + actor_t *ap; + u8 *mem; + + bucket = key % NBUCKETS; + + ap = hash[bucket]; + + if (ap == NULL) { + /* Ensure 8-byte alignment to avoid (double) alignment faults */ + mem = malloc(sizeof(*ap) + 4); + if (((uword)(mem)) & 0x7) + mem += 4; + ap = (actor_t *)mem; + + if (ap == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ap->next = 0; + ap->key = key; + ap->first = 0; + ap->last = 0; + ap->a = 0.00; + ap->b = 0.00; + hash [bucket] = ap; + return (ap); + } + + while (ap) { + if (ap->key == key) + return (ap); + ap = ap->next; + } + + mem = malloc(sizeof(*ap)+4); + if (((uword)(mem) & 0x7)) + mem += 4; + ap = (actor_t *)mem; + + if (ap == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ap->key = key; + ap->first = 0; + ap->last = 0; + ap->a = 0.00; + ap->b = 0.00; + + ap->next = hash[bucket]; + hash[bucket] = ap; + + return (ap); +} + +void record_instance (ulong key, ulonglong time) +{ + actor_t *ap; + instance_t *ip; + + if (nokey) + key = 0; + + ap = find_or_create_actor (key); + + ip = (instance_t *)malloc(sizeof(*ip)); + if (ip == NULL) { + fprintf (stderr, "out of memory...\n"); + exit (1); + } + ip->time = time; + ip->next = 0; + + if (ap->first == 0) { + ap->first = ip; + ap->last = ip; + ap->ninst = 1; + } else { + ap->last->next = ip; + ap->last = ip; + ap->ninst++; + } +} + +#define NINSTANCE 200000 + +double x[NINSTANCE]; +double y[NINSTANCE]; + +int actor_compare (const void *arg1, const void *arg2) +{ + double e10k1, e10k2; + actor_t **a1 = (actor_t **)arg1; + actor_t **a2 = (actor_t **)arg2; + double ninst1, ninst2; + + ninst1 = ((double)((*a1)->ninst)); + ninst2 = ((double)((*a2)->ninst)); + + e10k1 = ninst1 * ((*a1)->mean); + e10k2 = ninst2 * ((*a2)->mean); + + if (e10k1 < e10k2) + return (1); + else if (e10k1 == e10k2) + return (0); + else + return (-1); +} + +void report_actors (void) +{ + int i; + actor_t *ap; + instance_t *ip; + int nactors = 0; + int ninstance; + actor_t **actor_vector; + double e10k; + extern void linreg (double *x, double *y, int nitems, double *a, double *b, + double *minp, double *maxp, double *meanp, double *r); + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + nactors++; + ninstance = 0; + + ip = ap->first; + + while (ip) { + if (ninstance < NINSTANCE) { + x[ninstance] = ninstance; + y[ninstance] = ((double)ip->time); + ninstance++; + } + ip = ip->next; + } + if (ninstance > 1) { +#if DEBUG > 0 + int j; + + for (j = 0; j < ninstance; j++) { + printf("x[%d] = %10.2f, y[%d] = %10.2f\n", + j, x[j], j, y[j]); + } +#endif + + linreg (x, y, ninstance, &ap->a, &ap->b, &ap->min, + &ap->max, &ap->mean, &ap->r); + } else { + ap->a = 0.00; + ap->b = 0.00; + } + + ap = ap->next; + } + } + + actor_vector = (actor_t **)malloc (nactors*sizeof(*actor_vector)); + nactors = 0; + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + if ((ap->a != 0.00) || (ap->b != 0.00)) { + actor_vector[nactors++] = ap; + } + ap = ap->next; + } + } + + qsort (actor_vector, nactors, sizeof (actor_t *), actor_compare); + + if (summary_stats) + printf("NInst Offset Slope T(Ninst) Min Max Avg %%InstTime R Key"); + else + printf("NInst Offset Slope T(Ninst) Key"); + + for (i = 0; i < model_index; i++) { + printf ("T @ %-8d ", model_these[i]); + } + + printf ("\n"); + + for (i = 0; i < nactors; i++) { + int j; + double ninst; + double pcttot; + ap = actor_vector[i]; + ninst = ap->ninst; + + e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); + + if (ap->ninst) { + if (summary_stats) { + pcttot = (e10k / ((double)total_time)) * 100.0; + printf ("%6ld %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f %11.2f 0x%08lx ", + ap->ninst, ap->a, ap->b, e10k, ap->min, + ap->max, ap->mean, pcttot, ap->r, ap->key); + } + else + printf ("%6ld %11.2f %11.2f %11.2f 0x%08lx ", + ap->ninst, ap->a, ap->b, e10k, ap->key); + + for (j = 0; j < model_index; j++) { + ninst = model_these[j]; + e10k = ninst * (ap->a + ap->b*((ninst-1.0)/2.0)); + printf ("%10.2f ", e10k); + } + printf ("\n"); + } + } +} + +void scatterplot_data(void) +{ + actor_t *ap; + int i; + instance_t *ip; + double time; + int count=0; + + for (i = 0; i < NBUCKETS; i++) { + ap = hash[i]; + if (ap == NULL) + continue; + while (ap) { + if (ap->key == scatterkey){ + ip = ap->first; + while (ip) { + time = ((double)ip->time); + printf ("%d\t%.0f\n", count++, time); + ip = ip->next; + } + return; + } + ap = ap->next; + } + } +} + + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + fprintf(stderr, "\n"); + exit(1); +} + +typedef enum { + PASS1=1, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int trackdef_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u32 track_code; + uword *p; + bound_track_t *btp; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(stderr, "Track Definition Section: %d definitions\n", + nevents); + } + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track_code = track_code; + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + tp++; + } + return (0); +} + + +int event_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + event_entry_t *ep; + f64 ticks_per_us; + long output_count; + long dup_events = 0; + ulonglong end_time = 0; + double t; + int sp, ancestor; + int nevents, i; + u64 now; + u64 time0, time1; + double d; + u32 last_track_code = 0xdeafb00b; + u32 track_code; + u32 event_code, event_datum; + bound_track_t *tp = 0; + uword *p; + + output_count = 0; + total_time = 0; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + d = now; + d /= ticks_per_us; + first_start_time = d; + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Convert from bus ticks to usec */ + d = now; + d /= ticks_per_us; + + now = d; + + track_code = ntohl(ep->track); + event_code = ntohl(ep->event_code); + event_datum = ntohl(ep->event_datum); + + if (track_code != last_track_code) { + if (tp) { + tp->thread_timestamp += now - tp->time_thread_on_cpu; + tp->time_thread_on_cpu = 0; + } + p = hash_get(the_trackdef_hash, track_code); + if (!p) { + /* synthesize a new track */ + vec_add2(bound_tracks, tp, 1); + tp->track_code = track_code; + hash_set(the_trackdef_hash, track_code, tp - bound_tracks); + } else { + tp = bound_tracks + p[0]; + } + last_track_code = track_code; + tp->time_thread_on_cpu = now; + } + + if (event_code != entry_event && + event_code != exit_event) { + ep++; + continue; + } + + again: + switch (tp->state) { + case 0: /* not in state */ + /* Another exit event? Stack pop */ + if (event_code == exit_event) { + /* Only if we have something on the stack */ + if (vec_len(tp->start_datum) > 0) { + tp->state = 1; + goto again; + } else { + fprintf (stderr, + "End event before start event, key 0x%x.", + ntohl(ep->event_datum)); + fprintf (stderr, " Interpret results carefully...\n"); + } + } + + tp->state = 1; + if (vec_len(tp->start_datum) >= MAXSTACK) { + int j; + + fprintf (stderr, "stack overflow..\n"); + for (j = vec_len(tp->start_datum)-1; j >= 0; j--) { + fprintf(stderr, "stack[%d]: datum 0x%x\n", + j, tp->start_datum[j]); + } + fprintf (stderr, + "Stack overflow... This occurs when " + "(start, datum)...(end, datum) events\n" + "are not properly paired.\n\n" + "A typical scenario looks like this:\n\n" + " ...\n" + " ELOG(..., START_EVENT, datum);\n" + " if (condition)\n" + " return; /*oops, forgot the end event*/\n" + " ELOG(..., END_EVENT, datum);\n" + " ...\n\n" + "The datum stack dump (above) should make it clear\n" + "where to start looking for a sneak path...\n"); + + exit (1); + } + vec_add1(tp->start_datum, event_datum); + vec_add1(tp->start_time, (tp->thread_timestamp + (now - tp->time_thread_on_cpu))); +#ifdef HAVING_TROUBLE + printf ("sp %lld key 0x%x start time %llu\n", + (long long) vec_len(tp->start_time)-1, event_datum, + (unsigned long long) + tp->start_time [vec_len(tp->start_time)-1]); + printf ("timestamp %llu, now %llu, thread on cpu %llu\n", + (unsigned long long) tp->thread_timestamp, + (unsigned long long) now, + (unsigned long long) tp->time_thread_on_cpu); +#endif + + + + /* + * Multiple identical enter events? If the user knows that + * gcc is producing bogus events due to inline functions, + * trash the duplicate. + */ + if (inline_mokus + && vec_len (tp->start_datum) > 1 + && tp->start_datum [vec_len(tp->start_datum)-1] == + tp->start_datum [vec_len(tp->start_datum)-2]) { + vec_add1 (tp->dup_event, 1); + } else { + vec_add1 (tp->dup_event, 0); + } + + + ep++; + continue; + + case 1: /* in state */ + /* Another entry event? Stack push*/ + if (event_code == entry_event) { + tp->state = 0; + goto again; + } + + if (vec_len(tp->start_datum) == 0) { + fprintf (stderr, "Stack underflow...\n"); + exit (1); + } + + sp = vec_len(tp->start_time)-1; + + end_time = tp->thread_timestamp + (now - tp->time_thread_on_cpu); + + if (!tp->dup_event[sp]) { +#ifdef HAVING_TROUBLE + printf ("sp %d key 0x%x charged %llu\n", sp, + tp->start_datum[sp], end_time - tp->start_time[sp]); + printf (" start %llu, end %llu\n", (unsigned long long) tp->start_time[sp], + (unsigned long long) end_time); +#endif + + record_instance (tp->start_datum[sp], (end_time - + tp->start_time[sp])); + + /* Factor out our time from surrounding services, if any */ + for (ancestor = sp-1; ancestor >= 0; ancestor--) { +#ifdef HAVING_TROUBLE + printf ("Factor out %lld from key 0x%08x\n", + (end_time - tp->start_time[sp]), tp->start_datum[ancestor]); +#endif + tp->start_time[ancestor] += (end_time - tp->start_time[sp]); + } + output_count++; + total_time += (end_time - tp->start_time[sp]); + tp->state = 0; + } else { + dup_events++; + } + _vec_len(tp->start_datum) = sp; + _vec_len(tp->start_time) = sp; + _vec_len(tp->dup_event) = sp; + } + + ep++; + } + last_end_time = now; + + if (scatterkey) { + scatterplot_data(); + exit (0); + } + + if (output_count) { + t = (double)total_time; + printf ("%ld instances of state, %.2f microseconds average\n", + output_count, t / output_count); + + printf ("Total instrumented runtime: %.2f microseconds\n", + ((double)total_time)); + printf ("Total runtime: %lld microseconds\n", + last_end_time - first_start_time); + + t /= (double)(last_end_time - first_start_time); + t *= 100.0; + + if (dup_events) { + printf ("Suppressed %ld duplicate state entry events\n", + dup_events); + } + printf ("Instrumented code accounts for %.2f%% of total time.\n\n", + t); + report_actors(); + } else { + printf ("No instances of state...\n"); + } + + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {unsupported_pass}, /* type 0 -- f**ked */ + {noop_pass}, /* type 1 -- STRTAB */ + {noop_pass}, /* type 2 -- SYMTAB */ + {noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass}, /* type 4 -- TRACKDEF */ + {event_pass}, /* type 5 -- EVENTS */ +}; + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +int process_file (u8 *cpel, int verbose) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + FILE *ofp = stderr; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + nsections = ntohs(fh->nsections); + + /* + * Take a passe through the file. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", + ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + return(0); +} + +/**************************************************************************** +* main - +****************************************************************************/ + +int main (int argc, char **argv) +{ + int curarg = 1; + u8 *cpel = 0; + int verbose = 0; + + if (argc < 6) + { + fprintf (stderr, "usage: cpelinreg -i \n"); + fprintf (stderr, " -s start-event --e end-event [-nokey]\n"); + fprintf (stderr, " [-m ][-xtra-stats]\n"); + fprintf (stderr, " [-keyscatterplot ]\n\n"); + fprintf (stderr, "%s\n", version); + exit (1); + } + + while (curarg < argc) { + if (!strncmp (argv[curarg], "-ifile", 2)) { + curarg++; + g_ifile = argv[curarg++]; + continue; + } + if (!strncmp (argv[curarg], "-start", 2)) { + curarg++; + entry_event = atol (argv [curarg++]); + continue; + } + if (!strncmp (argv[curarg], "-end", 2)) { + curarg++; + exit_event = atol (argv [curarg++]); + continue; + } + + if (!strncmp(argv[curarg], "-badinlines", 2)) { + curarg++; + inline_mokus = 1; + continue; + } + + if (!strncmp (argv[curarg], "-x", 2)) { + curarg++; + summary_stats=1; + continue; + } + if (!strncmp (argv[curarg], "-nokey", 2)) { + curarg++; + nokey = 1; + continue; + } + if (!strncmp (argv[curarg], "-keyscatterplot", 2)) { + curarg++; + sscanf (argv[curarg], "%lx", &scatterkey); + curarg++; + continue; + } + + if (!strncmp (argv[curarg], "-model", 2)) { + if (model_index >= sizeof(model_these) / sizeof(int)) { + fprintf (stderr, "Too many model requests\n"); + exit (1); + } + curarg++; + model_these[model_index++] = atol (argv [curarg++]); + continue; + } + if (!strncmp (argv[curarg], "-verbose", 2)) { + verbose++; + curarg++; + continue; + } + + fprintf (stderr, "unknown switch '%s'\n", argv[curarg]); + exit (1); + } + + cpel = (u8 *)mapfile(g_ifile); + + if (cpel == NULL) + { + fprintf (stderr, "Couldn't open %s\n", g_ifile); + exit (1); + } + + printf ("Extracting state info from %s\nentry_event %d, exit_event %d\n", + g_ifile, entry_event, exit_event); + if (nokey) { + printf ("All state instances mapped to a single actor chain\n"); + } + + the_trackdef_hash = hash_create (0, sizeof (uword)); + + process_file(cpel, verbose); + exit (0); +} diff --git a/src/tools/perftool/cpelstate.c b/src/tools/perftool/cpelstate.c new file mode 100644 index 00000000000..3fd9ccb9c79 --- /dev/null +++ b/src/tools/perftool/cpelstate.c @@ -0,0 +1,822 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpel.h" +#include + +char *time_format = "%.03d:%.02d:%.02d:%.03d:%.03d "; +static char version[] = "cpelstate 2.0h"; + +#define USEC_PER_MS 1000LL +#define USEC_PER_SECOND (1000*USEC_PER_MS) +#define USEC_PER_MINUTE (60*USEC_PER_SECOND) +#define USEC_PER_HOUR (60*USEC_PER_MINUTE) + +uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */ +uword *the_evtdef_hash; /* (event-id, event-definition) hash */ +uword *the_trackdef_hash; /* (track-id, track-definition) hash */ + +f64 ticks_per_us; +u32 state_event_code = 1; /* default: XR thread-on-cpu */ +int exclude_kernel_from_summary_stats=1; +int summary_stats_only; +int scatterplot; +u8 *name_filter; + +typedef enum { + SORT_MAX_TIME=1, + SORT_MAX_OCCURRENCES, + SORT_NAME, +} sort_t; + +sort_t sort_type = SORT_MAX_TIME; + +int widest_name_format=5; +int widest_track_format=5; + +typedef struct bound_event_ { + u32 event_code; + u8 *event_str; + u8 *datum_str; + u32 is_strtab_ref; +} bound_event_t; + +bound_event_t *bound_events; + +typedef struct bound_track_ { + u32 track; + u8 *track_str; + u64 *ticks_in_state; /* vector of state occurrences */ + f64 mean_ticks_in_state; + f64 variance_ticks_in_state; + f64 total_ticks_in_state; +} bound_track_t; + +bound_track_t *bound_tracks; + +void fatal(char *s) +{ + fprintf(stderr, "%s", s); + exit(1); +} + +typedef enum { + PASS1=1, + PASS2=2, +} pass_t; + +typedef struct { + int (*pass1)(cpel_section_header_t *, int, FILE *); + int (*pass2)(cpel_section_header_t *, int, FILE *); +} section_processor_t; + +int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + fprintf(ofp, "Bad (type 0) section, skipped...\n"); + return(0); +} + +int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + return(0); +} + +int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + uword *p; + u8 *strtab_data_area = (u8 *)(sh+1); + + /* Multiple string tables with the same name are Bad... */ + p = hash_get_mem(the_strtab_hash, strtab_data_area); + if (p) { + fprintf(ofp, "Duplicate string table name %s", strtab_data_area); + } + /* + * Looks funny, but we really do want key = first string in the + * table, value = address(first string in the table) + */ + hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area); + if (verbose) { + fprintf(ofp, "String Table %s\n", strtab_data_area); + } + return(0); +} + +int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + event_definition_section_header_t *edh; + event_definition_t *ep; + u8 *this_strtab; + u32 event_code; + uword *p; + bound_event_t *bp; + int thislen; + + edh = (event_definition_section_header_t *)(sh+1); + nevents = ntohl(edh->number_of_event_definitions); + + if (verbose) { + fprintf(ofp, "Event Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, edh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + ep = (event_definition_t *)(edh+1); + + for (i = 0; i < nevents; i++) { + event_code = ntohl(ep->event); + p = hash_get(the_evtdef_hash, event_code); + if (p) { + fprintf(ofp, "Event %d redefined, retain first definition\n", + event_code); + continue; + } + vec_add2(bound_events, bp, 1); + bp->event_code = event_code; + bp->event_str = this_strtab + ntohl(ep->event_format); + bp->datum_str = this_strtab + ntohl(ep->datum_format); + bp->is_strtab_ref = 0; + /* Decide if the datum format is a %s format => strtab reference */ + { + int j; + int seen_percent=0; + + for (j = 0; j < strlen((char *)(bp->datum_str)); j++) { + if (bp->datum_str[j] == '%'){ + seen_percent=1; + continue; + } + if (seen_percent && bp->datum_str[j] == 's') { + bp->is_strtab_ref = 1; + } + } + } + + hash_set(the_evtdef_hash, event_code, bp - bound_events); + + thislen = strlen((char *)bp->event_str); + if (thislen > widest_name_format) + widest_name_format = thislen; + + ep++; + } + return (0); +} + +int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + int i, nevents; + track_definition_section_header_t *tdh; + track_definition_t *tp; + u8 *this_strtab; + u32 track_code; + uword *p; + bound_track_t *btp; + int thislen; + + tdh = (track_definition_section_header_t *)(sh+1); + nevents = ntohl(tdh->number_of_track_definitions); + + if (verbose) { + fprintf(ofp, "Track Definition Section: %d definitions\n", + nevents); + } + + p = hash_get_mem(the_strtab_hash, tdh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + this_strtab = (u8 *)p[0]; + + tp = (track_definition_t *)(tdh+1); + + for (i = 0; i < nevents; i++) { + track_code = ntohl(tp->track); + p = hash_get(the_trackdef_hash, track_code); + if (p) { + fprintf(ofp, "track %d redefined, retain first definition\n", + track_code); + continue; + } + vec_add2(bound_tracks, btp, 1); + btp->track = track_code; + btp->track_str = this_strtab + ntohl(tp->track_format); + hash_set(the_trackdef_hash, track_code, btp - bound_tracks); + + thislen = strlen((char *)(btp->track_str)); + if (thislen > widest_track_format) + widest_track_format = thislen; + tp++; + } + return (0); +} + +int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + if (verbose) { + fprintf(ofp, "Unsupported type %d section\n", + ntohl(sh->section_type)); + } + return(0); +} + +int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp) +{ + event_section_header_t *eh; + u32 track_code; + int nevents; + int i; + uword *p; + event_entry_t *ep; + u64 now; + u32 time0, time1; + bound_track_t generic_track; + u32 last_track_code; + u64 state_start_ticks=0; + u64 ticks_in_state; + bound_track_t *state_track=0; + int in_state=0; + generic_track.track_str = (u8 *) "%d"; + last_track_code = 0xdeafbeef; + + eh = (event_section_header_t *)(sh+1); + nevents = ntohl(eh->number_of_events); + ticks_per_us = ((double)ntohl(eh->clock_ticks_per_second))/1e6; + + if (verbose) { + fprintf(ofp, "%.3f ticks_per_us\n", ticks_per_us); + } + + ep = (event_entry_t *)(eh+1); + + p = hash_get_mem(the_strtab_hash, eh->string_table_name); + if (!p) { + fprintf(ofp, "Fatal: couldn't find string table\n"); + return(1); + } + + for (i = 0; i < nevents; i++) { + time0 = ntohl (ep->time[0]); + time1 = ntohl (ep->time[1]); + + now = (((u64) time0)<<32) | time1; + + /* Found the state-change event ? */ + if (ntohl(ep->event_code) == state_event_code) { + /* + * Add a ticks-in-state record, unless + * this is the "prime mover" event instance + */ + if (in_state) { + ticks_in_state = now - state_start_ticks; + vec_add1(state_track->ticks_in_state, ticks_in_state); + } + /* switch to now-current track */ + state_start_ticks = now; + track_code = ntohl(ep->track); + if (track_code != last_track_code) { + p = hash_get(the_trackdef_hash, track_code); + if (p) { + state_track = &bound_tracks[p[0]]; + } else { + state_track = &generic_track; + } + last_track_code = track_code; + } + in_state = 1; + } + ep++; + } + return(0); +} + +/* + * Note: If necessary, add passes / columns to this table to + * handle section order dependencies. + */ + +section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] = +{ + {bad_section, noop_pass}, /* type 0 -- f**ked */ + {strtab_pass1, noop_pass}, /* type 1 -- STRTAB */ + {unsupported_pass, noop_pass}, /* type 2 -- SYMTAB */ + {evtdef_pass1, noop_pass}, /* type 3 -- EVTDEF */ + {trackdef_pass1, noop_pass}, /* type 4 -- TRACKDEF */ + {noop_pass, event_pass2}, /* type 5 -- EVENTS */ +}; + + +int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp, + pass_t pass) +{ + u32 type; + type = ntohl(sh->section_type); + int rv; + int (*fp)(cpel_section_header_t *, int, FILE *); + + if (type > CPEL_NUM_SECTION_TYPES) { + fprintf(stderr, "Unknown section type %d\n", type); + return(1); + } + switch(pass) { + case PASS1: + fp = processors[type].pass1; + break; + + case PASS2: + fp = processors[type].pass2; + break; + + default: + fprintf(stderr, "Unknown pass %d\n", pass); + return(1); + } + + rv = (*fp)(sh, verbose, ofp); + + return(rv); +} + +int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp) +{ + time_t file_time; + + if (verbose) { + fprintf(ofp, "CPEL file: %s-endian, version %d\n", + ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? + "little" : "big"), + fh->endian_version & CPEL_FILE_VERSION_MASK); + + file_time = ntohl(fh->file_date); + + fprintf(ofp, "File created %s", ctime(&file_time)); + fprintf(ofp, "File has %d sections\n", + ntohs(fh->nsections)); + } + + return(0); +} + + +int cpel_dump(u8 *cpel, int verbose, FILE *ofp) +{ + cpel_file_header_t *fh; + cpel_section_header_t *sh; + u16 nsections; + u32 section_size; + int i; + + /* First, the file header */ + fh = (cpel_file_header_t *)cpel; + if (fh->endian_version != CPEL_FILE_VERSION) { + if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) { + fprintf(stderr, "Little endian data format not supported\n"); + return(1); + } + fprintf(stderr, "Unsupported file version 0x%x\n", + fh->endian_version); + return(1); + } + cpel_dump_file_header(fh, verbose, ofp); + nsections = ntohs(fh->nsections); + + /* + * Take two passes through the file. PASS1 builds + * data structures, PASS2 actually dumps the file. + * Just in case the sections are in an unobvious order. + */ + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + section_size = ntohl(sh->data_length); + + if(verbose) { + fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type), + section_size); + } + + if(process_section(sh, verbose, ofp, PASS1)) + return(1); + + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + + sh = (cpel_section_header_t *)(fh+1); + for (i = 0; i < nsections; i++) { + if(process_section(sh, verbose, ofp, PASS2)) + return(1); + section_size = ntohl(sh->data_length); + sh++; + sh = (cpel_section_header_t *)(((u8 *)sh)+section_size); + } + return(0); +} + +void compute_state_statistics(int verbose, FILE *ofp) +{ + int i, j; + bound_track_t *bp; + f64 fticks; + + /* Across the bound tracks */ + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + bp->mean_ticks_in_state = 0.0; + bp->variance_ticks_in_state = 0.0; + bp->total_ticks_in_state = 0.0; + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + bp->total_ticks_in_state += (f64) bp->ticks_in_state[j]; + } + /* Compute mean */ + if (vec_len(bp->ticks_in_state)) { + bp->mean_ticks_in_state = bp->total_ticks_in_state / + ((f64) vec_len(bp->ticks_in_state)); + } + /* Accumulate sum: (Xi-Xbar)**2 */ + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fticks = bp->ticks_in_state[j]; + bp->variance_ticks_in_state += + (fticks - bp->mean_ticks_in_state)* + (fticks - bp->mean_ticks_in_state); + } + /* Compute s**2, the unbiased estimator of sigma**2 */ + if (vec_len(bp->ticks_in_state) > 1) { + bp->variance_ticks_in_state /= (f64) + (vec_len(bp->ticks_in_state)-1); + } + } +} + +int track_compare_max (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = a1->total_ticks_in_state; + v2 = a2->total_ticks_in_state; + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_occurrences (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + f64 v1, v2; + + v1 = (f64) vec_len(a1->ticks_in_state); + v2 = (f64) vec_len(a2->ticks_in_state); + + if (v1 < v2) + return (1); + else if (v1 == v2) + return (0); + else return (-1); +} + +int track_compare_name (const void *arg1, const void *arg2) +{ + bound_track_t *a1 = (bound_track_t *)arg1; + bound_track_t *a2 = (bound_track_t *)arg2; + + return (strcmp((char *)(a1->track_str), (char *)(a2->track_str))); +} + +void sort_state_statistics(sort_t type, FILE *ofp) +{ + int (*compare)(const void *, const void *)=0; + + if (summary_stats_only) + return; + + switch(type) { + case SORT_MAX_TIME: + fprintf(ofp, "Results sorted by max time in state.\n"); + compare = track_compare_max; + break; + + case SORT_MAX_OCCURRENCES: + fprintf(ofp, "Results sorted by max occurrences of state.\n"); + compare = track_compare_occurrences; + break; + + case SORT_NAME: + compare = track_compare_name; + fprintf(ofp, "Results sorted by process-id/name/thread ID\n"); + break; + + default: + fatal("sort type not set?"); + } + + qsort (bound_tracks, vec_len(bound_tracks), + sizeof (bound_track_t), compare); +} + +void print_state_statistics(int verbose, FILE *ofp) +{ + int i,j; + u8 *trackpad; + bound_track_t *bp; + f64 total_time = 0.0; + f64 total_switches = 0.0; + + trackpad = format(0, "%%-%ds ", widest_track_format); + vec_add1(trackpad, 0); + + if (!summary_stats_only) { + fprintf(ofp, (char *)trackpad, "ProcThread"); + fprintf(ofp, " Mean(us) Stdev(us) Total(us) N\n"); + } + + for (i = 0; i < vec_len(bound_tracks); i++) { + bp = &bound_tracks[i]; + if (bp->mean_ticks_in_state == 0.0) + continue; + + if (name_filter && + strncmp((char *)(bp->track_str), (char *)name_filter, + strlen((char *)name_filter))) + continue; + + /* + * Exclude kernel threads (e.g. idle thread) from + * state statistics + */ + if (exclude_kernel_from_summary_stats && + !strncmp((char *)(bp->track_str), "kernel ", 7)) + continue; + + total_switches += (f64) vec_len(bp->ticks_in_state); + + if (!summary_stats_only) { + fprintf(ofp, (char *) trackpad, bp->track_str); + fprintf(ofp, "%10.3f +- %10.3f", + bp->mean_ticks_in_state / ticks_per_us, + sqrt(bp->variance_ticks_in_state) + / (f64) ticks_per_us); + fprintf(ofp, "%12.3f", + bp->total_ticks_in_state / ticks_per_us); + fprintf(ofp, "%8d\n", (int)vec_len(bp->ticks_in_state)); + } + + if (scatterplot) { + for (j = 0; j < vec_len(bp->ticks_in_state); j++) { + fprintf(ofp, "%.3f\n", + (f64)bp->ticks_in_state[j] / ticks_per_us); + } + } + + total_time += bp->total_ticks_in_state; + } + + if (!summary_stats_only) + fprintf(ofp, "\n"); + fprintf(ofp, "Note: the following statistics %s kernel-thread activity.\n", + exclude_kernel_from_summary_stats ? "exclude" : "include"); + if (name_filter) + fprintf(ofp, + "Note: only pid/proc/threads matching '%s' are included.\n", + name_filter); + + fprintf(ofp, + "Total runtime: %10.3f (us), Total state switches: %.0f\n", + total_time / ticks_per_us, total_switches); + fprintf(ofp, "Average time in state: %10.3f (us)\n", + (total_time / total_switches) / ticks_per_us); +} + +char *mapfile (char *file) +{ + struct stat statb; + char *rv; + int maphfile; + size_t mapfsize; + + maphfile = open (file, O_RDONLY); + + if (maphfile < 0) + { + fprintf (stderr, "Couldn't read %s, skipping it...\n", file); + return (NULL); + } + + if (fstat (maphfile, &statb) < 0) + { + fprintf (stderr, "Couldn't get size of %s, skipping it...\n", file); + return (NULL); + } + + /* Don't try to mmap directories, FIFOs, semaphores, etc. */ + if (! (statb.st_mode & S_IFREG)) { + fprintf (stderr, "%s is not a regular file, skipping it...\n", file); + return (NULL); + } + + mapfsize = statb.st_size; + + if (mapfsize < 3) + { + fprintf (stderr, "%s zero-length, skipping it...\n", file); + close (maphfile); + return (NULL); + } + + rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); + + if (rv == 0) + { + fprintf (stderr, "%s problem mapping, I quit...\n", file); + exit (-1); + } + close (maphfile); + return (rv); +} + +/* + * main + */ +int main (int argc, char **argv) +{ + char *cpel_file = 0; + char *outputfile = 0; + FILE *ofp; + char *cpel; + int verbose=0; + int curarg=1; + + while (curarg < argc) { + if (!strncmp(argv[curarg], "--input-file", 3)) { + curarg++; + if (curarg < argc) { + cpel_file = argv[curarg]; + curarg++; + continue; + } + fatal("Missing filename after --input-file\n"); + } + if (!strncmp(argv[curarg], "--output-file", 3)) { + curarg ++; + if (curarg < argc) { + outputfile = argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filename after --output-file\n"); + } + if (!strncmp(argv[curarg], "--verbose", 3)) { + curarg++; + verbose++; + continue; + } + if (!strncmp(argv[curarg], "--scatterplot", 4)) { + curarg++; + scatterplot=1; + continue; + } + + if (!strncmp(argv[curarg], "--state-event", 4)) { + curarg++; + if (curarg < argc) { + state_event_code = atol(argv[curarg]); + curarg ++; + continue; + } + fatal("Missing integer after --state-event\n"); + } + if (!strncmp(argv[curarg], "--max-time-sort", 7)) { + sort_type = SORT_MAX_TIME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--max-occurrence-sort", 7)) { + sort_type = SORT_MAX_OCCURRENCES; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--name-sort", 3)) { + sort_type = SORT_NAME; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--kernel-included", 3)) { + exclude_kernel_from_summary_stats = 0; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--summary", 3)) { + summary_stats_only=1; + curarg++; + continue; + } + if (!strncmp(argv[curarg], "--filter", 3)) { + curarg ++; + if (curarg < argc) { + name_filter = (u8 *)argv[curarg]; + curarg ++; + continue; + } + fatal("Missing filter string after --filter\n"); + } + + + usage: + fprintf(stderr, + "cpelstate --input-file [--output-file ]\n"); + fprintf(stderr, + " [--state-event ] [--verbose]\n"); + fprintf(stderr, + " [--max-time-sort(default) | --max-occurrence-sort |\n"); + + fprintf(stderr, + " --name-sort-sort] [--kernel-included]\n"); + + fprintf(stderr, + " [--summary-stats-only] [--scatterplot]\n"); + + fprintf(stderr, "%s\n", version); + exit(1); + } + + if (cpel_file == 0) + goto usage; + + cpel = mapfile(cpel_file); + if (cpel == 0) { + fprintf(stderr, "Couldn't map %s...\n", cpel_file); + exit(1); + } + + if (!outputfile) { + ofp = fdopen(1, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't fdopen(1)?\n"); + exit(1); + } + } else { + ofp = fopen(outputfile, "w"); + if (ofp == NULL) { + fprintf(stderr, "Couldn't create %s...\n", outputfile); + exit(1); + } + } + + the_strtab_hash = hash_create_string (0, sizeof (uword)); + the_evtdef_hash = hash_create (0, sizeof (uword)); + the_trackdef_hash = hash_create (0, sizeof (uword)); + + if (cpel_dump((u8 *) cpel, verbose, ofp)) { + if (outputfile) + unlink(outputfile); + } + + compute_state_statistics(verbose, ofp); + sort_state_statistics(sort_type, ofp); + print_state_statistics(verbose, ofp); + + fclose(ofp); + return(0); +} diff --git a/src/tools/perftool/delsvec.c b/src/tools/perftool/delsvec.c new file mode 100644 index 00000000000..724935d331e --- /dev/null +++ b/src/tools/perftool/delsvec.c @@ -0,0 +1,315 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Break up a delimited string into a vector of substrings */ + +#include +#include +#include +#include +#include + +/* + * #define UNIT_TESTS 1 + * #define MATCH_TRACE 1 + */ + +/* + * delsvec + * break up an input string into a vector of [null-terminated] u8 *'s + * + * Each supplied delimiter character results in a string in the output + * vector, unless the delimiters occur back-to-back. When matched, + * a whitespace character in the delimiter consumes an arbitrary + * run of whitespace. See the unit tests at the end of this file + * for a set of examples. + * + * Returns a u8 **, or NULL if the input fails to match. It is assumed + * that both input and fmt are C strings, not necessarily vectors. + * + * Output strings are both vectors and proper C strings. + */ + +static u8 **string_cache; +static u8 **svec_cache; + +void delsvec_recycle_this_string (u8 *s) +{ + if (s) { + _vec_len (s) = 0; + vec_add1(string_cache, s); + } +} + +void delsvec_recycle_this_svec (u8 **svec) +{ + if (svec) { + if (svec_cache) { + vec_free (svec_cache); + } + _vec_len (svec) = 0; + svec_cache = svec; + } +} + +int pvl (char *a) +{ + return vec_len(a); +} + +u8 **delsvec(void *input_arg, char *fmt) +{ + u8 **rv = 0; + int input_index=0; + u8 *this; + int dirflag=0; + int i; + u8 *input = input_arg; + + if (svec_cache) { + rv = svec_cache; + svec_cache = 0; + } + + while (fmt) { + dirflag=0; + if (vec_len (string_cache) > 0) { + this = string_cache [vec_len(string_cache)-1]; + _vec_len (string_cache) = vec_len (string_cache) - 1; + } else + this = 0; + /* + * '*' means one of two things: match the rest of the input, + * or match as many characters as possible + */ + if (fmt[0] == '*') { + fmt++; + dirflag=1; + /* + * no more format: eat rest of string... + */ + if (!fmt[0]) { + for (;input[input_index]; input_index++) + vec_add1(this, input[input_index]); + if (vec_len(this)) { + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("final star-match adds: '%s'\n", this); +#endif + vec_add1(rv, this); + } else { + vec_add1(string_cache, this); + } + + return(rv); + } + } + /* + * Left-to-right scan, adding chars until next delimiter char + * appears. + */ + if (!dirflag) { + while (input[input_index]) { + if (input[input_index] == fmt[0]) { + /* If we just (exact) matched a whitespace delimiter */ + if (fmt[0] == ' '){ + /* scan forward eating whitespace */ + while (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') + input_index++; + input_index--; + } + goto found; + } + /* If we're looking for whitespace */ + if (fmt[0] == ' ') { + /* and we have whitespace */ + if (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') { + /* scan forward eating whitespace */ + while (input[input_index] == ' ' || + input[input_index] == '\t' || + input[input_index] == '\n') { + input_index++; + } + input_index--; + goto found; + } + } + /* Not a delimiter, save it */ + vec_add1(this, input[input_index]); + input_index++; + } + /* + * Fell off the wagon, clean up and bail out + */ + bail: + +#ifdef MATCH_TRACE + printf("failed, fmt[0] = '%c', input[%d]='%s'\n", + fmt[0], input_index, &input[input_index]); +#endif + delsvec_recycle_this_string(this); + for (i = 0; i < vec_len(rv); i++) + delsvec_recycle_this_string(rv[i]); + delsvec_recycle_this_svec(rv); + return(0); + + found: + /* + * Delimiter matched + */ + input_index++; + fmt++; + /* + * If we actually accumulated non-delimiter characters, + * add them to the result vector + */ + if (vec_len(this)) { + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("match: add '%s'\n", this); +#endif + vec_add1(rv, this); + } else { + vec_add1(string_cache, this); + } + } else { + /* + * right-to-left scan, '*' not at + * the end of the delimiter string + */ + i = input_index; + while (input[++i]) + ; /* scan forward */ + i--; + while (i > input_index) { + if (input[i] == fmt[0]) + goto found2; + + if (fmt[0] == ' ' || fmt[0] == '\t' || + fmt[0] == '\n') { + if (input[i] == ' ' || + input[i] == '\t' || + input[i] == '\n') + goto found2; + } + i--; + } + goto bail; + + found2: + for (; input_index < i; input_index++) { + vec_add1(this, input[input_index]); + } + input_index++; + fmt++; + vec_add1(this, 0); +#ifdef MATCH_TRACE + printf("inner '*' match: add '%s'\n", this); +#endif + vec_add1(rv, this); + } + } + return (rv); +} + +#ifdef UNIT_TESTS + +typedef struct utest_ { + char *string; + char *fmt; +} utest_t; + +utest_t tests[] = { +#ifdef NOTDEF + {"Dec 7 08:56", + " :*"}, + {"Dec 17 08:56", + " :*"}, + {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", + " ::. / // [] *"}, + {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", + "///: ::. : []: *"}, + /* Expected to fail */ + {"Dec 7 08:56:41.239 install/inst_repl 0/9/CPU0 t1 [40989] File List:Successfully blobbified file list. Took 1 milliseconds", + "///: ::. : : *"}, + /* Expected to fail */ + {"RP/0/9/CPU0:Dec 7 08:55:28.550 : sam_server[291]: SAM backs up digest list to memory file", + " ::. / // [] *"}, + {"THIS that and + theother", "*+ *"}, + {"Dec 12 15:33:07.103 ifmgr/errors 0/RP0/CPU0 3# t2 Failed to open IM connection: No such file or directory", " ::. / // *"}, + {"Dec 16 21:43:47.328 ifmgr/bulk 0/3/CPU0 t8 Bulk DPC async download complete. Partitions 1, node_count 1, total_out 0, out_offset 0, out_expected 0: No error"," ::. / // *"}, + {"t:0x53034bd6 CPU:00 PROCESS :PROCCREATE_NAME", + ": : :*"}, + {" pid:1", " *"}, + {"t:0x53034cbb CPU:00 THREAD :THCREATE pid:1 tid:1", + ": : : pid: tid:*"}, + {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", + ": : : *"}, + {"/hfr-base-3.3.85/lib/libttyconnection.dll 0xfc000000 0x0000306c 0xfc027000 0x000001c8 1", + " *"}, + {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_receive:ifmgr/t8:IMC_MSG_MTU_UPDATE:ppp_ma/t1", + " ::. // ::::*"}, + + {"Feb 28 02:38:26.123 seqtrace 0/1/CPU0 t8 :msg_send_event:call:ifmgr/t8:124/0:cdp/t1", + " ::. // :msg_send_event::::*"}, + + {"Feb 28 02:38:26.125 seqtrace 0/1/CPU0 t1 :msg_receive_event:cdp/t1:124/0", + " ::. // :msg_receive_event::*"} + {"t:0x645dd86d CPU:00 USREVENT:EVENT:100, d0:0x00000002 d1:0x00000000", + ": : USREVENT:EVENT:, d0: *"} + {"t:0x5303f950 CPU:00 COMM :REC_PULSE scoid:0x40000003 pid:364659", + ": : : *"}, + {"t:0x2ccf9f5a CPU:00 INT_ENTR:0x80000000 (-2147483648) IP:0x002d8b18", + ": : INT_ENTR: IP:*"} + {"t:0xd473951c CPU:00 KER_EXIT:SCHED_GET/88 ret_val:2 sched_priority:10", + ": : KER_EXIT:SCHED_GET : sched_priority:*"} + {"t:0x00000123 CPU:01 SYSTEM :FUNC_ENTER thisfn:0x40e62048 call_site:0x00000000", + ": : SYSTEM :FUNC_ thisfn: *"}, + {"t:0x5af8de95 CPU:00 INT_HANDLER_ENTR:0x0000004d (77) PID:8200 IP:0x00000000 AREA:0x0bf9b290", ": : INT_HANDLER_*"}, +#endif + {"t:0x6d1ff92f CPU:00 CONTROL: BUFFER sequence = 1053, num_events = 714", + ": : CONTROL*"}, + {"t:0x6d1ff92f CPU:00 CONTROL :TIME msb:0x0000003c lsb(offset):0x6d1ff921", + ": : CONTROL*"}, +}; + +int main (int argc, char **argv) +{ + int i, j; + u8 **svec; + + for (j = 0; j < ARRAY_LEN(tests); j++) { + printf ("input string: '%s'\n", tests[j].string); + printf ("delimiter arg: '%s'\n", tests[j].fmt); + printf ("parse trace:\n"); + svec = delsvec(tests[j].string, tests[j].fmt); + if (!svec) { + printf("index %d failed\n", j); + continue; + } + printf("%d substring vectors\n", vec_len(svec)); + for (i = 0; i < vec_len(svec); i++) { + printf("[%d]: '%s'\n", i, svec[i]); + } + printf ("-------------------\n"); + } + exit(0); +} +#endif diff --git a/src/tools/perftool/linreg.c b/src/tools/perftool/linreg.c new file mode 100644 index 00000000000..084091bb907 --- /dev/null +++ b/src/tools/perftool/linreg.c @@ -0,0 +1,78 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* see "Numerical Recipies in C, 2nd ed." p 665 */ + +#include +#include + +/* + * linreg + * Linear regression of (xi, yi), returns parameters for least-squares + * fit y = a + bx. Also, compute Pearson's R. + */ +void linreg (double *x, double *y, int nitems, double *a, double *b, + double *minp, double *maxp, double *meanp, double *r) +{ + double sx = 0.0; + double sy = 0.0; + double st2 = 0.0; + double min = y[0]; + double max = 0.0; + double ss, meanx, meany, t; + double errx, erry, prodsum, sqerrx, sqerry; + int i; + + *b = 0.0; + + for (i = 0; i < nitems; i++) { + sx += x[i]; + sy += y[i]; + if (y[i] < min) + min = y[i]; + if (y[i] > max) + max = y[i]; + } + ss = nitems; + meanx = sx / ss; + meany = *meanp = sy / ss; + *minp = min; + *maxp = max; + + for (i = 0; i < nitems; i++) { + t = x[i] - meanx; + st2 += t*t; + *b += t*y[i]; + } + + *b /= st2; + *a = (sy-sx*(*b))/ss; + + prodsum = 0.0; + sqerrx = 0.0; + sqerry = 0.0; + + /* Compute numerator of Pearson's R */ + for (i = 0; i < nitems; i++) { + errx = x[i] - meanx; + erry = y[i] - meany; + prodsum += errx * erry; + sqerrx += errx*errx; + sqerry += erry*erry; + } + + *r = prodsum / (sqrt(sqerrx)*sqrt(sqerry)); +} diff --git a/src/tools/perftool/new.cpel b/src/tools/perftool/new.cpel new file mode 100644 index 00000000000..b0f35958dc0 Binary files /dev/null and b/src/tools/perftool/new.cpel differ diff --git a/src/tools/perftool/new.elog b/src/tools/perftool/new.elog new file mode 100644 index 00000000000..2d99bb16b82 Binary files /dev/null and b/src/tools/perftool/new.elog differ diff --git a/src/tools/perftool/props.c b/src/tools/perftool/props.c new file mode 100644 index 00000000000..84af5b1c648 --- /dev/null +++ b/src/tools/perftool/props.c @@ -0,0 +1,280 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2006-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +static char *sxerox (char *s); + +#define NBUCKETS 97 + +typedef struct prop_ { + struct prop_ *next; + char *name; + char *value; +} prop_t; + +static prop_t *buckets [NBUCKETS]; +static int hash_shifts[4] = {24, 16, 8, 0}; + +/* + * getprop + */ + +char *getprop (char *name) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t *bp; + int i=0; + + for (cp = (unsigned char *) name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bp = buckets [hash%NBUCKETS]; + + while (bp && strcmp(bp->name, name)) { + bp = bp->next; + } + + if (bp == NULL) + return (0); + else + return (bp->value); +} + +/* + * getprop_default + */ + +char *getprop_default (char *name, char *def) +{ + char *rv; + rv = getprop (name); + if (rv) + return (rv); + else + return (def); +} + +/* + * addprop + */ + +void addprop (char *name, char *value) +{ + unsigned char *cp; + unsigned long hash=0; + prop_t **bpp; + prop_t *bp; + int i=0; + + bp = (prop_t *)malloc (sizeof (prop_t)); + + bp->next = 0; + bp->name = sxerox (name); + bp->value = sxerox (value); + + for (cp = (unsigned char *)name; *cp; cp++) + hash ^= (*cp)<<(hash_shifts[(i++)&0x3]); + + bpp = &buckets [hash%NBUCKETS]; + + if (*bpp == NULL) + *bpp = bp; + else { + bp->next = *bpp; + *bpp = bp; + } +} + +/* + * sxerox + */ + +static char *sxerox (char *s) +{ + char *rv = (char *) malloc (strlen (s) + 1); + strcpy (rv, s); + return rv; +} + +/* + * readprops + */ + +#define START 0 +#define READNAME 1 +#define READVALUE 2 +#define C_COMMENT 3 +#define CPP_COMMENT 4 + +int readprops (char *filename) +{ + FILE *ifp; + unsigned char c; + int state=START; + int linenum=1; + char namebuf [128]; + char valbuf [512]; + int i; + + ifp = fopen (filename, "r"); + + if (ifp == NULL) + return (-1); + + while (1) { + + readchar: + c = getc (ifp); + + again: + switch (state) { + case START: + if (feof (ifp)) { + fclose (ifp); + return (0); + } + + if (c == ' ' || c == '\t') + goto readchar; + + if (c == '\n') { + linenum++; + goto readchar; + } + if (isalpha (c) || (c == '_')) { + state = READNAME; + goto again; + } + if (c == '/') { + c = getc (ifp); + if (c == '/') { + state = CPP_COMMENT; + goto readchar; + } else if (c == '*') { + state = C_COMMENT; + goto readchar; + } else { + fprintf (stderr, "unknown token '/' line %d\n", + linenum); + exit(1); + } + } + fprintf (stderr, "unknown token '%c' line %d\n", + c, linenum); + exit (1); + break; + + case CPP_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) + return (0); + if (c == '\n') { + linenum++; + state = START; + goto readchar; + } + } + break; + + case C_COMMENT: + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "unterminated comment, line %d\n", + linenum); + exit (1); + } + if (c == '*') { + staragain: + c = getc (ifp); + if (c == '/') { + state = START; + goto readchar; + } + if (c == '*') + goto staragain; + } + } + break; + + case READNAME: + i = 0; + namebuf[i++] = c; + while (1) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a name, line %d\n", + linenum); + exit (1); + } + if ((!isalnum (c)) && (c != '_')) { + namebuf [i] = 0; + state = READVALUE; + goto again; + } + namebuf [i++] = c; + } + break; + + case READVALUE: + i = 0; + while ((c == ' ') || (c == '\t') || (c == '=')) { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF while reading a value, line %d\n", + linenum); + exit (1); + } + } + goto firsttime; + while (1) { + c = getc (ifp); + + firsttime: + if (c == '\\') { + c = getc (ifp); + if (feof (ifp)) { + fprintf (stderr, "EOF after '\\', line %d\n", + linenum); + exit (1); + } + valbuf[i++] = c; + continue; + } + if (c == '\n') { + linenum++; + while (valbuf [i-1] == ' ' || valbuf[i-1] == '\t') + i--; + valbuf[i] = 0; + addprop (namebuf, valbuf); + state = START; + goto readchar; + } + valbuf[i++] = c; + } + + } + } +} diff --git a/src/tools/vppapigen/configure.ac b/src/tools/vppapigen/configure.ac new file mode 100644 index 00000000000..16ad59d286d --- /dev/null +++ b/src/tools/vppapigen/configure.ac @@ -0,0 +1,14 @@ +# -*- Autoconf -*- +# Copyright (c) 2008 by cisco Systems, Inc. +# All rights reserved. +# Process this file with autoconf to produce a configure script. + +AC_INIT(vppapigen, 1.0) +AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_YACC + +AC_OUTPUT([Makefile]) diff --git a/src/tools/vppapigen/gram.y b/src/tools/vppapigen/gram.y new file mode 100644 index 00000000000..de26af8daa0 --- /dev/null +++ b/src/tools/vppapigen/gram.y @@ -0,0 +1,90 @@ +%{ +/* + * gram.y - message definition language + * + * Copyright (c) 2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern void yyerror (char *s); +extern int yylex (void); + +#define YYSTYPE void * + +void generate (YYSTYPE); + YYSTYPE add_slist(YYSTYPE, YYSTYPE); + YYSTYPE add_define(YYSTYPE, YYSTYPE); + YYSTYPE suppress_version(void); + YYSTYPE add_defbody(YYSTYPE, YYSTYPE); + YYSTYPE add_primtype(YYSTYPE, YYSTYPE, YYSTYPE); + YYSTYPE add_complex(YYSTYPE, YYSTYPE); + YYSTYPE add_union(YYSTYPE, YYSTYPE); + YYSTYPE add_scalar_vbl(YYSTYPE); + YYSTYPE add_vector_vbl(YYSTYPE, YYSTYPE); + YYSTYPE add_variable_length_vector_vbl(YYSTYPE, YYSTYPE); + YYSTYPE set_flags(YYSTYPE, YYSTYPE); +%} + +%token NAME RPAR LPAR SEMI LBRACK RBRACK NUMBER PRIMTYPE BARF +%token TPACKED DEFINE LCURLY RCURLY STRING UNION +%token HELPER_STRING COMMA +%token NOVERSION MANUAL_PRINT MANUAL_ENDIAN TYPEONLY DONT_TRACE + +%% + +pgm: slist {generate ($1);} + ; + +slist: slist stmt {$$ = add_slist ($1, $2);} + | stmt {$$ = $1;} + ; + +stmt: flist defn {$$ = set_flags($1, $2);} + | defn {$$ = $1;} + ; + +flist: flist flag {$$ = (YYSTYPE)(unsigned long long) + ((unsigned long long) $1 + | (unsigned long long) $2);} + | flag {$$ = $1;} + ; + +flag: + MANUAL_PRINT {$$ = $1;} + | MANUAL_ENDIAN {$$ = $1;} + | DONT_TRACE {$$ = $1;} + | TYPEONLY {$$ = $1;} + ; + +defn: DEFINE NAME LCURLY defbody RCURLY SEMI + {$$ = add_define($2, $4);} + + | NOVERSION SEMI + {$$ = suppress_version();} + ; + +defbody: defbody onedef {$$ = add_defbody($1, $2);} + | onedef {$$ = $1;} + ; + +onedef: PRIMTYPE vbl SEMI {$$ = add_primtype($1, $2, 0);} + | TPACKED PRIMTYPE vbl SEMI {$$ = add_primtype($1, $2, $3);} + | NAME vbl SEMI {$$ = add_complex($1, $2);} + | UNION NAME LCURLY defbody RCURLY SEMI + {$$ = add_union($2, $4);} + ; + +vbl: NAME {$$ = add_scalar_vbl($1);} + | NAME LBRACK NUMBER RBRACK {$$ = add_vector_vbl($1, $3);} + | NAME LBRACK NAME RBRACK {$$ = add_variable_length_vector_vbl($1, $3);} + ; diff --git a/src/tools/vppapigen/lex.c b/src/tools/vppapigen/lex.c new file mode 100644 index 00000000000..733942add8d --- /dev/null +++ b/src/tools/vppapigen/lex.c @@ -0,0 +1,1067 @@ +/* + *------------------------------------------------------------------ + * lex.c - API generator lexical analyzer + * + * Copyright (c) 1996-2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include + +#include "lex.h" +#include "node.h" +#include "tools/vppapigen/gram.h" + +FILE *ifp, *ofp, *pythonfp, *jsonfp; +char *vlib_app_name = "vpp"; +int dump_tree; +time_t starttime; +char *input_filename; +char *current_filename; +int current_filename_allocated; +unsigned long input_crc; +unsigned long message_crc; +int yydebug; + +/* + * lexer variable definitions + */ + +static const char *version = "0.1"; +static int the_lexer_linenumber = 1; +static enum lex_state the_lexer_state = START_STATE; + +/* + * private prototypes + */ +static void usage (char *); +static int name_check (const char *, YYSTYPE *); +static int name_compare (const char *, const char *); +extern int yydebug; +extern YYSTYPE yylval; + +unsigned int crc32c_table[256] = { + 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, + 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, + 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, + 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, + 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, + 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, + 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, + 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, + 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, + 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, + 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, + 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, + 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, + 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, + 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, + 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, + 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, + 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, + 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, + 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, + 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, + 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, + 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, + 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, + 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, + 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, + 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, + 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, + 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, + 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, + 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, + 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, + 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, + 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, + 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, + 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, + 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, + 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, + 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, + 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, + 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, + 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, + 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, + 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, + 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, + 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, + 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, + 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, + 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, + 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, + 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, + 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, + 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, + 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, + 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, + 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, + 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, + 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, + 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, + 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, + 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, + 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, + 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, + 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 +}; + +static inline unsigned long CRC8 (unsigned long crc, + unsigned char d) +{ + return ((crc >> 8) ^ crc32c_table[(crc ^ d) & 0xFF]); +} +static inline unsigned long CRC16 (unsigned long crc, + unsigned short d) +{ + crc = CRC8 (crc, d & 0xff); + d = d >> 8; + crc = CRC8 (crc, d & 0xff); + return crc; +} + + +static unsigned long +crc_eliding_c_comments (const char *buf, unsigned long crc) +{ + const char *p; + enum { cOTHER, /* */ + cSTRING, /* "... */ + cSBACKSLASH, /* "...\ */ + cCHAR, /* '... */ + cCBACKSLASH, /* '...\ */ + cSLASH, /* / */ + cSLASH_SLASH, /* //... */ + cSLASH_STAR, /* / *... */ + cSTAR /* / *...* */ + } ss = cOTHER; + + for (p = buf; ;) { + unsigned char c = *p++; + + switch (c) { + case 0: + switch (ss) { + case cOTHER: + return (crc); + case cSTRING: case cSBACKSLASH: + case cCHAR: case cCBACKSLASH: + case cSLASH: case cSLASH_SLASH: case cSLASH_STAR: case cSTAR: + fprintf (stderr, "Inopportune EOF: %s\n", buf); + exit (1); + } + break; + case '\"': + switch (ss) { + case cOTHER: ss = cSTRING; break; /* start string */ + case cSTRING: ss = cOTHER; break; /* end string */ + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + break; + case '\\': + switch (ss) { + case cOTHER: break; + case cSTRING: ss = cSBACKSLASH; break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: ss = cCBACKSLASH; break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ; ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + break; + case '/': + switch (ss) { + case cOTHER: ss = cSLASH; continue; /* potential comment */ + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: ss = cSLASH_SLASH; continue; /* start comment */ + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cOTHER; continue; /* end of comment */ + } + break; + case '*': + switch (ss) { + case cOTHER: break; + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: ss = cSLASH_STAR; continue; /* start comment */ + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: ss = cSTAR; continue; /* potential end */ + case cSTAR: continue; /* still potential end of comment */ + } + break; + case '\n': case '\r': case ' ': case '\t': case '\014': + switch (ss) { + case cOTHER: continue; /* ignore all whitespace */ + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: c = '/'; ss = cOTHER; break; + case cSLASH_SLASH: + if (c == '\n' || c == '\r') ss = cOTHER; /* end comment */ + continue; + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + default: + switch (ss) { + case cOTHER: break; + case cSTRING: break; + case cSBACKSLASH: ss = cSTRING; break; + case cCHAR: break; + case cCBACKSLASH: ss = cCHAR; break; + case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break; + case cSLASH_SLASH: continue; /* in comment */ + case cSLASH_STAR: continue; /* in comment */ + case cSTAR: ss = cSLASH_STAR; continue; /* in comment */ + } + } + crc = CRC8 (crc, c); + } +} + +/* + * main + */ +int main (int argc, char **argv) +{ + int curarg = 1; + char *ofile=0; + char *pythonfile=0; + char *jsonfile=0; + char *show_name=0; + + while (curarg < argc) { + if (!strncmp (argv [curarg], "--verbose", 3)) { + fprintf (stderr, "%s version %s\n", argv [0], version); + curarg++; + continue; + } + + if (!strncmp (argv [curarg], "--yydebug", 3)) { + yydebug = 1; + curarg++; + continue; + } + + if (!strncmp (argv [curarg], "--dump", 3)) { + dump_tree = 1; + curarg++; + continue; + } + + if (!strncmp (argv[curarg], "--show-name", 3)) { + curarg++; + if (curarg < argc) { + show_name = argv[curarg]; + curarg++; + continue; + } else { + fprintf(stderr, "Missing filename after --show-name \n"); + exit(1); + } + } + + if (!strncmp (argv [curarg], "--input", 3)) { + curarg++; + if (curarg < argc) { + input_filename = argv[curarg]; + if (!strcmp (argv [curarg], "-")) + ifp = stdin; + else + ifp = fopen (argv [curarg], "r"); + if (ifp == NULL) { + fprintf (stderr, "Couldn't open input file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --input\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--output", 3)) { + curarg++; + if (curarg < argc) { + ofp = fopen (argv[curarg], "w"); + if (ofp == NULL) { + fprintf (stderr, "Couldn't open output file %s\n", + argv[curarg]); + exit (1); + } + ofile = argv[curarg]; + curarg++; + } else { + fprintf(stderr, "Missing filename after --output\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--python", 8)) { + curarg++; + if (curarg < argc) { + if (!strcmp(argv[curarg], "-")) { + pythonfp = stdout; + } else { + pythonfp = fopen(argv[curarg], "w"); + pythonfile = argv[curarg]; + } + if (pythonfp == NULL) { + fprintf (stderr, "Couldn't open python output file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --python\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--json", 6)) { + curarg++; + if (curarg < argc) { + if (!strcmp(argv[curarg], "-")) { + jsonfp = stdout; + } else { + jsonfp = fopen(argv[curarg], "w"); + jsonfile = argv[curarg]; + } + if (jsonfp == NULL) { + fprintf (stderr, "Couldn't open JSON output file %s\n", + argv[curarg]); + exit (1); + } + curarg++; + } else { + fprintf(stderr, "Missing filename after --json\n"); + exit(1); + } + continue; + } + if (!strncmp (argv [curarg], "--app", 4)) { + curarg++; + if (curarg < argc) { + vlib_app_name = argv[curarg]; + curarg++; + } else { + fprintf(stderr, "Missing app name after --app\n"); + exit(1); + } + continue; + } + + usage(argv[0]); + exit (1); + } + if (ofp == NULL) { + ofile = 0; + } + if (pythonfp == NULL) { + pythonfile = 0; + } + if (jsonfp == NULL) { + jsonfile = 0; + } + if (ifp == NULL) { + fprintf(stderr, "No input file specified...\n"); + exit(1); + } + if (show_name) { + input_filename = show_name; + } + + starttime = time (0); + + if (yyparse() == 0) { + fclose (ifp); + curarg -= 2; + if (ofile) { + printf ("Output written to %s\n", ofile); + fclose (ofp); + } + if (pythonfile) { + printf ("Python bindings written to %s\n", pythonfile); + fclose (pythonfp); + } + if (jsonfile) { + printf ("JSON bindings written to %s\n", jsonfile); + fclose (jsonfp); + } + } + else { + fclose (ifp); + if (ofp) + fclose (ofp); + if (ofile) { + printf ("Removing %s\n", ofile); + unlink (ofile); + } + if (pythonfile) { + printf ("Removing %s\n", pythonfile); + unlink (pythonfile); + } + if (jsonfile) { + printf ("Removing %s\n", jsonfile); + unlink (jsonfile); + } + exit (1); + } + exit (0); +} + +/* + * usage + */ +static void usage (char *progname) +{ + fprintf (stderr, + "usage: %s --input [--output ] " + "[--json ] [--python ]\n%s", + progname, + " [--yydebug] [--dump-tree]\n"); + exit (1); +} + +/* + * yyerror + */ +void yyerror (char *s) +{ + fprintf (stderr, "%s:%d %s\n", current_filename, the_lexer_linenumber, s); +} + +static char namebuf [MAXNAME]; + +static inline char +getc_char (FILE *ifp) +{ + return ((char)(getc(ifp) & 0x7f)); +} + +/* + * yylex (well, yylex_1: The real yylex below does crc-hackery) + */ +static int yylex_1 (void) +{ + int nameidx=0; + char c; + enum { LP_INITIAL_WHITESPACE, LP_LINE_NUMBER, + LP_PRE_FILENAME_WHITESPACE, LP_FILENAME, + LP_POST_FILENAME, + LP_OTHER + } lp_substate = LP_INITIAL_WHITESPACE; + + again: + switch (the_lexer_state) { + /* + * START state -- looking for something interesting + */ + case START_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + switch (c) { + case '\n': + the_lexer_linenumber++; + goto again; + + case '#': + the_lexer_state = LINE_PRAGMA_STATE; + lp_substate = LP_INITIAL_WHITESPACE; + goto again; + + /* FALLTHROUGH */ + case '\t': + case ' ': + goto again; + + case '(': + return (LPAR); + + case ')': + return (RPAR); + + case ';': + return (SEMI); + + case '[': + return (LBRACK); + + case ']': + return (RBRACK); + + case '{': + return (LCURLY); + + case '}': + return (RCURLY); + + case ',': + return (COMMA); + + case '"': + nameidx = 0; + the_lexer_state = STRING_STATE; + goto again; + + case '@': + nameidx = 0; + the_lexer_state = HELPER_STATE; + goto again; + + case '/': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (c == '/') { + the_lexer_state = CPP_COMMENT_STATE; + goto again; + } else if (c == '*') { + the_lexer_state = C_COMMENT_STATE; + goto again; + } else { + fprintf (stderr, "unknown token /%c at line %d\n", + c, the_lexer_linenumber); + return (BARF); + } + + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + /* Note fallthrough... */ + + default: + if (isalpha (c) || c == '_') { + namebuf [0] = c; + nameidx = 1; + the_lexer_state = NAME_STATE; + goto again; + } else if (isdigit(c)) { + namebuf [0] = c; + nameidx = 1; + the_lexer_state = NUMBER_STATE; + goto again; + } + + fprintf (stderr, "unknown token %c at line %d\n", + c, the_lexer_linenumber); + return (BARF); + } + + /* + * NAME state -- eat the rest of a name + */ + case NAME_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (!isalnum (c) && c != '_') { + ungetc (c, ifp); + namebuf [nameidx] = 0; + the_lexer_state = START_STATE; + return (name_check (namebuf, &yylval)); + } + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf [nameidx++] = c; + goto again; + + /* + * NUMBER state -- eat the rest of a number + */ + case NUMBER_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + + if (!isdigit (c)) { + ungetc (c, ifp); + namebuf [nameidx] = 0; + the_lexer_state = START_STATE; + yylval = (void *) atol(namebuf); + return (NUMBER); + } + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf [nameidx++] = c; + goto again; + + /* + * C_COMMENT state -- eat a peach + */ + case C_COMMENT_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '*') { + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '/') { + the_lexer_state = START_STATE; + goto again; + } + } + if (c == '\n') + the_lexer_linenumber++; + goto again; + + /* + * CPP_COMMENT state -- eat a plum + */ + + case CPP_COMMENT_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + if (c == '\n') { + the_lexer_linenumber++; + the_lexer_state = START_STATE; + goto again; + } + goto again; + + case STRING_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + switch (c) { + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + namebuf[nameidx++] = c; + goto again; + + case '"': + namebuf[nameidx] = 0; + yylval = (YYSTYPE) sxerox (namebuf); + the_lexer_state = START_STATE; + return (STRING); + + default: + if (c == '\n') + the_lexer_linenumber++; + + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf[nameidx++] = c; + goto again; + } + break; + + case HELPER_STATE: + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + switch (c) { + case '\\': + c = getc_char (ifp); + if (feof (ifp)) + return (EOF); + namebuf[nameidx] = c; + goto again; + + case '@': + namebuf[nameidx] = 0; + yylval = (YYSTYPE) sxerox (namebuf); + the_lexer_state = START_STATE; + return (HELPER_STRING); + + default: + if (c == '\n') + the_lexer_linenumber++; + + /* + * CPP makes it approximately impossible to + * type "#define FOO 123", so we provide a + * lexical trick to achieve that result + */ + + if (c == '$') + c = '#'; + + if (nameidx >= (MAXNAME-1)) { + fprintf(stderr, "lex input buffer overflow...\n"); + exit(1); + } + namebuf[nameidx++] = c; + goto again; + } + break; + + case LINE_PRAGMA_STATE: + /* We're only interested in lines of the form # 259 "foo.c" 17 */ + + switch (lp_substate) { + + case LP_INITIAL_WHITESPACE: /* no number seen yet */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + if (c >= '0' && c <= '9') { + namebuf[nameidx++] = c; + lp_substate = LP_LINE_NUMBER; + } else if (c == '\n') { + goto lp_end_of_line; + } else if (c != ' ' && c != '\t') { + /* Nothing */ + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_LINE_NUMBER: /* eating linenumber */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + if (c >= '0' && c <= '9') { + namebuf[nameidx++] = c; + } else if (c == ' ' || c == '\t') { + namebuf[nameidx++] = 0; + the_lexer_linenumber = atol(namebuf); + lp_substate = LP_PRE_FILENAME_WHITESPACE; + } else if (c == '\n') { + goto lp_end_of_line; + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_PRE_FILENAME_WHITESPACE: /* awaiting filename */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '"') { + lp_substate = LP_FILENAME; + nameidx = 0; + } else if (c == ' ' || c == '\t') { + /* nothing */ + } else if (c == '\n') { + goto lp_end_of_line; + } else { + lp_substate = LP_OTHER; + } + goto again; + + case LP_FILENAME: /* eating filename */ + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '"') { + lp_substate = LP_POST_FILENAME; + namebuf[nameidx] = 0; + } else if (c == '\n') { + goto lp_end_of_line; /* syntax error... */ + } else { + namebuf[nameidx++] = c; + } + goto again; + + case LP_POST_FILENAME: /* ignoring rest of line */ + case LP_OTHER: + c = getc_char(ifp); + if (feof(ifp)) + return(EOF); + + if (c == '\n') { + if (lp_substate == LP_POST_FILENAME) { + if (current_filename_allocated) { + current_filename_allocated = 0; + free(current_filename); + } + + if (!strcmp(namebuf, "")) { + current_filename = input_filename; + } else { + current_filename = sxerox(namebuf); + current_filename_allocated = 1; + } + } + lp_end_of_line: + the_lexer_state = START_STATE; + nameidx = 0; + } + goto again; + } + break; + } + fprintf (stderr, "LEXER BUG!\n"); + exit (1); + /* NOTREACHED */ + return (0); +} + +/* + * Parse a token and side-effect input_crc + * in a whitespace- and comment-insensitive fashion. + */ +int yylex (void) +{ + /* + * Accumulate a crc32-based signature while processing the + * input file. The goal is to come up with a magic number + * which changes precisely when the original input file changes + * but which ignores whitespace changes. + */ + unsigned long crc = input_crc; + int node_type = yylex_1 (); + unsigned long crc2 = message_crc; + int use_helper_string = 0; + unsigned short code; + + switch (node_type) { + case PRIMTYPE: + case NAME: + case NUMBER: + case STRING: + case HELPER_STRING: + use_helper_string = 1; + break; + + /* Other node types have no "substate" */ + /* This code is written in this curious fashion because we + * want the generated CRC to be independent of the particular + * values a particular version of lex/bison assigned to various states. + */ + + case RPAR: code = 258; break; + case LPAR: code = 259; break; + case SEMI: code = 260; break; + case LBRACK: code = 261; break; + case RBRACK: code = 262; break; + case BARF: code = 265; break; + case TPACKED: code = 266; break; + case DEFINE: code = 267; break; + case LCURLY: code = 268; break; + case RCURLY: code = 269; break; + case UNION: code = 271; break; + case COMMA: code = 273; break; + case NOVERSION: code = 274; break; + case MANUAL_PRINT: code = 275; break; + case MANUAL_ENDIAN: code = 276; break; + case TYPEONLY: code = 278; break; + case DONT_TRACE: code = 279; break; + + case EOF: code = ~0; break; /* hysterical compatibility */ + + default: + fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n", + node_type); + exit(1); + } + + if (use_helper_string) + { + /* We know these types accumulated token text into namebuf */ + /* HELPER_STRING may still contain C comments. Argh. */ + crc = crc_eliding_c_comments (namebuf, crc); + crc2 = crc_eliding_c_comments (namebuf, crc2); + } else + { + crc = CRC16 (crc, code); + crc2 = CRC16 (crc2, code); + } + + input_crc = crc; + message_crc = crc2; + return (node_type); +} + +/* + * name_check -- see if the name we just ate + * matches a known keyword. If so, set yylval + * to a new instance of , and return PARSER_MACRO + * + * Otherwise, set yylval to sxerox (s) and return NAME + */ + +static struct keytab { + char *name; + enum node_subclass subclass_id; +} keytab [] = +/* Keep the table sorted, binary search used below! */ +{ + {"define", NODE_DEFINE}, + {"dont_trace", NODE_DONT_TRACE}, + {"f64", NODE_F64}, + {"i16", NODE_I16}, + {"i32", NODE_I32}, + {"i64", NODE_I64}, + {"i8", NODE_I8}, + {"manual_endian", NODE_MANUAL_ENDIAN}, + {"manual_print", NODE_MANUAL_PRINT}, + {"noversion", NODE_NOVERSION}, + {"packed", NODE_PACKED}, + {"typeonly", NODE_TYPEONLY}, + {"u16", NODE_U16}, + {"u32", NODE_U32}, + {"u64", NODE_U64}, + {"u8", NODE_U8}, + {"union", NODE_UNION}, + {"uword", NODE_UWORD}, +}; + +static int name_check (const char *s, YYSTYPE *token_value) +{ + enum node_subclass subclass_id; + int top, bot, mid; + int result; + + for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1; + bot >= top; ) { + mid = (top + bot) / 2; + result = name_compare (s, keytab[mid].name); + if (result < 0) + bot = mid - 1; + else if (result > 0) + top = mid + 1; + else { + subclass_id = keytab[mid].subclass_id; + + switch (subclass_id) { + case NODE_U8: + case NODE_U16: + case NODE_U32: + case NODE_U64: + case NODE_I8: + case NODE_I16: + case NODE_I32: + case NODE_I64: + case NODE_F64: + case NODE_UWORD: + *token_value = make_node(subclass_id); + return (PRIMTYPE); + + case NODE_PACKED: + *token_value = make_node(subclass_id); + return (TPACKED); + + case NODE_DEFINE: + message_crc = 0; + *token_value = make_node(subclass_id); + return(DEFINE); + + case NODE_MANUAL_PRINT: + *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT; + return (MANUAL_PRINT); + + case NODE_MANUAL_ENDIAN: + *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN; + return (MANUAL_ENDIAN); + + case NODE_TYPEONLY: + *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY; + return(TYPEONLY); + + case NODE_DONT_TRACE: + *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE; + return(DONT_TRACE); + + case NODE_NOVERSION: + return(NOVERSION); + + case NODE_UNION: + return(UNION); + + default: + fprintf (stderr, "fatal: keytab botch!\n"); + exit (1); + } + } + } + *token_value = (YYSTYPE) sxerox (s); + return (NAME); +} + +/* + * sxerox + */ + +char *sxerox (const char *s) +{ + int len = strlen (s); + char *rv; + + rv = (char *) malloc (len+1); + if (rv == 0) { + fprintf(stderr, "Out of memory..."); + exit (1); + } + + strcpy (rv, s); + return (rv); +} + +/* + * name_compare + */ + +int name_compare (const char *s1, const char *s2) +{ + char c1, c2; + + while (*s1 && *s2) { + c1 = *s1++; + c2 = *s2++; + + c1 = tolower (c1); + c2 = tolower (c2); + if (c1 < c2) + return (-1); + else if (c1 > c2) + return (1); + } + if (*s1 < *s2) + return (-1); + else if (*s1 > *s2) + return (1); + return (0); +} diff --git a/src/tools/vppapigen/lex.h b/src/tools/vppapigen/lex.h new file mode 100644 index 00000000000..a0fdc735b74 --- /dev/null +++ b/src/tools/vppapigen/lex.h @@ -0,0 +1,50 @@ +/* + *------------------------------------------------------------------ + * lex.h - definitions for the api generator's lexical + * analyzer. + * + * Copyright (c) 1996-2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef _LEX_H_ +#define _LEX_H_ 1 + +extern int yylex (void); +extern void yyerror (char *); +extern int yyparse (void); + +#ifndef YYSTYPE +#define YYSTYPE void * +#endif + +#include "tools/vppapigen/gram.h" + +enum lex_state { + START_STATE = 1, + NAME_STATE, + NUMBER_STATE, + C_COMMENT_STATE, + CPP_COMMENT_STATE, + STRING_STATE, + HELPER_STATE, + LINE_PRAGMA_STATE, +}; + +#define MAXNAME 64000 + +extern unsigned long input_crc; +extern unsigned long message_crc; + +#endif /* _LEX_H_ */ diff --git a/src/tools/vppapigen/node.c b/src/tools/vppapigen/node.c new file mode 100644 index 00000000000..260c6f2ef7b --- /dev/null +++ b/src/tools/vppapigen/node.c @@ -0,0 +1,1527 @@ +/* + *------------------------------------------------------------------ + * node.c - the api generator's semantic back-end + * + * Copyright (c) 2004-2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lex.h" +#include "node.h" + +#define YYSTYPE void * + +FILE *ofp; +FILE *pythonfp; +FILE *jsonfp; +time_t starttime; +char *vlib_app_name; +char *input_filename; +node_vft_t *the_vft[NODE_N_TYPES]; +static int indent; +static int dont_output_version; +int dump_tree; +static char *fixed_name; +static char tmpbuf [MAXNAME]; +static char *current_def_name; +static char *current_union_name; +static char *current_type_fmt; +static char *current_type_cast; +static char current_id; +static char current_is_complex; +static char *current_endianfun; +static char *current_type_name; + +void indent_me(FILE *ofp) +{ + int i; + + for (i = 0; i < indent; i++) + putc(' ', ofp); +} + +char *uppercase (char *s) +{ + char *cp; + + cp = tmpbuf; + + while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) { + if (*s >= 'a' && *s <= 'z') + *cp++ = *s++ - ('a' - 'A'); + else + *cp++ = *s++; + } + *cp = 0; + return(tmpbuf); +} + +char *lowercase (char *s) +{ + char *cp; + + cp = tmpbuf; + + while (*s && (cp < tmpbuf + (sizeof(tmpbuf)-1))) { + if (*s >= 'A' && *s <= 'Z') + *cp++ = *s++ + ('a' - 'A'); + else + *cp++ = *s++; + } + *cp = 0; + return(tmpbuf); +} + +void primtype_recursive_print(node_t *this, i8 *fmt) +{ + fputs((char *)fmt, stdout); + + if (this->deeper) { + node_vft_t *vftp = the_vft[this->deeper->type]; + vftp->print(this->deeper); + } +} + +void primtype_recursive_generate(node_t *this, enum passid which, FILE *ofp, + i8 *type_name, i8 *type_fmt, i8 *type_cast) +{ + node_vft_t *vftp; + + current_type_name = (char *)type_name; + current_type_cast = (char *)type_cast; + + switch(which) { + case TYPEDEF_PASS: + fputs((char *)type_name, ofp); + fputs(" ", ofp); + break; + + case PRINTFUN_PASS: + current_type_fmt = (char *)type_fmt; + break; + + case ENDIANFUN_PASS: + vftp = the_vft[this->type]; + current_endianfun = vftp->endian_converter; + break; + + case PYTHON_PASS: + fputs("('", pythonfp); + fputs((char *)type_name, pythonfp); + fputs("', ", pythonfp); + break; + + case JSON_PASS: + fputs("[\"", jsonfp); + fputs((char *)type_name, jsonfp); + fputs("\", ", jsonfp); + break; + + default: + fprintf(stderr, "primtype_recursive_generate: unimp pass %d\n", which); + break; + } + + if (this->deeper) { + vftp = the_vft[this->deeper->type]; + vftp->generate(this->deeper, which, ofp); + } +} + +void node_illegal_print (node_t *this) +{ + fprintf(stderr, "node_illegal_print called\n"); + exit(0); +} + +void node_illegal_generate (node_t *this, enum passid notused, FILE *ofp) +{ + fprintf(stderr, "node_illegal_generate called\n"); + exit(0); +} + +node_vft_t node_illegal_vft = { + node_illegal_print, + node_illegal_generate, + "illegal" +}; + +void node_u8_print (node_t *this) +{ + primtype_recursive_print(this, "u8 "); +} + +void node_u8_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u8", "%u", "(unsigned)"); +} + +node_vft_t node_u8_vft = { + node_u8_print, + node_u8_generate, + NULL +}; + +void node_u16_print (node_t *this) +{ + primtype_recursive_print(this, "u16 "); +} + +void node_u16_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u16", "%u", "(unsigned)"); +} + +node_vft_t node_u16_vft = { + node_u16_print, + node_u16_generate, + "clib_net_to_host_u16" +}; + +void node_u32_print (node_t *this) +{ + primtype_recursive_print(this, "u32 "); +} + +void node_u32_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u32", "%u", "(unsigned)"); +} + +node_vft_t node_u32_vft = { + node_u32_print, + node_u32_generate, + "clib_net_to_host_u32", +}; + +void node_u64_print (node_t *this) +{ + primtype_recursive_print(this, "u64 "); +} + +void node_u64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "u64", "%llu", + "(long long)"); +} + +node_vft_t node_u64_vft = { + node_u64_print, + node_u64_generate, + "clib_net_to_host_u64" +}; + +void node_i8_print (node_t *this) +{ + primtype_recursive_print(this, "i8 "); +} + +void node_i8_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i8", "%d", "(int)"); +} + +node_vft_t node_i8_vft = { + node_i8_print, + node_i8_generate, + "" +}; + +void node_i16_print (node_t *this) +{ + primtype_recursive_print(this, "i16 "); +} + +void node_i16_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i16", "%d", "(int)"); +} + +node_vft_t node_i16_vft = { + node_i16_print, + node_i16_generate, + "clib_net_to_host_u16" +}; + +void node_i32_print (node_t *this) +{ + primtype_recursive_print(this, "i32 "); +} + +void node_i32_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i32", "%ld", "(long)"); +} + +node_vft_t node_i32_vft = { + node_i32_print, + node_i32_generate, + "clib_net_to_host_u32" +}; + +void node_i64_print (node_t *this) +{ + primtype_recursive_print(this, "i64 "); +} + +void node_i64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "i64", "%lld", + "(long long)"); +} + +node_vft_t node_i64_vft = { + node_i64_print, + node_i64_generate, + "clib_net_to_host_u64" +}; + +void node_f64_print (node_t *this) +{ + primtype_recursive_print(this, "f64 "); +} + +void node_f64_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "f64", "%.2f", + "(double)"); +} + +node_vft_t node_f64_vft = { + node_f64_print, + node_f64_generate, + " ", /* FP numbers are sent in host byte order */ +}; + + +void node_packed_print (node_t *this) +{ + primtype_recursive_print (this, "packed "); +} + +void node_packed_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "PACKED", "", ""); +} + +node_vft_t node_packed_vft = { + node_packed_print, + node_packed_generate, + 0, +}; + +void node_define_print (node_t *this) +{ + fprintf(stdout, "define %s {\n", CDATA0); + if (this->deeper) { + node_vft_t *vftp = the_vft[this->deeper->type]; + fprintf(stdout, " "); + vftp->print(this->deeper); + } + fprintf(stdout, "};\n"); +} + +void node_define_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *child; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "typedef VL_API_PACKED(struct _vl_api_%s {\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + fprintf(fp, "}) vl_api_%s_t;\n\n", CDATA0); + break; + + case ENDIANFUN_PASS: + case PRINTFUN_PASS: + child = this->deeper; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + vftp->generate(child, which, fp); + child = child->peer; + } + break; + + case PYTHON_PASS: + fprintf(fp, "('%s',\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + fprintf(fp, "),\n\n"); + break; + + case JSON_PASS: + fprintf(fp, "[\"%s\",\n", CDATA0); + child = this->deeper; + indent += 4; + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + fprintf(fp, ",\n"); + } + indent_me(fp); + fprintf (fp, "{\"crc\" : \"0x%08x\"}\n", (u32)(u64)CDATA3); + indent -= 4; + indent_me(fp); + fprintf(fp, "]"); + break; + + default: + fprintf(stderr, "node_define_generate: unimp pass %d\n", which); + break; + } +} + +node_vft_t node_define_vft = { + node_define_print, + node_define_generate, + 0, +}; + +void node_union_print (node_t *this) +{ + primtype_recursive_print (this, "union "); +} + +void node_union_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *child; + node_t *uelem; + int case_id=1; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "u8 _%s_which;\n", CDATA0); + indent_me(fp); + fprintf(fp, "union _%s {\n", CDATA0); + child = this->deeper; + indent += 4; + + while (child) { + node_vft_t *vftp = the_vft[child->type]; + indent_me(fp); + vftp->generate(child, which, fp); + child = child->peer; + } + indent -= 4; + indent_me(fp); + fprintf(fp, "} %s;\n", CDATA0); + break; + + case PRINTFUN_PASS: + case ENDIANFUN_PASS: + uelem = this->deeper; + + indent_me(fp); + fprintf(fp, "switch(a->_%s_which) {\n", + CDATA0); + indent += 4; + current_union_name = CDATA0; + + /* Walk the list of objects in this union */ + while (uelem) { + node_vft_t *vftp = the_vft[uelem->type]; + indent -= 4; + indent_me(fp); + fprintf(fp, "case %d:\n", case_id); + case_id++; + indent += 4; + /* Drill down on each element */ + vftp->generate(uelem, which, fp); + indent_me(fp); + fprintf(fp, "break;\n"); + uelem = uelem->peer; + } + current_union_name = 0; + indent -= 4; + indent_me(fp); + fprintf(fp, "default:\n"); + indent += 4; + indent_me(fp); + if (which == PRINTFUN_PASS) { + fprintf(fp, + "vl_print(handle, \"WARNING: _%s_which not set.\\n\");\n", + CDATA0); + } + indent_me(fp); + fprintf(fp, "break;\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + + default: + fprintf(stderr, "node_union_generate: unimp pass %d\n", which); + break; + } +} + + +node_vft_t node_union_vft = { + node_union_print, + node_union_generate, + 0, +}; + +void node_scalar_print (node_t *this) +{ + fprintf(stdout, "%s", CDATA0); + primtype_recursive_print (this, ""); +} + +void node_scalar_generate (node_t *this, enum passid which, FILE *fp) +{ + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s;\n", CDATA0); + break; + + case PRINTFUN_PASS: + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_api_%s_t_print(a->%s%s, handle);\n", + current_type_name, union_prefix, CDATA0); + } else { + if (!strcmp(current_type_fmt, "uword")) { + fprintf(fp, + "vl_print(handle, \"%s%s: \" _uword_fmt \"\\n\", %s a->%s%s);\n", + union_prefix, CDATA0, "(_uword_cast)", + union_prefix, CDATA0); + } else { + fprintf(fp, + "vl_print(handle, \"%s%s: %s\\n\", %s a->%s%s);\n", + union_prefix, CDATA0, + current_type_fmt, current_type_cast, + union_prefix, CDATA0); + } + } + break; + + case ENDIANFUN_PASS: + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_api%s_t_endian(a->%s%s);\n", + current_type_name, union_prefix, CDATA0); + } else { + /* Current_endianfun == NULL means e.g. it's a u8... */ + if (current_endianfun) { + fprintf(fp, "a->%s%s = %s(a->%s%s);\n", union_prefix, + CDATA0, current_endianfun, + union_prefix, CDATA0); + } else { + fprintf(fp, "/* a->%s%s = a->%s%s (no-op) */\n", + union_prefix, CDATA0, + union_prefix, CDATA0); + } + } + break; + case PYTHON_PASS: + fprintf(fp, "'%s'),\n", CDATA0); + break; + + case JSON_PASS: + fprintf(fp, "\"%s\"]", CDATA0); + break; + + default: + fprintf(stderr, "node_scalar_generate: unimp pass %d\n", which); + } + if (this->deeper) { + fprintf(stderr, "broken recursion in node_scalar_generate\n"); + } +} + + +node_vft_t node_scalar_vft = { + node_scalar_print, + node_scalar_generate, + 0, +}; + +void node_vector_print (node_t *this) +{ + primtype_recursive_print (this, "vector "); +} + +void node_vector_generate (node_t *this, enum passid which, FILE *fp) +{ + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s[%d];\n", CDATA0, IDATA1); + break; + + case PRINTFUN_PASS: + /* Don't bother about "u8 data [0];" et al. */ + if (IDATA1 == 0) + break; + + indent_me(fp); + fprintf(fp, "{\n"); + indent += 4; + indent_me(fp); + fprintf(fp, "int _i;\n"); + indent_me(fp); + fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", + IDATA1); + indent += 4; + indent_me(fp); + if (current_is_complex) { + fprintf(fp, "vl_print(handle, \"%s%s[%%d]: ", + union_prefix, CDATA0); + fprintf(fp, + "vl_print_%s (handle, a->%s%s[_i]);\n", + CDATA0, union_prefix, CDATA0); + } else { + fprintf(fp, + "vl_print(handle, \"%s%s[%%d]: %s\\n\", _i, a->%s%s[_i]);\n", + union_prefix, CDATA0, + current_type_fmt, + union_prefix, CDATA0); + } + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + + case ENDIANFUN_PASS: + /* Don't bother about "u8 data [0];" et al. */ + if (IDATA1 == 0) + break; + /* If this is a simple endian swap, but the endian swap method is a no-op, + * then indicate this is a no-op in a comment. + */ + if (!current_is_complex && current_endianfun == NULL) { + indent_me(fp); + fprintf(fp, "/* a->%s%s[0..%d] = a->%s%s[0..%d] (no-op) */\n", + union_prefix, CDATA0, IDATA1 - 1, + union_prefix, CDATA0, IDATA1 - 1); + break; + } + + indent_me(fp); + fprintf(fp, "{\n"); + indent += 4; + indent_me(fp); + fprintf(fp, "int _i;\n"); + indent_me(fp); + fprintf(fp, "for (_i = 0; _i < %d; _i++) {\n", + IDATA1); + indent += 4; + indent_me(fp); + if (current_is_complex) { + fprintf(fp, + "vl_api_%s_t_endian (a->%s%s[_i]);\n", + current_type_name, union_prefix, CDATA0); + } else { + fprintf(fp, + "a->%s%s[_i] = %s(a->%s%s[_i]);\n", + union_prefix, CDATA0, + current_endianfun, + union_prefix, CDATA0); + } + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + indent -= 4; + indent_me(fp); + fprintf(fp, "}\n"); + break; + case PYTHON_PASS: + if (CDATA2 != 0) { // variable length vector + fprintf(fp, "'%s', '%d', '%s'),\n", CDATA0, IDATA1, CDATA2); + } else { + fprintf(fp, "'%s', '%d'),\n", CDATA0, IDATA1); + } + break; + + case JSON_PASS: + if (CDATA2 != 0) { /* variable length vector */ + fprintf(fp, "\"%s\", %d, \"%s\"]", CDATA0, IDATA1, CDATA2); + } else { + fprintf(fp, "\"%s\", %d]", CDATA0, IDATA1); + } + break; + + default: + fprintf(stderr, "node_vector_generate: unimp pass %d\n", which); + } + if (this->deeper) { + fprintf(stderr, "broken recursion in node_vector_generate\n"); + } +} + +node_vft_t node_vector_vft = { + node_vector_print, + node_vector_generate, + 0, +}; + +void node_complex_print (node_t *this) +{ + primtype_recursive_print (this, "complex "); +} + +void node_complex_generate (node_t *this, enum passid which, FILE *fp) +{ + node_t *deeper; + node_vft_t *vftp; + char *member_name = "broken!"; + char *union_prefix = ""; + + if (current_union_name) { + sprintf(tmpbuf, "%s.", current_union_name); + union_prefix = tmpbuf; + } + + current_is_complex++; + + switch(which) { + case TYPEDEF_PASS: + fprintf(fp, "%s ", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + case PRINTFUN_PASS: + deeper = this->deeper; + while (deeper) { + if (deeper->type == NODE_SCALAR || + deeper->type == NODE_VECTOR) { + member_name = deeper->data[0]; + break; + } + deeper = deeper->deeper; + } + indent_me(fp); + fprintf(fp, "vl_print(handle, \"%s%s ----- \\n\");\n", + union_prefix, member_name); + indent_me(fp); + fprintf(fp, "%s_print(&a->%s%s, handle);\n", + CDATA0, union_prefix, member_name); + indent_me(fp); + fprintf(fp, "vl_print(handle, \"%s%s ----- END \\n\");\n", + union_prefix, member_name); + break; + + case ENDIANFUN_PASS: + deeper = this->deeper; + while (deeper) { + if (deeper->type == NODE_SCALAR || + deeper->type == NODE_VECTOR) { + member_name = deeper->data[0]; + break; + } + deeper = deeper->deeper; + } + + indent_me(fp); + fprintf(fp, "%s_endian(&a->%s%s);\n", + CDATA0, union_prefix, member_name); + break; + case PYTHON_PASS: + fprintf(fp, "('%s',", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + case JSON_PASS: + fprintf(fp, "[\"%s\", ", CDATA0); + deeper = this->deeper; + if (deeper) { + vftp = the_vft[deeper->type]; + vftp->generate(deeper, which, fp); + } + break; + + default: + fprintf(stderr, "node_complex_generate unimp pass %d...\n", which); + break; + } + current_is_complex--; +} + +node_vft_t node_complex_vft = { + node_complex_print, + node_complex_generate, + 0, +}; + +void node_noversion_print (node_t *this) +{ + primtype_recursive_print (this, "noversion "); +} + +void node_noversion_generate (node_t *this, enum passid which, FILE *ofp) +{ + fprintf(stderr, "node_noversion_generate called...\n"); +} + +node_vft_t node_noversion_vft = { + node_noversion_print, + node_noversion_generate, + 0, +}; + +void node_uword_print (node_t *this) +{ + primtype_recursive_print(this, "uword "); +} + +void node_uword_generate (node_t *this, enum passid which, FILE *ofp) +{ + primtype_recursive_generate(this, which, ofp, "uword", "uword", ""); +} + +node_vft_t node_uword_vft = { + node_uword_print, + node_uword_generate, + "clib_net_to_host_uword", +}; + +node_vft_t *the_vft[NODE_N_TYPES] = { + &node_illegal_vft, + &node_u8_vft, + &node_u16_vft, + &node_u32_vft, + &node_u64_vft, + &node_i8_vft, + &node_i16_vft, + &node_i32_vft, + &node_i64_vft, + &node_f64_vft, + &node_packed_vft, + &node_define_vft, + &node_union_vft, + &node_scalar_vft, + &node_vector_vft, + &node_complex_vft, + &node_noversion_vft, + &node_uword_vft, +}; + +void *make_node (enum node_subclass type) +{ + node_t *rv; + + rv = (node_t *) malloc (sizeof (*rv)); + if (rv == 0) { + fprintf (stderr, "fatal: make_node out of memory\n"); + exit (1); + } + bzero (rv, sizeof (*rv)); + rv->type = type; + return ((void *) rv); +} + +YYSTYPE deeper (YYSTYPE arg1, YYSTYPE arg2) +{ + node_t *np1 = (node_t *) arg1; + node_t *np2 = (node_t *) arg2; + node_t *hook_point; + + hook_point = np1; + + while (hook_point->deeper) + hook_point = hook_point->deeper; + + hook_point->deeper = np2; + return (arg1); +} + +YYSTYPE addpeer (YYSTYPE arg1, YYSTYPE arg2) +{ + node_t *np1 = (node_t *) arg1; + node_t *np2 = (node_t *) arg2; + node_t *hook_point; + + hook_point = np1; + + while (hook_point->peer) + hook_point = hook_point->peer; + + hook_point->peer = np2; + return (arg1); +} + +/* + * add_slist (stmt_list, stmt) + */ + +YYSTYPE add_slist (YYSTYPE a1, YYSTYPE a2) +{ + if (a1 && a2) + return (addpeer(a1, a2)); + else if(a1) + return(a1); + else + return(a2); +} + +/* + * add_define (char *name, defn_list); + */ +YYSTYPE add_define (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_DEFINE); + np->data[0] = a1; + np->data[3] = (void *) message_crc; + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + +/* + * add_defbody (defn_list, new_defn) + */ +YYSTYPE add_defbody (YYSTYPE a1, YYSTYPE a2) +{ + return (addpeer(a1, a2)); +} + +/* + * add_primtype ([packed], primitive type, instance) + */ + +YYSTYPE add_primtype (YYSTYPE a1, YYSTYPE a2, YYSTYPE a3) +{ + /* Hook instance to type node */ + deeper (a1, a2); + if (a3) { + deeper(a1, a3); + } + return (a1); +} + +/* + * add_complex(char *type_name, instance) + */ + +YYSTYPE add_complex (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_COMPLEX); + np->data[0] = (void *) a1; + + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + +/* + * add_union(char *type_name, definition) + */ + +YYSTYPE add_union (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_UNION); + np->data[0] = (void *) a1; + + deeper((YYSTYPE)np, a2); + return ((YYSTYPE) np); +} + + +/* + * add_vector_vbl (node_t *variable, YYSTYPE size) + */ + +YYSTYPE add_vector_vbl (YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + + np = make_node(NODE_VECTOR); + np->data[0] = (void *) a1; + np->data[1] = (void *) a2; + return ((YYSTYPE) np); +} + +/* + * add_vector_vbl (char *vector_name, char *vector_length_var) + */ + +YYSTYPE add_variable_length_vector_vbl (YYSTYPE vector_name, YYSTYPE vector_length_var) +{ + node_t *np; + + np = make_node(NODE_VECTOR); + np->data[0] = (void *) vector_name; + np->data[1] = (void *) 0; // vector size used for vpe.api.h generation (array of length zero) + np->data[2] = (void *) vector_length_var; // name of the variable that stores vector length + return ((YYSTYPE) np); +} + +/* + * add_scalar_vbl (char *name) + */ +YYSTYPE add_scalar_vbl (YYSTYPE a1) +{ + node_t *np; + + np = make_node(NODE_SCALAR); + np->data[0] = (void *) a1; + return ((YYSTYPE) np); +} + +/* + * set_flags (int flags, msg(=0?)) + */ +YYSTYPE set_flags(YYSTYPE a1, YYSTYPE a2) +{ + node_t *np; + int flags; + + np = (node_t *)a2; + if (!np) + return(0); + + flags = (int)(uword) a1; + + np->flags |= flags; + return (a2); +} +/* + * suppress_version + */ +YYSTYPE suppress_version (void) +{ + dont_output_version = 1; + return (0); +} + +void dump(node_t *np) +{ + node_vft_t *vftp; + + while (np) { + vftp = the_vft[np->type]; + vftp->print(np); + np = np->peer; + } +} + +char *fixup_input_filename(void) +{ + char *cp; + + cp = (char *)input_filename; + + while (*cp) + cp++; + + cp--; + + while (cp > input_filename && *cp != '/') + cp--; + if (*cp == '/') + cp++; + + strncpy (tmpbuf, cp, sizeof(tmpbuf)-1); + + cp = tmpbuf; + + while (*cp) + cp++; + + cp--; + + while (cp > tmpbuf && *cp != '.') + cp--; + + if (*cp == '.') + *cp = 0; + + return (sxerox(tmpbuf)); +} + +void generate_top_boilerplate(FILE *fp) + +{ + char *datestring = ctime(&starttime); + fixed_name = fixup_input_filename(); + + datestring[24] = 0; + + fprintf (fp, "/*\n"); + fprintf (fp, " * VLIB API definitions %s\n", datestring); + fprintf (fp, " * Input file: %s\n", input_filename); + fprintf (fp, " * Automatically generated: please edit the input file "); + fprintf (fp, "NOT this file!\n"); + fprintf (fp, " */\n\n"); + fprintf (fp, "#if defined(vl_msg_id)||defined(vl_union_id)||"); + fprintf (fp, "defined(vl_printfun) \\\n ||defined(vl_endianfun)||"); + fprintf (fp, " defined(vl_api_version)||defined(vl_typedefs) \\\n"); + fprintf (fp, " ||defined(vl_msg_name)||defined(vl_msg_name_crc_list)\n"); + fprintf (fp, "/* ok, something was selected */\n"); + fprintf (fp, "#else\n"); + fprintf (fp, "#warning no content included from %s\n", input_filename); + fprintf (fp, "#endif\n\n"); + fprintf (fp, "#define VL_API_PACKED(x) x __attribute__ ((packed))\n\n"); +} + +void generate_bottom_boilerplate(FILE *fp) + +{ + fprintf (fp, "\n#ifdef vl_api_version\n"); + + if (dont_output_version) { + fprintf (fp, "/* WARNING: API FILE VERSION CHECK DISABLED */\n"); + input_crc = 0; + } + + fprintf (fp, "vl_api_version(%s, 0x%08x)\n\n", + fixed_name, (unsigned int)input_crc); + fprintf (fp, "#endif\n\n"); +} + +void generate_msg_ids(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf (fp, "\n/****** Message ID / handler enum ******/\n\n"); + fprintf (fp, "#ifdef vl_msg_id\n"); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n", + uppercase(np->data[0]), (i8 *)np->data[0]); + } else { + fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]); + } + } + np = np->peer; + } + fprintf (fp, "#endif\n"); + +} + +void generate_msg_names(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf (fp, "\n/****** Message names ******/\n\n"); + + fprintf (fp, "#ifdef vl_msg_name\n"); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "vl_msg_name(vl_api_%s_t, %d)\n", + (i8 *) np->data[0], + (np->flags & NODE_FLAG_DONT_TRACE ? 0 : 1)); + } else { + fprintf (fp, "/* typeonly: %s */\n", (i8 *)np->data[0]); + } + } + np = np->peer; + } + fprintf (fp, "#endif\n\n"); +} + +void generate_msg_name_crc_list (YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + char *unique_suffix, *cp; + + unique_suffix = sxerox(fixed_name); + + cp = unique_suffix; + while (*cp && (*cp != '.')) + cp++; + if (*cp == '.') + *cp = 0; + + fprintf (fp, "\n/****** Message name, crc list ******/\n\n"); + + fprintf (fp, "#ifdef vl_msg_name_crc_list\n"); + fprintf (fp, "#define foreach_vl_msg_name_crc_%s ", unique_suffix); + + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + fprintf (fp, "\\\n_(VL_API_%s, %s, %08x) ", + uppercase (np->data[0]), (i8 *) np->data[0], + (u32)(u64)np->data[3]); + } + } + np = np->peer; + } + fprintf (fp, "\n#endif\n\n"); + free (unique_suffix); +} + +void generate_typedefs(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "\n/****** Typedefs *****/\n\n"); + fprintf(fp, "#ifdef vl_typedefs\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, TYPEDEF_PASS, fp); + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_typedefs */\n\n"); +} + +void union_walk_one_defn(node_t *np, FILE *fp) +{ + node_t *vblp; + node_t *uelem; + + /* Walk the list of typed objects in this msg def */ + while (np) { + if (np->type == NODE_UNION) { + current_union_name = np->data[0]; + uelem = np->deeper; + + /* Walk the list of objects in this union */ + while (uelem) { + vblp = uelem->deeper; + /* Drill down on each element, find the variable name */ + while(vblp) { + if (vblp->type == NODE_SCALAR || + vblp->type == NODE_VECTOR || + vblp->type == NODE_COMPLEX) { + fprintf(ofp, "#define %s_", + uppercase(current_def_name)); + fprintf(ofp, "%s_", uppercase(current_union_name)); + fprintf(ofp, "%s %d\n",uppercase(vblp->data[0]), + current_id); + current_id++; + break; + } + vblp = vblp->deeper; + } + uelem = uelem->peer; + } + current_union_name = 0; + current_id = 1; + } + np = np->peer; + } +} + +void generate_uniondefs(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + + fprintf(fp, "/****** Discriminated Union Definitions *****/\n\n"); + fprintf(fp, "#ifdef vl_union_id\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + current_id = 1; + current_def_name = np->data[0]; + union_walk_one_defn(np->deeper, fp); + } + np = np->peer; + } + fprintf(fp, "\n#endif /* vl_union_id */\n\n"); +} + +void generate_printfun(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "/****** Print functions *****/\n\n"); + fprintf(fp, "#ifdef vl_printfun\n\n"); + + fprintf(fp, "#ifdef LP64\n"); + fputs ("#define _uword_fmt \"%lld\"\n", fp); + fputs ("#define _uword_cast (long long)\n", fp); + fprintf(fp, "#else\n"); + fputs("#define _uword_fmt \"%ld\"\n", fp); + fputs ("#define _uword_cast long\n", fp); + fprintf(fp, "#endif\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_MANUAL_PRINT)) { + fprintf(fp, + "static inline void *vl_api_%s_t_print (vl_api_%s_t *a,", + (i8 *)np->data[0], (i8 *) np->data[0]); + fprintf(fp, "void *handle)\n{\n"); + /* output the message name */ + fprintf(fp, + " vl_print(handle, \"vl_api_%s_t:\\n\");\n", + (i8 *)np->data[0]); + + indent += 4; + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, PRINTFUN_PASS, fp); + fprintf(fp, " return handle;\n"); + fprintf(fp, "}\n\n"); + indent -= 4; + } else { + fprintf(fp, "/***** manual: vl_api_%s_t_print *****/\n\n", + (i8 *) np->data[0]); + } + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_printfun */\n\n"); +} + +void generate_endianfun(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + + fprintf(fp, "\n/****** Endian swap functions *****/\n\n"); + fprintf(fp, "#ifdef vl_endianfun\n\n"); + fprintf(fp, "#undef clib_net_to_host_uword\n"); + fprintf(fp, "#ifdef LP64\n"); + fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u64\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "#define clib_net_to_host_uword clib_net_to_host_u32\n"); + fprintf(fp, "#endif\n\n"); + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_MANUAL_ENDIAN)) { + fprintf(fp, + "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)\n{\n", + (i8 *) np->data[0], (i8 *) np->data[0]); + indent += 4; + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, ENDIANFUN_PASS, fp); + fprintf(fp, "}\n\n"); + indent -= 4; + } else { + fprintf(fp, "/***** manual: vl_api_%s_t_endian *****/\n\n", + (i8 *) np->data[0]); + } + } + np = np->peer; + } + fprintf(fp, "#endif /* vl_endianfun */\n\n"); +} + +void add_msg_ids(YYSTYPE a1) +{ + node_t *np = (node_t *)a1; + node_t *new_u16; + node_t *new_vbl; + + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE) { + if (!(np->flags & NODE_FLAG_TYPEONLY)) { + /* add the parse tree for "u16 _vl_msg_id" */ + new_u16 = make_node(NODE_U16); + new_u16->peer = np->deeper; + np->deeper = new_u16; + new_vbl = make_node(NODE_SCALAR); + new_vbl->data[0] = sxerox("_vl_msg_id"); + new_u16->deeper = new_vbl; + } + } + np = np->peer; + } +} + +void generate_python_msg_definitions(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + fprintf (fp, "messages = [\n"); + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE && !(np->flags & NODE_FLAG_TYPEONLY)) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + vftp->generate(np, PYTHON_PASS, fp); + } + np = np->peer; + } + fprintf (fp, "\n]\n"); +} + +static bool +is_typeonly_check(node_t *np, bool typeonly) +{ + bool is_typeonly = (np->flags & NODE_FLAG_TYPEONLY); + return (is_typeonly == typeonly); +} + +static void +generate_json_definitions(YYSTYPE a1, FILE *fp, bool typeonly) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + indent_me(fp); + if (typeonly) + fprintf (fp, "\"types\" : [\n"); + else + fprintf (fp, "\"messages\" : [\n"); + + /* Walk the top-level node-list */ + bool comma = false; + indent += 4; + while (np) { + if (np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) { + /* Yeah, this is pedantic */ + vftp = the_vft[np->type]; + indent_me(fp); + vftp->generate(np, JSON_PASS, fp); + comma = true; + } + np = np->peer; + if (comma && np && + np->type == NODE_DEFINE && is_typeonly_check(np, typeonly)) + fprintf (fp, ",\n"); + + } + indent -= 4; + fprintf (fp, "\n"); + indent_me(fp); + fprintf(fp, "]"); +} + +void generate_python_typeonly_definitions(YYSTYPE a1, FILE *fp) +{ + node_t *np = (node_t *)a1; + node_vft_t *vftp; + fprintf (fp, "types = [\n"); + /* Walk the top-level node-list */ + while (np) { + if (np->type == NODE_DEFINE && (np->flags & NODE_FLAG_TYPEONLY)) { + vftp = the_vft[np->type]; + vftp->generate(np, PYTHON_PASS, fp); + } + np = np->peer; + } + fprintf (fp, "\n]\n"); +} + +void generate_python(YYSTYPE a1, FILE *fp) +{ + generate_python_typeonly_definitions(a1, fp); + generate_python_msg_definitions(a1, fp); + + /* + * API CRC signature + */ + fprintf (fp, "vl_api_version = 0x%08x\n\n", (unsigned int)input_crc); +} + +void generate_json(YYSTYPE a1, FILE *fp) +{ + fprintf (fp, "{\n"); + indent += 4; + generate_json_definitions(a1, fp, true); + fprintf (fp, ",\n"); + generate_json_definitions(a1, fp, false); + + /* + * API CRC signature + */ + fprintf (fp, ",\n\"vl_api_version\" :\"0x%08x\"\n", + (unsigned int)input_crc); + fprintf (fp, "}\n"); +} + +void generate(YYSTYPE a1) +{ + if (dump_tree) { + dump((node_t *)a1); + } + + add_msg_ids(a1); + + if (ofp) { + generate_top_boilerplate(ofp); + + generate_msg_ids(a1, ofp); + generate_msg_names(a1, ofp); + generate_msg_name_crc_list(a1, ofp); + generate_typedefs(a1, ofp); + generate_uniondefs(a1, ofp); + generate_printfun(a1, ofp); + generate_endianfun(a1, ofp); + + generate_bottom_boilerplate(ofp); + } + if (pythonfp) { + generate_python(a1, pythonfp); + } + if (jsonfp) { + generate_json(a1, jsonfp); + } +} diff --git a/src/tools/vppapigen/node.h b/src/tools/vppapigen/node.h new file mode 100644 index 00000000000..297d603615b --- /dev/null +++ b/src/tools/vppapigen/node.h @@ -0,0 +1,94 @@ +/* + *------------------------------------------------------------------ + * node.h - definitions for an API generator + * + * Copyright (c) 2004-2009 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef _node_h_ +#define _node_h_ + +/* + * Global prototypes + */ + +char *sxerox (const char *s); + +enum node_subclass { /* WARNING: indices must match the vft... */ + NODE_ILLEGAL=0, + NODE_U8, + NODE_U16, + NODE_U32, + NODE_U64, + NODE_I8, + NODE_I16, + NODE_I32, + NODE_I64, + NODE_F64, + NODE_PACKED, + NODE_DEFINE, + NODE_UNION, + NODE_SCALAR, + NODE_VECTOR, + NODE_COMPLEX, + NODE_NOVERSION, + NODE_UWORD, + NODE_N_TYPES, /* number of node types with VFT's */ + + /* pseudo-node(s) used in the lexer keyword table, but + NOT in need of a VFT... */ + NODE_TYPEONLY, + NODE_MANUAL_PRINT, + NODE_MANUAL_ENDIAN, + NODE_DONT_TRACE, +}; + +enum passid { + TYPEDEF_PASS=1, + UNION_DEF_PASS, + ENDIANFUN_PASS, + PRINTFUN_PASS, + PYTHON_PASS, + JSON_PASS, +}; + +extern void *make_node (enum node_subclass type); + +typedef struct node_ { + enum node_subclass type; + struct node_ *peer; + struct node_ *deeper; + int flags; + void *data[4]; +} node_t; + +/* To shut up gcc-4.2.x warnings */ +#define CDATA0 ((char *)(this->data[0])) +#define IDATA1 ((int)(uword)(this->data[1])) +#define CDATA2 ((char *)(this->data[2])) +#define CDATA3 ((char *)(this->data[3])) + +#define NODE_FLAG_MANUAL_PRINT (1<<0) +#define NODE_FLAG_MANUAL_ENDIAN (1<<1) +#define NODE_FLAG_TYPEONLY (1<<3) +#define NODE_FLAG_DONT_TRACE (1<<4) + +typedef struct node_vft_ { + void (*print)(struct node_ *); + void (*generate)(struct node_ *, enum passid id, FILE *ofp); + char *endian_converter; +} node_vft_t; + +#endif /* _node_h */ diff --git a/src/vat/api_format.c b/src/vat/api_format.c new file mode 100644 index 00000000000..e6c0f244d83 --- /dev/null +++ b/src/vat/api_format.c @@ -0,0 +1,17829 @@ +/* + *------------------------------------------------------------------ + * api_format.c + * + * Copyright (c) 2014-2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vat/json_format.h" + +#include +#include + +#define vl_typedefs /* define message structures */ +#include +#undef vl_typedefs + +/* declare message handlers for each api */ + +#define vl_endianfun /* define message structures */ +#include +#undef vl_endianfun + +/* instantiate all the print functions we know about */ +#define vl_print(handle, ...) +#define vl_printfun +#include +#undef vl_printfun + +static uword +api_unformat_sw_if_index (unformat_input_t * input, va_list * args) +{ + vat_main_t *vam = va_arg (*args, vat_main_t *); + u32 *result = va_arg (*args, u32 *); + u8 *if_name; + uword *p; + + if (!unformat (input, "%s", &if_name)) + return 0; + + p = hash_get_mem (vam->sw_if_index_by_interface_name, if_name); + if (p == 0) + return 0; + *result = p[0]; + return 1; +} + +void vat_suspend (vlib_main_t * vm, f64 interval); + +#if VPP_API_TEST_BUILTIN == 0 +/* Parse an IP4 address %d.%d.%d.%d. */ +uword +unformat_ip4_address (unformat_input_t * input, va_list * args) +{ + u8 *result = va_arg (*args, u8 *); + unsigned a[4]; + + if (!unformat (input, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3])) + return 0; + + if (a[0] >= 256 || a[1] >= 256 || a[2] >= 256 || a[3] >= 256) + return 0; + + result[0] = a[0]; + result[1] = a[1]; + result[2] = a[2]; + result[3] = a[3]; + + return 1; +} + +uword +unformat_ethernet_address (unformat_input_t * input, va_list * args) +{ + u8 *result = va_arg (*args, u8 *); + u32 i, a[6]; + + if (!unformat (input, "%_%x:%x:%x:%x:%x:%x%_", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5])) + return 0; + + /* Check range. */ + for (i = 0; i < 6; i++) + if (a[i] >= (1 << 8)) + return 0; + + for (i = 0; i < 6; i++) + result[i] = a[i]; + + return 1; +} + +/* Returns ethernet type as an int in host byte order. */ +uword +unformat_ethernet_type_host_byte_order (unformat_input_t * input, + va_list * args) +{ + u16 *result = va_arg (*args, u16 *); + int type; + + /* Numeric type. */ + if (unformat (input, "0x%x", &type) || unformat (input, "%d", &type)) + { + if (type >= (1 << 16)) + return 0; + *result = type; + return 1; + } + return 0; +} + +/* Parse an IP6 address. */ +uword +unformat_ip6_address (unformat_input_t * input, va_list * args) +{ + ip6_address_t *result = va_arg (*args, ip6_address_t *); + u16 hex_quads[8]; + uword hex_quad, n_hex_quads, hex_digit, n_hex_digits; + uword c, n_colon, double_colon_index; + + n_hex_quads = hex_quad = n_hex_digits = n_colon = 0; + double_colon_index = ARRAY_LEN (hex_quads); + while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT) + { + hex_digit = 16; + if (c >= '0' && c <= '9') + hex_digit = c - '0'; + else if (c >= 'a' && c <= 'f') + hex_digit = c + 10 - 'a'; + else if (c >= 'A' && c <= 'F') + hex_digit = c + 10 - 'A'; + else if (c == ':' && n_colon < 2) + n_colon++; + else + { + unformat_put_input (input); + break; + } + + /* Too many hex quads. */ + if (n_hex_quads >= ARRAY_LEN (hex_quads)) + return 0; + + if (hex_digit < 16) + { + hex_quad = (hex_quad << 4) | hex_digit; + + /* Hex quad must fit in 16 bits. */ + if (n_hex_digits >= 4) + return 0; + + n_colon = 0; + n_hex_digits++; + } + + /* Save position of :: */ + if (n_colon == 2) + { + /* More than one :: ? */ + if (double_colon_index < ARRAY_LEN (hex_quads)) + return 0; + double_colon_index = n_hex_quads; + } + + if (n_colon > 0 && n_hex_digits > 0) + { + hex_quads[n_hex_quads++] = hex_quad; + hex_quad = 0; + n_hex_digits = 0; + } + } + + if (n_hex_digits > 0) + hex_quads[n_hex_quads++] = hex_quad; + + { + word i; + + /* Expand :: to appropriate number of zero hex quads. */ + if (double_colon_index < ARRAY_LEN (hex_quads)) + { + word n_zero = ARRAY_LEN (hex_quads) - n_hex_quads; + + for (i = n_hex_quads - 1; i >= (signed) double_colon_index; i--) + hex_quads[n_zero + i] = hex_quads[i]; + + for (i = 0; i < n_zero; i++) + hex_quads[double_colon_index + i] = 0; + + n_hex_quads = ARRAY_LEN (hex_quads); + } + + /* Too few hex quads given. */ + if (n_hex_quads < ARRAY_LEN (hex_quads)) + return 0; + + for (i = 0; i < ARRAY_LEN (hex_quads); i++) + result->as_u16[i] = clib_host_to_net_u16 (hex_quads[i]); + + return 1; + } +} + +uword +unformat_ipsec_policy_action (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_POLICY_ACTION_##f; + foreach_ipsec_policy_action +#undef _ + else + return 0; + return 1; +} + +uword +unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_CRYPTO_ALG_##f; + foreach_ipsec_crypto_alg +#undef _ + else + return 0; + return 1; +} + +u8 * +format_ipsec_crypto_alg (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(v,f,str) case IPSEC_CRYPTO_ALG_##f: t = (u8 *) str; break; + foreach_ipsec_crypto_alg +#undef _ + default: + return format (s, "unknown"); + } + return format (s, "%s", t); +} + +uword +unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IPSEC_INTEG_ALG_##f; + foreach_ipsec_integ_alg +#undef _ + else + return 0; + return 1; +} + +u8 * +format_ipsec_integ_alg (u8 * s, va_list * args) +{ + u32 i = va_arg (*args, u32); + u8 *t = 0; + + switch (i) + { +#define _(v,f,str) case IPSEC_INTEG_ALG_##f: t = (u8 *) str; break; + foreach_ipsec_integ_alg +#undef _ + default: + return format (s, "unknown"); + } + return format (s, "%s", t); +} + +uword +unformat_ikev2_auth_method (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IKEV2_AUTH_METHOD_##f; + foreach_ikev2_auth_method +#undef _ + else + return 0; + return 1; +} + +uword +unformat_ikev2_id_type (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (0); +#define _(v,f,s) else if (unformat (input, s)) *r = IKEV2_ID_TYPE_##f; + foreach_ikev2_id_type +#undef _ + else + return 0; + return 1; +} +#endif /* VPP_API_TEST_BUILTIN */ + +static uword +unformat_policer_rate_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "kbps")) + *r = SSE2_QOS_RATE_KBPS; + else if (unformat (input, "pps")) + *r = SSE2_QOS_RATE_PPS; + else + return 0; + return 1; +} + +static uword +unformat_policer_round_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "closest")) + *r = SSE2_QOS_ROUND_TO_CLOSEST; + else if (unformat (input, "up")) + *r = SSE2_QOS_ROUND_TO_UP; + else if (unformat (input, "down")) + *r = SSE2_QOS_ROUND_TO_DOWN; + else + return 0; + return 1; +} + +static uword +unformat_policer_type (unformat_input_t * input, va_list * args) +{ + u8 *r = va_arg (*args, u8 *); + + if (unformat (input, "1r2c")) + *r = SSE2_QOS_POLICER_TYPE_1R2C; + else if (unformat (input, "1r3c")) + *r = SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697; + else if (unformat (input, "2r3c-2698")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698; + else if (unformat (input, "2r3c-4115")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115; + else if (unformat (input, "2r3c-mef5cf1")) + *r = SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1; + else + return 0; + return 1; +} + +static uword +unformat_dscp (unformat_input_t * input, va_list * va) +{ + u8 *r = va_arg (*va, u8 *); + + if (0); +#define _(v,f,str) else if (unformat (input, str)) *r = VNET_DSCP_##f; + foreach_vnet_dscp +#undef _ + else + return 0; + return 1; +} + +static uword +unformat_policer_action_type (unformat_input_t * input, va_list * va) +{ + sse2_qos_pol_action_params_st *a + = va_arg (*va, sse2_qos_pol_action_params_st *); + + if (unformat (input, "drop")) + a->action_type = SSE2_QOS_ACTION_DROP; + else if (unformat (input, "transmit")) + a->action_type = SSE2_QOS_ACTION_TRANSMIT; + else if (unformat (input, "mark-and-transmit %U", unformat_dscp, &a->dscp)) + a->action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT; + else + return 0; + return 1; +} + +static uword +unformat_policer_classify_table_type (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + u32 tid; + + if (unformat (input, "ip4")) + tid = POLICER_CLASSIFY_TABLE_IP4; + else if (unformat (input, "ip6")) + tid = POLICER_CLASSIFY_TABLE_IP6; + else if (unformat (input, "l2")) + tid = POLICER_CLASSIFY_TABLE_L2; + else + return 0; + + *r = tid; + return 1; +} + +static uword +unformat_flow_classify_table_type (unformat_input_t * input, va_list * va) +{ + u32 *r = va_arg (*va, u32 *); + u32 tid; + + if (unformat (input, "ip4")) + tid = FLOW_CLASSIFY_TABLE_IP4; + else if (unformat (input, "ip6")) + tid = FLOW_CLASSIFY_TABLE_IP6; + else + return 0; + + *r = tid; + return 1; +} + +#if (VPP_API_TEST_BUILTIN==0) +u8 * +format_ip4_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + return format (s, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); +} + +u8 * +format_ip6_address (u8 * s, va_list * args) +{ + ip6_address_t *a = va_arg (*args, ip6_address_t *); + u32 i, i_max_n_zero, max_n_zeros, i_first_zero, n_zeros, last_double_colon; + + i_max_n_zero = ARRAY_LEN (a->as_u16); + max_n_zeros = 0; + i_first_zero = i_max_n_zero; + n_zeros = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + u32 is_zero = a->as_u16[i] == 0; + if (is_zero && i_first_zero >= ARRAY_LEN (a->as_u16)) + { + i_first_zero = i; + n_zeros = 0; + } + n_zeros += is_zero; + if ((!is_zero && n_zeros > max_n_zeros) + || (i + 1 >= ARRAY_LEN (a->as_u16) && n_zeros > max_n_zeros)) + { + i_max_n_zero = i_first_zero; + max_n_zeros = n_zeros; + i_first_zero = ARRAY_LEN (a->as_u16); + n_zeros = 0; + } + } + + last_double_colon = 0; + for (i = 0; i < ARRAY_LEN (a->as_u16); i++) + { + if (i == i_max_n_zero && max_n_zeros > 1) + { + s = format (s, "::"); + i += max_n_zeros - 1; + last_double_colon = 1; + } + else + { + s = format (s, "%s%x", + (last_double_colon || i == 0) ? "" : ":", + clib_net_to_host_u16 (a->as_u16[i])); + last_double_colon = 0; + } + } + + return s; +} + +/* Format an IP46 address. */ +u8 * +format_ip46_address (u8 * s, va_list * args) +{ + ip46_address_t *ip46 = va_arg (*args, ip46_address_t *); + ip46_type_t type = va_arg (*args, ip46_type_t); + int is_ip4 = 1; + + switch (type) + { + case IP46_TYPE_ANY: + is_ip4 = ip46_address_is_ip4 (ip46); + break; + case IP46_TYPE_IP4: + is_ip4 = 1; + break; + case IP46_TYPE_IP6: + is_ip4 = 0; + break; + } + + return is_ip4 ? + format (s, "%U", format_ip4_address, &ip46->ip4) : + format (s, "%U", format_ip6_address, &ip46->ip6); +} + +u8 * +format_ethernet_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[0], a[1], a[2], a[3], a[4], a[5]); +} +#endif + +static void +increment_v4_address (ip4_address_t * a) +{ + u32 v; + + v = ntohl (a->as_u32) + 1; + a->as_u32 = ntohl (v); +} + +static void +increment_v6_address (ip6_address_t * a) +{ + u64 v0, v1; + + v0 = clib_net_to_host_u64 (a->as_u64[0]); + v1 = clib_net_to_host_u64 (a->as_u64[1]); + + v1 += 1; + if (v1 == 0) + v0 += 1; + a->as_u64[0] = clib_net_to_host_u64 (v0); + a->as_u64[1] = clib_net_to_host_u64 (v1); +} + +static void +increment_mac_address (u64 * mac) +{ + u64 tmp = *mac; + + tmp = clib_net_to_host_u64 (tmp); + tmp += 1 << 16; /* skip unused (least significant) octets */ + tmp = clib_host_to_net_u64 (tmp); + *mac = tmp; +} + +static void vl_api_create_loopback_reply_t_handler + (vl_api_create_loopback_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_loopback_reply_t_handler_json + (vl_api_create_loopback_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_af_packet_create_reply_t_handler + (vl_api_af_packet_create_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_af_packet_create_reply_t_handler_json + (vl_api_af_packet_create_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_vlan_subif_reply_t_handler + (vl_api_create_vlan_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_vlan_subif_reply_t_handler_json + (vl_api_create_vlan_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_subif_reply_t_handler + (vl_api_create_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_subif_reply_t_handler_json + (vl_api_create_subif_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_interface_name_renumber_reply_t_handler + (vl_api_interface_name_renumber_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->result_ready = 1; +} + +static void vl_api_interface_name_renumber_reply_t_handler_json + (vl_api_interface_name_renumber_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +/* + * Special-case: build the interface table, maintain + * the next loopback sw_if_index vbl. + */ +static void vl_api_sw_interface_details_t_handler + (vl_api_sw_interface_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = format (0, "%s%c", mp->interface_name, 0); + + hash_set_mem (vam->sw_if_index_by_interface_name, s, + ntohl (mp->sw_if_index)); + + /* In sub interface case, fill the sub interface table entry */ + if (mp->sw_if_index != mp->sup_sw_if_index) + { + sw_interface_subif_t *sub = NULL; + + vec_add2 (vam->sw_if_subif_table, sub, 1); + + vec_validate (sub->interface_name, strlen ((char *) s) + 1); + strncpy ((char *) sub->interface_name, (char *) s, + vec_len (sub->interface_name)); + sub->sw_if_index = ntohl (mp->sw_if_index); + sub->sub_id = ntohl (mp->sub_id); + + sub->sub_dot1ad = mp->sub_dot1ad; + sub->sub_number_of_tags = mp->sub_number_of_tags; + sub->sub_outer_vlan_id = ntohs (mp->sub_outer_vlan_id); + sub->sub_inner_vlan_id = ntohs (mp->sub_inner_vlan_id); + sub->sub_exact_match = mp->sub_exact_match; + sub->sub_default = mp->sub_default; + sub->sub_outer_vlan_id_any = mp->sub_outer_vlan_id_any; + sub->sub_inner_vlan_id_any = mp->sub_inner_vlan_id_any; + + /* vlan tag rewrite */ + sub->vtr_op = ntohl (mp->vtr_op); + sub->vtr_push_dot1q = ntohl (mp->vtr_push_dot1q); + sub->vtr_tag1 = ntohl (mp->vtr_tag1); + sub->vtr_tag2 = ntohl (mp->vtr_tag2); + } +} + +static void vl_api_sw_interface_details_t_handler_json + (vl_api_sw_interface_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "sup_sw_if_index", + ntohl (mp->sup_sw_if_index)); + vat_json_object_add_uint (node, "l2_address_length", + ntohl (mp->l2_address_length)); + vat_json_object_add_bytes (node, "l2_address", mp->l2_address, + sizeof (mp->l2_address)); + vat_json_object_add_string_copy (node, "interface_name", + mp->interface_name); + vat_json_object_add_uint (node, "admin_up_down", mp->admin_up_down); + vat_json_object_add_uint (node, "link_up_down", mp->link_up_down); + vat_json_object_add_uint (node, "link_duplex", mp->link_duplex); + vat_json_object_add_uint (node, "link_speed", mp->link_speed); + vat_json_object_add_uint (node, "mtu", ntohs (mp->link_mtu)); + vat_json_object_add_uint (node, "sub_id", ntohl (mp->sub_id)); + vat_json_object_add_uint (node, "sub_dot1ad", mp->sub_dot1ad); + vat_json_object_add_uint (node, "sub_number_of_tags", + mp->sub_number_of_tags); + vat_json_object_add_uint (node, "sub_outer_vlan_id", + ntohs (mp->sub_outer_vlan_id)); + vat_json_object_add_uint (node, "sub_inner_vlan_id", + ntohs (mp->sub_inner_vlan_id)); + vat_json_object_add_uint (node, "sub_exact_match", mp->sub_exact_match); + vat_json_object_add_uint (node, "sub_default", mp->sub_default); + vat_json_object_add_uint (node, "sub_outer_vlan_id_any", + mp->sub_outer_vlan_id_any); + vat_json_object_add_uint (node, "sub_inner_vlan_id_any", + mp->sub_inner_vlan_id_any); + vat_json_object_add_uint (node, "vtr_op", ntohl (mp->vtr_op)); + vat_json_object_add_uint (node, "vtr_push_dot1q", + ntohl (mp->vtr_push_dot1q)); + vat_json_object_add_uint (node, "vtr_tag1", ntohl (mp->vtr_tag1)); + vat_json_object_add_uint (node, "vtr_tag2", ntohl (mp->vtr_tag2)); +} + +static void vl_api_sw_interface_set_flags_t_handler + (vl_api_sw_interface_set_flags_t * mp) +{ + vat_main_t *vam = &vat_main; + if (vam->interface_event_display) + errmsg ("interface flags: sw_if_index %d %s %s", + ntohl (mp->sw_if_index), + mp->admin_up_down ? "admin-up" : "admin-down", + mp->link_up_down ? "link-up" : "link-down"); +} + +static void vl_api_sw_interface_set_flags_t_handler_json + (vl_api_sw_interface_set_flags_t * mp) +{ + /* JSON output not supported */ +} + +static void +vl_api_cli_reply_t_handler (vl_api_cli_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->shmem_result = (u8 *) mp->reply_in_shmem; + vam->result_ready = 1; +} + +static void +vl_api_cli_reply_t_handler_json (vl_api_cli_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + api_main_t *am = &api_main; + void *oldheap; + u8 *reply; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "reply_in_shmem", + ntohl (mp->reply_in_shmem)); + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + reply = (u8 *) (mp->reply_in_shmem); + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_cli_inband_reply_t_handler (vl_api_cli_inband_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->cmd_reply = mp->reply; + vam->result_ready = 1; +} + +static void +vl_api_cli_inband_reply_t_handler_json (vl_api_cli_inband_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_string_copy (&node, "reply", mp->reply); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_classify_add_del_table_reply_t_handler + (vl_api_classify_add_del_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0 && + ((mp->new_table_index != 0xFFFFFFFF) || + (mp->skip_n_vectors != 0xFFFFFFFF) || + (mp->match_n_vectors != 0xFFFFFFFF))) + /* + * Note: this is just barely thread-safe, depends on + * the main thread spinning waiting for an answer... + */ + errmsg ("new index %d, skip_n_vectors %d, match_n_vectors %d", + ntohl (mp->new_table_index), + ntohl (mp->skip_n_vectors), ntohl (mp->match_n_vectors)); + vam->result_ready = 1; + } +} + +static void vl_api_classify_add_del_table_reply_t_handler_json + (vl_api_classify_add_del_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "new_table_index", + ntohl (mp->new_table_index)); + vat_json_object_add_uint (&node, "skip_n_vectors", + ntohl (mp->skip_n_vectors)); + vat_json_object_add_uint (&node, "match_n_vectors", + ntohl (mp->match_n_vectors)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_node_index_reply_t_handler + (vl_api_get_node_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("node index %d", ntohl (mp->node_index)); + vam->result_ready = 1; + } +} + +static void vl_api_get_node_index_reply_t_handler_json + (vl_api_get_node_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "node_index", ntohl (mp->node_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_next_index_reply_t_handler + (vl_api_get_next_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("next node index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void vl_api_get_next_index_reply_t_handler_json + (vl_api_get_next_index_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_add_node_next_reply_t_handler + (vl_api_add_node_next_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + if (retval == 0) + errmsg ("next index %d", ntohl (mp->next_index)); + vam->result_ready = 1; + } +} + +static void vl_api_add_node_next_reply_t_handler_json + (vl_api_add_node_next_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "next_index", ntohl (mp->next_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_show_version_reply_t_handler + (vl_api_show_version_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (retval >= 0) + { + errmsg (" program: %s", mp->program); + errmsg (" version: %s", mp->version); + errmsg (" build date: %s", mp->build_date); + errmsg ("build directory: %s", mp->build_directory); + } + vam->retval = retval; + vam->result_ready = 1; +} + +static void vl_api_show_version_reply_t_handler_json + (vl_api_show_version_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_string_copy (&node, "program", mp->program); + vat_json_object_add_string_copy (&node, "version", mp->version); + vat_json_object_add_string_copy (&node, "build_date", mp->build_date); + vat_json_object_add_string_copy (&node, "build_directory", + mp->build_directory); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_ip4_arp_event_t_handler (vl_api_ip4_arp_event_t * mp) +{ + errmsg ("arp %s event: address %U new mac %U sw_if_index %d", + mp->mac_ip ? "mac/ip binding" : "address resolution", + format_ip4_address, &mp->address, + format_ethernet_address, mp->new_mac, mp->sw_if_index); +} + +static void +vl_api_ip4_arp_event_t_handler_json (vl_api_ip4_arp_event_t * mp) +{ + /* JSON output not supported */ +} + +static void +vl_api_ip6_nd_event_t_handler (vl_api_ip6_nd_event_t * mp) +{ + errmsg ("ip6 nd %s event: address %U new mac %U sw_if_index %d", + mp->mac_ip ? "mac/ip binding" : "address resolution", + format_ip6_address, mp->address, + format_ethernet_address, mp->new_mac, mp->sw_if_index); +} + +static void +vl_api_ip6_nd_event_t_handler_json (vl_api_ip6_nd_event_t * mp) +{ + /* JSON output not supported */ +} + +/* + * Special-case: build the bridge domain table, maintain + * the next bd id vbl. + */ +static void vl_api_bridge_domain_details_t_handler + (vl_api_bridge_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 n_sw_ifs = ntohl (mp->n_sw_ifs); + + print (vam->ofp, "\n%-3s %-3s %-3s %-3s %-3s %-3s", + " ID", "LRN", "FWD", "FLD", "BVI", "#IF"); + + print (vam->ofp, "%3d %3d %3d %3d %3d %3d", + ntohl (mp->bd_id), mp->learn, mp->forward, + mp->flood, ntohl (mp->bvi_sw_if_index), n_sw_ifs); + + if (n_sw_ifs) + print (vam->ofp, "\n\n%s %s %s", "sw_if_index", "SHG", "Interface Name"); +} + +static void vl_api_bridge_domain_details_t_handler_json + (vl_api_bridge_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node, *array = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "flood", mp->flood); + vat_json_object_add_uint (node, "forward", mp->forward); + vat_json_object_add_uint (node, "learn", mp->learn); + vat_json_object_add_uint (node, "bvi_sw_if_index", + ntohl (mp->bvi_sw_if_index)); + vat_json_object_add_uint (node, "n_sw_ifs", ntohl (mp->n_sw_ifs)); + array = vat_json_object_add (node, "sw_if"); + vat_json_init_array (array); +} + +/* + * Special-case: build the bridge domain sw if table. + */ +static void vl_api_bridge_domain_sw_if_details_t_handler + (vl_api_bridge_domain_sw_if_details_t * mp) +{ + vat_main_t *vam = &vat_main; + hash_pair_t *p; + u8 *sw_if_name = 0; + u32 sw_if_index; + + sw_if_index = ntohl (mp->sw_if_index); + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index) + { + sw_if_name = (u8 *)(p->key); + break; + } + })); + /* *INDENT-ON* */ + + print (vam->ofp, "%7d %3d %s", sw_if_index, + mp->shg, sw_if_name ? (char *) sw_if_name : + "sw_if_index not found!"); +} + +static void vl_api_bridge_domain_sw_if_details_t_handler_json + (vl_api_bridge_domain_sw_if_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + uword last_index = 0; + + ASSERT (VAT_JSON_ARRAY == vam->json_tree.type); + ASSERT (vec_len (vam->json_tree.array) >= 1); + last_index = vec_len (vam->json_tree.array) - 1; + node = &vam->json_tree.array[last_index]; + node = vat_json_object_get_element (node, "sw_if"); + ASSERT (NULL != node); + node = vat_json_array_add (node); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "shg", mp->shg); +} + +static void vl_api_control_ping_reply_t_handler + (vl_api_control_ping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_control_ping_reply_t_handler_json + (vl_api_control_ping_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (VAT_JSON_NONE != vam->json_tree.type) + { + vat_json_print (vam->ofp, &vam->json_tree); + vat_json_free (&vam->json_tree); + vam->json_tree.type = VAT_JSON_NONE; + } + else + { + /* just print [] */ + vat_json_init_array (&vam->json_tree); + vat_json_print (vam->ofp, &vam->json_tree); + vam->json_tree.type = VAT_JSON_NONE; + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_l2_flags_reply_t_handler (vl_api_l2_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_l2_flags_reply_t_handler_json + (vl_api_l2_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "resulting_feature_bitmap", + ntohl (mp->resulting_feature_bitmap)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_bridge_flags_reply_t_handler + (vl_api_bridge_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_bridge_flags_reply_t_handler_json + (vl_api_bridge_flags_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "resulting_feature_bitmap", + ntohl (mp->resulting_feature_bitmap)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_tap_connect_reply_t_handler + (vl_api_tap_connect_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } + +} + +static void vl_api_tap_connect_reply_t_handler_json + (vl_api_tap_connect_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; + +} + +static void +vl_api_tap_modify_reply_t_handler (vl_api_tap_modify_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_tap_modify_reply_t_handler_json + (vl_api_tap_modify_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_tap_delete_reply_t_handler (vl_api_tap_delete_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_tap_delete_reply_t_handler_json + (vl_api_tap_delete_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_mpls_tunnel_add_del_reply_t_handler + (vl_api_mpls_tunnel_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_mpls_tunnel_add_del_reply_t_handler_json + (vl_api_mpls_tunnel_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "tunnel_sw_if_index", + ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_l2tpv3_create_tunnel_reply_t_handler + (vl_api_l2tpv3_create_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_l2tpv3_create_tunnel_reply_t_handler_json + (vl_api_l2tpv3_create_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + + +static void vl_api_lisp_add_del_locator_set_reply_t_handler + (vl_api_lisp_add_del_locator_set_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_lisp_add_del_locator_set_reply_t_handler_json + (vl_api_lisp_add_del_locator_set_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "locator_set_index", ntohl (mp->ls_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_vxlan_add_del_tunnel_reply_t_handler + (vl_api_vxlan_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_vxlan_add_del_tunnel_reply_t_handler_json + (vl_api_vxlan_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_gre_add_del_tunnel_reply_t_handler + (vl_api_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_gre_add_del_tunnel_reply_t_handler_json + (vl_api_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_create_vhost_user_if_reply_t_handler + (vl_api_create_vhost_user_if_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_create_vhost_user_if_reply_t_handler_json + (vl_api_create_vhost_user_if_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_ip_address_details_t_handler + (vl_api_ip_address_details_t * mp) +{ + vat_main_t *vam = &vat_main; + static ip_address_details_t empty_ip_address_details = { {0} }; + ip_address_details_t *address = NULL; + ip_details_t *current_ip_details = NULL; + ip_details_t *details = NULL; + + details = vam->ip_details_by_sw_if_index[vam->is_ipv6]; + + if (!details || vam->current_sw_if_index >= vec_len (details) + || !details[vam->current_sw_if_index].present) + { + errmsg ("ip address details arrived but not stored"); + errmsg ("ip_dump should be called first"); + return; + } + + current_ip_details = vec_elt_at_index (details, vam->current_sw_if_index); + +#define addresses (current_ip_details->addr) + + vec_validate_init_empty (addresses, vec_len (addresses), + empty_ip_address_details); + + address = vec_elt_at_index (addresses, vec_len (addresses) - 1); + + clib_memcpy (&address->ip, &mp->ip, sizeof (address->ip)); + address->prefix_length = mp->prefix_length; +#undef addresses +} + +static void vl_api_ip_address_details_t_handler_json + (vl_api_ip_address_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (vam->is_ipv6) + { + clib_memcpy (&ip6, mp->ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip", ip4); + } + vat_json_object_add_uint (node, "prefix_length", mp->prefix_length); +} + +static void +vl_api_ip_details_t_handler (vl_api_ip_details_t * mp) +{ + vat_main_t *vam = &vat_main; + static ip_details_t empty_ip_details = { 0 }; + ip_details_t *ip = NULL; + u32 sw_if_index = ~0; + + sw_if_index = ntohl (mp->sw_if_index); + + vec_validate_init_empty (vam->ip_details_by_sw_if_index[vam->is_ipv6], + sw_if_index, empty_ip_details); + + ip = vec_elt_at_index (vam->ip_details_by_sw_if_index[vam->is_ipv6], + sw_if_index); + + ip->present = 1; +} + +static void +vl_api_ip_details_t_handler_json (vl_api_ip_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + vat_json_array_add_uint (&vam->json_tree, + clib_net_to_host_u32 (mp->sw_if_index)); +} + +static void vl_api_map_domain_details_t_handler_json + (vl_api_map_domain_details_t * mp) +{ + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "domain_index", + clib_net_to_host_u32 (mp->domain_index)); + clib_memcpy (&ip6, mp->ip6_prefix, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_prefix", ip6); + clib_memcpy (&ip4, mp->ip4_prefix, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip4_prefix", ip4); + clib_memcpy (&ip6, mp->ip6_src, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_src", ip6); + vat_json_object_add_int (node, "ip6_prefix_len", mp->ip6_prefix_len); + vat_json_object_add_int (node, "ip4_prefix_len", mp->ip4_prefix_len); + vat_json_object_add_int (node, "ip6_src_len", mp->ip6_src_len); + vat_json_object_add_int (node, "ea_bits_len", mp->ea_bits_len); + vat_json_object_add_int (node, "psid_offset", mp->psid_offset); + vat_json_object_add_int (node, "psid_length", mp->psid_length); + vat_json_object_add_uint (node, "flags", mp->flags); + vat_json_object_add_uint (node, "mtu", clib_net_to_host_u16 (mp->mtu)); + vat_json_object_add_int (node, "is_translation", mp->is_translation); +} + +static void vl_api_map_domain_details_t_handler + (vl_api_map_domain_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + if (mp->is_translation) + { + print (vam->ofp, + "* %U/%d (ipv4-prefix) %U/%d (ipv6-prefix) %U/%d (ip6-src) index: %u", + format_ip4_address, mp->ip4_prefix, mp->ip4_prefix_len, + format_ip6_address, mp->ip6_prefix, mp->ip6_prefix_len, + format_ip6_address, mp->ip6_src, mp->ip6_src_len, + clib_net_to_host_u32 (mp->domain_index)); + } + else + { + print (vam->ofp, + "* %U/%d (ipv4-prefix) %U/%d (ipv6-prefix) %U (ip6-src) index: %u", + format_ip4_address, mp->ip4_prefix, mp->ip4_prefix_len, + format_ip6_address, mp->ip6_prefix, mp->ip6_prefix_len, + format_ip6_address, mp->ip6_src, + clib_net_to_host_u32 (mp->domain_index)); + } + print (vam->ofp, " ea-len %d psid-offset %d psid-len %d mtu %d %s", + mp->ea_bits_len, mp->psid_offset, mp->psid_length, mp->mtu, + mp->is_translation ? "map-t" : ""); +} + +static void vl_api_map_rule_details_t_handler_json + (vl_api_map_rule_details_t * mp) +{ + struct in6_addr ip6; + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "psid", clib_net_to_host_u16 (mp->psid)); + clib_memcpy (&ip6, mp->ip6_dst, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip6_dst", ip6); +} + +static void +vl_api_map_rule_details_t_handler (vl_api_map_rule_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, " %d (psid) %U (ip6-dst)", + clib_net_to_host_u16 (mp->psid), format_ip6_address, mp->ip6_dst); +} + +static void +vl_api_dhcp_compl_event_t_handler (vl_api_dhcp_compl_event_t * mp) +{ + errmsg ("DHCP compl event: pid %d %s hostname %s host_addr %U " + "router_addr %U host_mac %U", + mp->pid, mp->is_ipv6 ? "ipv6" : "ipv4", mp->hostname, + format_ip4_address, &mp->host_address, + format_ip4_address, &mp->router_address, + format_ethernet_address, mp->host_mac); +} + +static void vl_api_dhcp_compl_event_t_handler_json + (vl_api_dhcp_compl_event_t * mp) +{ + /* JSON output not supported */ +} + +static void +set_simple_interface_counter (u8 vnet_counter_type, u32 sw_if_index, + u32 counter) +{ + vat_main_t *vam = &vat_main; + static u64 default_counter = 0; + + vec_validate_init_empty (vam->simple_interface_counters, vnet_counter_type, + NULL); + vec_validate_init_empty (vam->simple_interface_counters[vnet_counter_type], + sw_if_index, default_counter); + vam->simple_interface_counters[vnet_counter_type][sw_if_index] = counter; +} + +static void +set_combined_interface_counter (u8 vnet_counter_type, u32 sw_if_index, + interface_counter_t counter) +{ + vat_main_t *vam = &vat_main; + static interface_counter_t default_counter = { 0, }; + + vec_validate_init_empty (vam->combined_interface_counters, + vnet_counter_type, NULL); + vec_validate_init_empty (vam->combined_interface_counters + [vnet_counter_type], sw_if_index, default_counter); + vam->combined_interface_counters[vnet_counter_type][sw_if_index] = counter; +} + +static void vl_api_vnet_interface_counters_t_handler + (vl_api_vnet_interface_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_interface_counters_t_handler_json + (vl_api_vnet_interface_counters_t * mp) +{ + interface_counter_t counter; + vlib_counter_t *v; + u64 *v_packets; + u64 packets; + u32 count; + u32 first_sw_if_index; + int i; + + count = ntohl (mp->count); + first_sw_if_index = ntohl (mp->first_sw_if_index); + + if (!mp->is_combined) + { + v_packets = (u64 *) & mp->data; + for (i = 0; i < count; i++) + { + packets = + clib_net_to_host_u64 (clib_mem_unaligned (v_packets, u64)); + set_simple_interface_counter (mp->vnet_counter_type, + first_sw_if_index + i, packets); + v_packets++; + } + } + else + { + v = (vlib_counter_t *) & mp->data; + for (i = 0; i < count; i++) + { + counter.packets = + clib_net_to_host_u64 (clib_mem_unaligned (&v->packets, u64)); + counter.bytes = + clib_net_to_host_u64 (clib_mem_unaligned (&v->bytes, u64)); + set_combined_interface_counter (mp->vnet_counter_type, + first_sw_if_index + i, counter); + v++; + } + } +} + +static u32 +ip4_fib_counters_get_vrf_index_by_vrf_id (u32 vrf_id) +{ + vat_main_t *vam = &vat_main; + u32 i; + + for (i = 0; i < vec_len (vam->ip4_fib_counters_vrf_id_by_index); i++) + { + if (vam->ip4_fib_counters_vrf_id_by_index[i] == vrf_id) + { + return i; + } + } + return ~0; +} + +static u32 +ip6_fib_counters_get_vrf_index_by_vrf_id (u32 vrf_id) +{ + vat_main_t *vam = &vat_main; + u32 i; + + for (i = 0; i < vec_len (vam->ip6_fib_counters_vrf_id_by_index); i++) + { + if (vam->ip6_fib_counters_vrf_id_by_index[i] == vrf_id) + { + return i; + } + } + return ~0; +} + +static void vl_api_vnet_ip4_fib_counters_t_handler + (vl_api_vnet_ip4_fib_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_ip4_fib_counters_t_handler_json + (vl_api_vnet_ip4_fib_counters_t * mp) +{ + vat_main_t *vam = &vat_main; + vl_api_ip4_fib_counter_t *v; + ip4_fib_counter_t *counter; + struct in_addr ip4; + u32 vrf_id; + u32 vrf_index; + u32 count; + int i; + + vrf_id = ntohl (mp->vrf_id); + vrf_index = ip4_fib_counters_get_vrf_index_by_vrf_id (vrf_id); + if (~0 == vrf_index) + { + vrf_index = vec_len (vam->ip4_fib_counters_vrf_id_by_index); + vec_validate (vam->ip4_fib_counters_vrf_id_by_index, vrf_index); + vam->ip4_fib_counters_vrf_id_by_index[vrf_index] = vrf_id; + vec_validate (vam->ip4_fib_counters, vrf_index); + vam->ip4_fib_counters[vrf_index] = NULL; + } + + vec_free (vam->ip4_fib_counters[vrf_index]); + v = (vl_api_ip4_fib_counter_t *) & mp->c; + count = ntohl (mp->count); + for (i = 0; i < count; i++) + { + vec_validate (vam->ip4_fib_counters[vrf_index], i); + counter = &vam->ip4_fib_counters[vrf_index][i]; + clib_memcpy (&ip4, &v->address, sizeof (ip4)); + counter->address = ip4; + counter->address_length = v->address_length; + counter->packets = clib_net_to_host_u64 (v->packets); + counter->bytes = clib_net_to_host_u64 (v->bytes); + v++; + } +} + +static void vl_api_vnet_ip6_fib_counters_t_handler + (vl_api_vnet_ip6_fib_counters_t * mp) +{ + /* not supported */ +} + +static void vl_api_vnet_ip6_fib_counters_t_handler_json + (vl_api_vnet_ip6_fib_counters_t * mp) +{ + vat_main_t *vam = &vat_main; + vl_api_ip6_fib_counter_t *v; + ip6_fib_counter_t *counter; + struct in6_addr ip6; + u32 vrf_id; + u32 vrf_index; + u32 count; + int i; + + vrf_id = ntohl (mp->vrf_id); + vrf_index = ip6_fib_counters_get_vrf_index_by_vrf_id (vrf_id); + if (~0 == vrf_index) + { + vrf_index = vec_len (vam->ip6_fib_counters_vrf_id_by_index); + vec_validate (vam->ip6_fib_counters_vrf_id_by_index, vrf_index); + vam->ip6_fib_counters_vrf_id_by_index[vrf_index] = vrf_id; + vec_validate (vam->ip6_fib_counters, vrf_index); + vam->ip6_fib_counters[vrf_index] = NULL; + } + + vec_free (vam->ip6_fib_counters[vrf_index]); + v = (vl_api_ip6_fib_counter_t *) & mp->c; + count = ntohl (mp->count); + for (i = 0; i < count; i++) + { + vec_validate (vam->ip6_fib_counters[vrf_index], i); + counter = &vam->ip6_fib_counters[vrf_index][i]; + clib_memcpy (&ip6, &v->address, sizeof (ip6)); + counter->address = ip6; + counter->address_length = v->address_length; + counter->packets = clib_net_to_host_u64 (v->packets); + counter->bytes = clib_net_to_host_u64 (v->bytes); + v++; + } +} + +static void vl_api_get_first_msg_id_reply_t_handler + (vl_api_get_first_msg_id_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } + if (retval >= 0) + { + errmsg ("first message id %d", ntohs (mp->first_msg_id)); + } +} + +static void vl_api_get_first_msg_id_reply_t_handler_json + (vl_api_get_first_msg_id_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "first_msg_id", + (uint) ntohs (mp->first_msg_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_get_node_graph_reply_t_handler + (vl_api_get_node_graph_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + api_main_t *am = &api_main; + i32 retval = ntohl (mp->retval); + u8 *pvt_copy, *reply; + void *oldheap; + vlib_node_t *node; + int i; + + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } + + /* "Should never happen..." */ + if (retval != 0) + return; + + reply = (u8 *) (mp->reply_in_shmem); + pvt_copy = vec_dup (reply); + + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + if (vam->graph_nodes) + { + hash_free (vam->graph_node_index_by_name); + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + vec_free (node->name); + vec_free (node->next_nodes); + vec_free (node); + } + vec_free (vam->graph_nodes); + } + + vam->graph_node_index_by_name = hash_create_string (0, sizeof (uword)); + vam->graph_nodes = vlib_node_unserialize (pvt_copy); + vec_free (pvt_copy); + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + hash_set_mem (vam->graph_node_index_by_name, node->name, i); + } +} + +static void vl_api_get_node_graph_reply_t_handler_json + (vl_api_get_node_graph_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + api_main_t *am = &api_main; + void *oldheap; + vat_json_node_t node; + u8 *reply; + + /* $$$$ make this real? */ + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "reply_in_shmem", mp->reply_in_shmem); + + reply = (u8 *) (mp->reply_in_shmem); + + /* Toss the shared-memory original... */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_free (reply); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_lisp_locator_details_t_handler (vl_api_lisp_locator_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = 0; + + if (mp->local) + { + s = format (s, "%=16d%=16d%=16d", + ntohl (mp->sw_if_index), mp->priority, mp->weight); + } + else + { + s = format (s, "%=16U%=16d%=16d", + mp->is_ipv6 ? format_ip6_address : + format_ip4_address, + mp->ip_address, mp->priority, mp->weight); + } + + print (vam->ofp, "%v", s); + vec_free (s); +} + +static void +vl_api_lisp_locator_details_t_handler_json (vl_api_lisp_locator_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "local", mp->local ? 1 : 0); + vat_json_object_add_uint (node, "priority", mp->priority); + vat_json_object_add_uint (node, "weight", mp->weight); + + if (mp->local) + vat_json_object_add_uint (node, "sw_if_index", + clib_net_to_host_u32 (mp->sw_if_index)); + else + { + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "address", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "address", ip4); + } + } +} + +static void +vl_api_lisp_locator_set_details_t_handler (vl_api_lisp_locator_set_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + + print (vam->ofp, "%=10d%=15v", clib_net_to_host_u32 (mp->ls_index), + ls_name); + vec_free (ls_name); +} + +static void + vl_api_lisp_locator_set_details_t_handler_json + (vl_api_lisp_locator_set_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *ls_name = 0; + + ls_name = format (0, "%s", mp->ls_name); + vec_add1 (ls_name, 0); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "ls_name", ls_name); + vat_json_object_add_uint (node, "ls_index", + clib_net_to_host_u32 (mp->ls_index)); + vec_free (ls_name); +} + +static u8 * +format_lisp_flat_eid (u8 * s, va_list * args) +{ + u32 type = va_arg (*args, u32); + u8 *eid = va_arg (*args, u8 *); + u32 eid_len = va_arg (*args, u32); + + switch (type) + { + case 0: + return format (s, "%U/%d", format_ip4_address, eid, eid_len); + case 1: + return format (s, "%U/%d", format_ip6_address, eid, eid_len); + case 2: + return format (s, "%U", format_ethernet_address, eid); + } + return 0; +} + +static u8 * +format_lisp_eid_vat (u8 * s, va_list * args) +{ + u32 type = va_arg (*args, u32); + u8 *eid = va_arg (*args, u8 *); + u32 eid_len = va_arg (*args, u32); + u8 *seid = va_arg (*args, u8 *); + u32 seid_len = va_arg (*args, u32); + u32 is_src_dst = va_arg (*args, u32); + + if (is_src_dst) + s = format (s, "%U|", format_lisp_flat_eid, type, seid, seid_len); + + s = format (s, "%U", format_lisp_flat_eid, type, eid, eid_len); + + return s; +} + +static void +vl_api_lisp_eid_table_details_t_handler (vl_api_lisp_eid_table_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *s = 0, *eid = 0; + + if (~0 == mp->locator_set_index) + s = format (0, "action: %d", mp->action); + else + s = format (0, "%d", clib_net_to_host_u32 (mp->locator_set_index)); + + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + + print (vam->ofp, "[%d] %-35s%-20s%-30s%-20d%-20d%-10d%-20s", + clib_net_to_host_u32 (mp->vni), + eid, + mp->is_local ? "local" : "remote", + s, clib_net_to_host_u32 (mp->ttl), mp->authoritative, + clib_net_to_host_u16 (mp->key_id), mp->key); + + vec_free (s); + vec_free (eid); +} + +static void +vl_api_lisp_eid_table_details_t_handler_json (vl_api_lisp_eid_table_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = 0; + u8 *eid = 0; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (~0 == mp->locator_set_index) + vat_json_object_add_uint (node, "action", mp->action); + else + vat_json_object_add_uint (node, "locator_set_index", + clib_net_to_host_u32 (mp->locator_set_index)); + + vat_json_object_add_uint (node, "is_local", mp->is_local ? 1 : 0); + eid = format (0, "%U", format_lisp_eid_vat, + mp->eid_type, + mp->eid, + mp->eid_prefix_len, + mp->seid, mp->seid_prefix_len, mp->is_src_dst); + vec_add1 (eid, 0); + vat_json_object_add_string_copy (node, "eid", eid); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); + vat_json_object_add_uint (node, "ttl", clib_net_to_host_u32 (mp->ttl)); + vat_json_object_add_uint (node, "authoritative", (mp->authoritative)); + + if (mp->key_id) + { + vat_json_object_add_uint (node, "key_id", + clib_net_to_host_u16 (mp->key_id)); + vat_json_object_add_string_copy (node, "key", mp->key); + } + vec_free (eid); +} + +static void + vl_api_lisp_eid_table_map_details_t_handler + (vl_api_lisp_eid_table_map_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + u8 *line = format (0, "%=10d%=10d", + clib_net_to_host_u32 (mp->vni), + clib_net_to_host_u32 (mp->dp_table)); + print (vam->ofp, "%v", line); + vec_free (line); +} + +static void + vl_api_lisp_eid_table_map_details_t_handler_json + (vl_api_lisp_eid_table_map_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + vat_json_object_add_uint (node, "dp_table", + clib_net_to_host_u32 (mp->dp_table)); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); +} + +static void + vl_api_lisp_eid_table_vni_details_t_handler + (vl_api_lisp_eid_table_vni_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + u8 *line = format (0, "%d", clib_net_to_host_u32 (mp->vni)); + print (vam->ofp, "%v", line); + vec_free (line); +} + +static void + vl_api_lisp_eid_table_vni_details_t_handler_json + (vl_api_lisp_eid_table_vni_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + vat_json_object_add_uint (node, "vni", clib_net_to_host_u32 (mp->vni)); +} + +static u8 * +format_decap_next (u8 * s, va_list * args) +{ + u32 next_index = va_arg (*args, u32); + + switch (next_index) + { + case LISP_GPE_INPUT_NEXT_DROP: + return format (s, "drop"); + case LISP_GPE_INPUT_NEXT_IP4_INPUT: + return format (s, "ip4"); + case LISP_GPE_INPUT_NEXT_IP6_INPUT: + return format (s, "ip6"); + default: + return format (s, "unknown %d", next_index); + } + return s; +} + +static void +vl_api_lisp_gpe_tunnel_details_t_handler (vl_api_lisp_gpe_tunnel_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + u8 *iid_str; + u8 *flag_str = NULL; + + iid_str = format (0, "%d (0x%x)", ntohl (mp->iid), ntohl (mp->iid)); + +#define _(n,v) if (mp->flags & v) flag_str = format (flag_str, "%s-bit ", #n); + foreach_lisp_gpe_flag_bit; +#undef _ + + print (vam->ofp, "%=20d%=30U%=16U%=16d%=16d%=16U" + "%=16d%=16d%=16sd=16d%=16s%=16s", + mp->tunnels, + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->source_ip, + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->destination_ip, + ntohl (mp->encap_fib_id), + ntohl (mp->decap_fib_id), + format_decap_next, ntohl (mp->dcap_next), + mp->ver_res >> 6, + flag_str, mp->next_protocol, mp->ver_res, mp->res, iid_str); + + vec_free (iid_str); +} + +static void + vl_api_lisp_gpe_tunnel_details_t_handler_json + (vl_api_lisp_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + u8 *next_decap_str; + + next_decap_str = format (0, "%U", format_decap_next, htonl (mp->dcap_next)); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "tunel", mp->tunnels); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->source_ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "source address", ip6); + clib_memcpy (&ip6, mp->destination_ip, sizeof (ip6)); + vat_json_object_add_ip6 (node, "destination address", ip6); + } + else + { + clib_memcpy (&ip4, mp->source_ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "source address", ip4); + clib_memcpy (&ip4, mp->destination_ip, sizeof (ip4)); + vat_json_object_add_ip4 (node, "destination address", ip4); + } + vat_json_object_add_uint (node, "fib encap", ntohl (mp->encap_fib_id)); + vat_json_object_add_uint (node, "fib decap", ntohl (mp->decap_fib_id)); + vat_json_object_add_string_copy (node, "decap next", next_decap_str); + vat_json_object_add_uint (node, "lisp version", mp->ver_res >> 6); + vat_json_object_add_uint (node, "flags", mp->flags); + vat_json_object_add_uint (node, "next protocol", mp->next_protocol); + vat_json_object_add_uint (node, "ver_res", mp->ver_res); + vat_json_object_add_uint (node, "res", mp->res); + vat_json_object_add_uint (node, "iid", ntohl (mp->iid)); + + vec_free (next_decap_str); +} + +static void + vl_api_show_lisp_map_register_state_reply_t_handler + (vl_api_show_lisp_map_register_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + print (vam->ofp, "%s", mp->is_enabled ? "enabled" : "disabled"); + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_map_register_state_reply_t_handler_json + (vl_api_show_lisp_map_register_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_enabled ? "enabled" : "disabled"); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + +static void + vl_api_show_lisp_rloc_probe_state_reply_t_handler + (vl_api_show_lisp_rloc_probe_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int retval = clib_net_to_host_u32 (mp->retval); + + if (retval) + goto end; + + print (vam->ofp, "%s", mp->is_enabled ? "enabled" : "disabled"); +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_rloc_probe_state_reply_t_handler_json + (vl_api_show_lisp_rloc_probe_state_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t _node, *node = &_node; + int retval = clib_net_to_host_u32 (mp->retval); + + u8 *s = format (0, "%s", mp->is_enabled ? "enabled" : "disabled"); + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "state", s); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = retval; + vam->result_ready = 1; + vec_free (s); +} + +static void + vl_api_lisp_adjacencies_get_reply_t_handler + (vl_api_lisp_adjacencies_get_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_lisp_adjacency_t *a; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + + for (i = 0; i < n; i++) + { + a = &mp->adjacencies[i]; + print (vam->ofp, "%U %40U", + format_lisp_flat_eid, a->eid_type, a->leid, a->leid_prefix_len, + format_lisp_flat_eid, a->eid_type, a->reid, a->reid_prefix_len); + } + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_lisp_adjacencies_get_reply_t_handler_json + (vl_api_lisp_adjacencies_get_reply_t * mp) +{ + u8 *s = 0; + vat_main_t *vam = &vat_main; + vat_json_node_t *e = 0, root; + u32 i, n; + int retval = clib_net_to_host_u32 (mp->retval); + vl_api_lisp_adjacency_t *a; + + if (retval) + goto end; + + n = clib_net_to_host_u32 (mp->count); + vat_json_init_array (&root); + + for (i = 0; i < n; i++) + { + e = vat_json_array_add (&root); + a = &mp->adjacencies[i]; + + vat_json_init_object (e); + s = format (0, "%U", format_lisp_flat_eid, a->eid_type, a->leid, + a->leid_prefix_len); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "leid", s); + vec_free (s); + + s = format (0, "%U", format_lisp_flat_eid, a->eid_type, a->reid, + a->reid_prefix_len); + vec_add1 (s, 0); + vat_json_object_add_string_copy (e, "reid", s); + vec_free (s); + } + + vat_json_print (vam->ofp, &root); + vat_json_free (&root); + +end: + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_lisp_map_server_details_t_handler (vl_api_lisp_map_server_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%=20U", + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->ip_address); +} + +static void + vl_api_lisp_map_server_details_t_handler_json + (vl_api_lisp_map_server_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "map-server", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "map-server", ip4); + } +} + +static void +vl_api_lisp_map_resolver_details_t_handler (vl_api_lisp_map_resolver_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%=20U", + mp->is_ipv6 ? format_ip6_address : format_ip4_address, + mp->ip_address); +} + +static void + vl_api_lisp_map_resolver_details_t_handler_json + (vl_api_lisp_map_resolver_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr ip6; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "map resolver", ip6); + } + else + { + clib_memcpy (&ip4, mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "map resolver", ip4); + } +} + +static void + vl_api_show_lisp_status_reply_t_handler + (vl_api_show_lisp_status_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "feature: %s\ngpe: %s", + mp->feature_status ? "enabled" : "disabled", + mp->gpe_status ? "enabled" : "disabled"); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_status_reply_t_handler_json + (vl_api_show_lisp_status_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *gpe_status = NULL; + u8 *feature_status = NULL; + + gpe_status = format (0, "%s", mp->gpe_status ? "enabled" : "disabled"); + feature_status = format (0, "%s", + mp->feature_status ? "enabled" : "disabled"); + vec_add1 (gpe_status, 0); + vec_add1 (feature_status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "gpe_status", gpe_status); + vat_json_object_add_string_copy (&node, "feature_status", feature_status); + + vec_free (gpe_status); + vec_free (feature_status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_lisp_get_map_request_itr_rlocs_reply_t_handler + (vl_api_lisp_get_map_request_itr_rlocs_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (retval >= 0) + { + print (vam->ofp, "%=20s", mp->locator_set_name); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_lisp_get_map_request_itr_rlocs_reply_t_handler_json + (vl_api_lisp_get_map_request_itr_rlocs_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "itr-rlocs", mp->locator_set_name); + + vat_json_print (vam->ofp, node); + vat_json_free (node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static u8 * +format_lisp_map_request_mode (u8 * s, va_list * args) +{ + u32 mode = va_arg (*args, u32); + + switch (mode) + { + case 0: + return format (0, "dst-only"); + case 1: + return format (0, "src-dst"); + } + return 0; +} + +static void + vl_api_show_lisp_map_request_mode_reply_t_handler + (vl_api_show_lisp_map_request_mode_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + u32 mode = mp->mode; + print (vam->ofp, "map_request_mode: %U", + format_lisp_map_request_mode, mode); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_show_lisp_map_request_mode_reply_t_handler_json + (vl_api_show_lisp_map_request_mode_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *s = 0; + u32 mode; + + mode = mp->mode; + s = format (0, "%U", format_lisp_map_request_mode, mode); + vec_add1 (s, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "map_request_mode", s); + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vec_free (s); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_show_lisp_pitr_reply_t_handler (vl_api_show_lisp_pitr_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (0 <= retval) + { + print (vam->ofp, "%-20s%-16s", + mp->status ? "enabled" : "disabled", + mp->status ? (char *) mp->locator_set_name : ""); + } + + vam->retval = retval; + vam->result_ready = 1; +} + +static void +vl_api_show_lisp_pitr_reply_t_handler_json (vl_api_show_lisp_pitr_reply_t * + mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + u8 *status = 0; + + status = format (0, "%s", mp->status ? "enabled" : "disabled"); + vec_add1 (status, 0); + + vat_json_init_object (&node); + vat_json_object_add_string_copy (&node, "status", status); + if (mp->status) + { + vat_json_object_add_string_copy (&node, "locator_set", + mp->locator_set_name); + } + + vec_free (status); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static u8 * +format_policer_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_POLICER_TYPE_1R2C) + s = format (s, "1r2c"); + else if (i == SSE2_QOS_POLICER_TYPE_1R3C_RFC_2697) + s = format (s, "1r3c"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_2698) + s = format (s, "2r3c-2698"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_4115) + s = format (s, "2r3c-4115"); + else if (i == SSE2_QOS_POLICER_TYPE_2R3C_RFC_MEF5CF1) + s = format (s, "2r3c-mef5cf1"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_rate_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_RATE_KBPS) + s = format (s, "kbps"); + else if (i == SSE2_QOS_RATE_PPS) + s = format (s, "pps"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_round_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_ROUND_TO_CLOSEST) + s = format (s, "closest"); + else if (i == SSE2_QOS_ROUND_TO_UP) + s = format (s, "up"); + else if (i == SSE2_QOS_ROUND_TO_DOWN) + s = format (s, "down"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_policer_action_type (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + + if (i == SSE2_QOS_ACTION_DROP) + s = format (s, "drop"); + else if (i == SSE2_QOS_ACTION_TRANSMIT) + s = format (s, "transmit"); + else if (i == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + s = format (s, "mark-and-transmit"); + else + s = format (s, "ILLEGAL"); + return s; +} + +static u8 * +format_dscp (u8 * s, va_list * va) +{ + u32 i = va_arg (*va, u32); + char *t = 0; + + switch (i) + { +#define _(v,f,str) case VNET_DSCP_##f: t = str; break; + foreach_vnet_dscp +#undef _ + default: + return format (s, "ILLEGAL"); + } + s = format (s, "%s", t); + return s; +} + +static void +vl_api_policer_details_t_handler (vl_api_policer_details_t * mp) +{ + vat_main_t *vam = &vat_main; + u8 *conform_dscp_str, *exceed_dscp_str, *violate_dscp_str; + + if (mp->conform_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + conform_dscp_str = format (0, "%U", format_dscp, mp->conform_dscp); + else + conform_dscp_str = format (0, ""); + + if (mp->exceed_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + exceed_dscp_str = format (0, "%U", format_dscp, mp->exceed_dscp); + else + exceed_dscp_str = format (0, ""); + + if (mp->violate_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + violate_dscp_str = format (0, "%U", format_dscp, mp->violate_dscp); + else + violate_dscp_str = format (0, ""); + + print (vam->ofp, "Name \"%s\", type %U, cir %u, eir %u, cb %u, eb %u, " + "rate type %U, round type %U, %s rate, %s color-aware, " + "cir %u tok/period, pir %u tok/period, scale %u, cur lim %u, " + "cur bkt %u, ext lim %u, ext bkt %u, last update %llu" + "conform action %U%s, exceed action %U%s, violate action %U%s", + mp->name, + format_policer_type, mp->type, + ntohl (mp->cir), + ntohl (mp->eir), + clib_net_to_host_u64 (mp->cb), + clib_net_to_host_u64 (mp->eb), + format_policer_rate_type, mp->rate_type, + format_policer_round_type, mp->round_type, + mp->single_rate ? "single" : "dual", + mp->color_aware ? "is" : "not", + ntohl (mp->cir_tokens_per_period), + ntohl (mp->pir_tokens_per_period), + ntohl (mp->scale), + ntohl (mp->current_limit), + ntohl (mp->current_bucket), + ntohl (mp->extended_limit), + ntohl (mp->extended_bucket), + clib_net_to_host_u64 (mp->last_update_time), + format_policer_action_type, mp->conform_action_type, + conform_dscp_str, + format_policer_action_type, mp->exceed_action_type, + exceed_dscp_str, + format_policer_action_type, mp->violate_action_type, + violate_dscp_str); + + vec_free (conform_dscp_str); + vec_free (exceed_dscp_str); + vec_free (violate_dscp_str); +} + +static void vl_api_policer_details_t_handler_json + (vl_api_policer_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + u8 *rate_type_str, *round_type_str, *type_str; + u8 *conform_action_str, *exceed_action_str, *violate_action_str; + + rate_type_str = format (0, "%U", format_policer_rate_type, mp->rate_type); + round_type_str = + format (0, "%U", format_policer_round_type, mp->round_type); + type_str = format (0, "%U", format_policer_type, mp->type); + conform_action_str = format (0, "%U", format_policer_action_type, + mp->conform_action_type); + exceed_action_str = format (0, "%U", format_policer_action_type, + mp->exceed_action_type); + violate_action_str = format (0, "%U", format_policer_action_type, + mp->violate_action_type); + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "name", mp->name); + vat_json_object_add_uint (node, "cir", ntohl (mp->cir)); + vat_json_object_add_uint (node, "eir", ntohl (mp->eir)); + vat_json_object_add_uint (node, "cb", ntohl (mp->cb)); + vat_json_object_add_uint (node, "eb", ntohl (mp->eb)); + vat_json_object_add_string_copy (node, "rate_type", rate_type_str); + vat_json_object_add_string_copy (node, "round_type", round_type_str); + vat_json_object_add_string_copy (node, "type", type_str); + vat_json_object_add_uint (node, "single_rate", mp->single_rate); + vat_json_object_add_uint (node, "color_aware", mp->color_aware); + vat_json_object_add_uint (node, "scale", ntohl (mp->scale)); + vat_json_object_add_uint (node, "cir_tokens_per_period", + ntohl (mp->cir_tokens_per_period)); + vat_json_object_add_uint (node, "eir_tokens_per_period", + ntohl (mp->pir_tokens_per_period)); + vat_json_object_add_uint (node, "current_limit", ntohl (mp->current_limit)); + vat_json_object_add_uint (node, "current_bucket", + ntohl (mp->current_bucket)); + vat_json_object_add_uint (node, "extended_limit", + ntohl (mp->extended_limit)); + vat_json_object_add_uint (node, "extended_bucket", + ntohl (mp->extended_bucket)); + vat_json_object_add_uint (node, "last_update_time", + ntohl (mp->last_update_time)); + vat_json_object_add_string_copy (node, "conform_action", + conform_action_str); + if (mp->conform_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->conform_dscp); + vat_json_object_add_string_copy (node, "conform_dscp", dscp_str); + vec_free (dscp_str); + } + vat_json_object_add_string_copy (node, "exceed_action", exceed_action_str); + if (mp->exceed_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->exceed_dscp); + vat_json_object_add_string_copy (node, "exceed_dscp", dscp_str); + vec_free (dscp_str); + } + vat_json_object_add_string_copy (node, "violate_action", + violate_action_str); + if (mp->violate_action_type == SSE2_QOS_ACTION_MARK_AND_TRANSMIT) + { + u8 *dscp_str = format (0, "%U", format_dscp, mp->violate_dscp); + vat_json_object_add_string_copy (node, "violate_dscp", dscp_str); + vec_free (dscp_str); + } + + vec_free (rate_type_str); + vec_free (round_type_str); + vec_free (type_str); + vec_free (conform_action_str); + vec_free (exceed_action_str); + vec_free (violate_action_str); +} + +static void +vl_api_classify_table_ids_reply_t_handler (vl_api_classify_table_ids_reply_t * + mp) +{ + vat_main_t *vam = &vat_main; + int i, count = ntohl (mp->count); + + if (count > 0) + print (vam->ofp, "classify table ids (%d) : ", count); + for (i = 0; i < count; i++) + { + print (vam->ofp, "%d", ntohl (mp->ids[i])); + print (vam->ofp, (i < count - 1) ? "," : ""); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_ids_reply_t_handler_json + (vl_api_classify_table_ids_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + int i, count = ntohl (mp->count); + + if (count > 0) + { + vat_json_node_t node; + + vat_json_init_object (&node); + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (&node, "table_id", ntohl (mp->ids[i])); + } + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_by_interface_reply_t_handler + (vl_api_classify_table_by_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + u32 table_id; + + table_id = ntohl (mp->l2_table_id); + if (table_id != ~0) + print (vam->ofp, "l2 table id : %d", table_id); + else + print (vam->ofp, "l2 table id : No input ACL tables configured"); + table_id = ntohl (mp->ip4_table_id); + if (table_id != ~0) + print (vam->ofp, "ip4 table id : %d", table_id); + else + print (vam->ofp, "ip4 table id : No input ACL tables configured"); + table_id = ntohl (mp->ip6_table_id); + if (table_id != ~0) + print (vam->ofp, "ip6 table id : %d", table_id); + else + print (vam->ofp, "ip6 table id : No input ACL tables configured"); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void + vl_api_classify_table_by_interface_reply_t_handler_json + (vl_api_classify_table_by_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "l2_table_id", ntohl (mp->l2_table_id)); + vat_json_object_add_int (&node, "ip4_table_id", ntohl (mp->ip4_table_id)); + vat_json_object_add_int (&node, "ip6_table_id", ntohl (mp->ip6_table_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_policer_add_del_reply_t_handler + (vl_api_policer_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + if (retval == 0 && mp->policer_index != 0xFFFFFFFF) + /* + * Note: this is just barely thread-safe, depends on + * the main thread spinning waiting for an answer... + */ + errmsg ("policer index %d", ntohl (mp->policer_index)); + } +} + +static void vl_api_policer_add_del_reply_t_handler_json + (vl_api_policer_add_del_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "policer_index", + ntohl (mp->policer_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +/* Format hex dump. */ +u8 * +format_hex_bytes (u8 * s, va_list * va) +{ + u8 *bytes = va_arg (*va, u8 *); + int n_bytes = va_arg (*va, int); + uword i; + + /* Print short or long form depending on byte count. */ + uword short_form = n_bytes <= 32; + uword indent = format_get_indent (s); + + if (n_bytes == 0) + return s; + + for (i = 0; i < n_bytes; i++) + { + if (!short_form && (i % 32) == 0) + s = format (s, "%08x: ", i); + s = format (s, "%02x", bytes[i]); + if (!short_form && ((i + 1) % 32) == 0 && (i + 1) < n_bytes) + s = format (s, "\n%U", format_white_space, indent); + } + + return s; +} + +static void +vl_api_classify_table_info_reply_t_handler (vl_api_classify_table_info_reply_t + * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + print (vam->ofp, "classify table info :"); + print (vam->ofp, "sessions: %d nexttbl: %d nextnode: %d", + ntohl (mp->active_sessions), ntohl (mp->next_table_index), + ntohl (mp->miss_next_index)); + print (vam->ofp, "nbuckets: %d skip: %d match: %d", + ntohl (mp->nbuckets), ntohl (mp->skip_n_vectors), + ntohl (mp->match_n_vectors)); + print (vam->ofp, "mask: %U", format_hex_bytes, mp->mask, + ntohl (mp->mask_length)); + } + vam->retval = retval; + vam->result_ready = 1; +} + +static void + vl_api_classify_table_info_reply_t_handler_json + (vl_api_classify_table_info_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "sessions", + ntohl (mp->active_sessions)); + vat_json_object_add_int (&node, "nexttbl", + ntohl (mp->next_table_index)); + vat_json_object_add_int (&node, "nextnode", + ntohl (mp->miss_next_index)); + vat_json_object_add_int (&node, "nbuckets", ntohl (mp->nbuckets)); + vat_json_object_add_int (&node, "skip", ntohl (mp->skip_n_vectors)); + vat_json_object_add_int (&node, "match", ntohl (mp->match_n_vectors)); + u8 *s = format (0, "%U%c", format_hex_bytes, mp->mask, + ntohl (mp->mask_length), 0); + vat_json_object_add_string_copy (&node, "mask", s); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void +vl_api_classify_session_details_t_handler (vl_api_classify_session_details_t * + mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "next_index: %d advance: %d opaque: %d ", + ntohl (mp->hit_next_index), ntohl (mp->advance), + ntohl (mp->opaque_index)); + print (vam->ofp, "mask: %U", format_hex_bytes, mp->match, + ntohl (mp->match_length)); +} + +static void + vl_api_classify_session_details_t_handler_json + (vl_api_classify_session_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_int (node, "next_index", ntohl (mp->hit_next_index)); + vat_json_object_add_int (node, "advance", ntohl (mp->advance)); + vat_json_object_add_int (node, "opaque", ntohl (mp->opaque_index)); + u8 *s = + format (0, "%U%c", format_hex_bytes, mp->match, ntohl (mp->match_length), + 0); + vat_json_object_add_string_copy (node, "match", s); +} + +static void vl_api_pg_create_interface_reply_t_handler + (vl_api_pg_create_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_pg_create_interface_reply_t_handler_json + (vl_api_pg_create_interface_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + i32 retval = ntohl (mp->retval); + if (retval == 0) + { + vat_json_init_object (&node); + + vat_json_object_add_int (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + } + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_policer_classify_details_t_handler + (vl_api_policer_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%10d%20d", ntohl (mp->sw_if_index), + ntohl (mp->table_index)); +} + +static void vl_api_policer_classify_details_t_handler_json + (vl_api_policer_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "table_index", ntohl (mp->table_index)); +} + +static void vl_api_ipsec_gre_add_del_tunnel_reply_t_handler + (vl_api_ipsec_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; + } +} + +static void vl_api_ipsec_gre_add_del_tunnel_reply_t_handler_json + (vl_api_ipsec_gre_add_del_tunnel_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static void vl_api_flow_classify_details_t_handler + (vl_api_flow_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%10d%20d", ntohl (mp->sw_if_index), + ntohl (mp->table_index)); +} + +static void vl_api_flow_classify_details_t_handler_json + (vl_api_flow_classify_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "table_index", ntohl (mp->table_index)); +} + + + +#define vl_api_vnet_ip4_fib_counters_t_endian vl_noop_handler +#define vl_api_vnet_ip4_fib_counters_t_print vl_noop_handler +#define vl_api_vnet_ip6_fib_counters_t_endian vl_noop_handler +#define vl_api_vnet_ip6_fib_counters_t_print vl_noop_handler +#define vl_api_lisp_adjacencies_get_reply_t_endian vl_noop_handler +#define vl_api_lisp_adjacencies_get_reply_t_print vl_noop_handler + +/* + * Generate boilerplate reply handlers, which + * dig the return value out of the xxx_reply_t API message, + * stick it into vam->retval, and set vam->result_ready + * + * Could also do this by pointing N message decode slots at + * a single function, but that could break in subtle ways. + */ + +#define foreach_standard_reply_retval_handler \ +_(sw_interface_set_flags_reply) \ +_(sw_interface_add_del_address_reply) \ +_(sw_interface_set_table_reply) \ +_(sw_interface_set_mpls_enable_reply) \ +_(sw_interface_set_vpath_reply) \ +_(sw_interface_set_vxlan_bypass_reply) \ +_(sw_interface_set_l2_bridge_reply) \ +_(sw_interface_set_dpdk_hqos_pipe_reply) \ +_(sw_interface_set_dpdk_hqos_subport_reply) \ +_(sw_interface_set_dpdk_hqos_tctbl_reply) \ +_(bridge_domain_add_del_reply) \ +_(sw_interface_set_l2_xconnect_reply) \ +_(l2fib_add_del_reply) \ +_(ip_add_del_route_reply) \ +_(mpls_route_add_del_reply) \ +_(mpls_ip_bind_unbind_reply) \ +_(proxy_arp_add_del_reply) \ +_(proxy_arp_intfc_enable_disable_reply) \ +_(sw_interface_set_unnumbered_reply) \ +_(ip_neighbor_add_del_reply) \ +_(reset_vrf_reply) \ +_(oam_add_del_reply) \ +_(reset_fib_reply) \ +_(dhcp_proxy_config_reply) \ +_(dhcp_proxy_config_2_reply) \ +_(dhcp_proxy_set_vss_reply) \ +_(dhcp_client_config_reply) \ +_(set_ip_flow_hash_reply) \ +_(sw_interface_ip6_enable_disable_reply) \ +_(sw_interface_ip6_set_link_local_address_reply) \ +_(sw_interface_ip6nd_ra_prefix_reply) \ +_(sw_interface_ip6nd_ra_config_reply) \ +_(set_arp_neighbor_limit_reply) \ +_(l2_patch_add_del_reply) \ +_(sr_tunnel_add_del_reply) \ +_(sr_policy_add_del_reply) \ +_(sr_multicast_map_add_del_reply) \ +_(classify_add_del_session_reply) \ +_(classify_set_interface_ip_table_reply) \ +_(classify_set_interface_l2_tables_reply) \ +_(l2tpv3_set_tunnel_cookies_reply) \ +_(l2tpv3_interface_enable_disable_reply) \ +_(l2tpv3_set_lookup_key_reply) \ +_(l2_fib_clear_table_reply) \ +_(l2_interface_efp_filter_reply) \ +_(l2_interface_vlan_tag_rewrite_reply) \ +_(modify_vhost_user_if_reply) \ +_(delete_vhost_user_if_reply) \ +_(want_ip4_arp_events_reply) \ +_(want_ip6_nd_events_reply) \ +_(input_acl_set_interface_reply) \ +_(ipsec_spd_add_del_reply) \ +_(ipsec_interface_add_del_spd_reply) \ +_(ipsec_spd_add_del_entry_reply) \ +_(ipsec_sad_add_del_entry_reply) \ +_(ipsec_sa_set_key_reply) \ +_(ikev2_profile_add_del_reply) \ +_(ikev2_profile_set_auth_reply) \ +_(ikev2_profile_set_id_reply) \ +_(ikev2_profile_set_ts_reply) \ +_(ikev2_set_local_key_reply) \ +_(delete_loopback_reply) \ +_(bd_ip_mac_add_del_reply) \ +_(map_del_domain_reply) \ +_(map_add_del_rule_reply) \ +_(want_interface_events_reply) \ +_(want_stats_reply) \ +_(cop_interface_enable_disable_reply) \ +_(cop_whitelist_enable_disable_reply) \ +_(sw_interface_clear_stats_reply) \ +_(ioam_enable_reply) \ +_(ioam_disable_reply) \ +_(lisp_add_del_locator_reply) \ +_(lisp_add_del_local_eid_reply) \ +_(lisp_add_del_remote_mapping_reply) \ +_(lisp_add_del_adjacency_reply) \ +_(lisp_gpe_add_del_fwd_entry_reply) \ +_(lisp_add_del_map_resolver_reply) \ +_(lisp_add_del_map_server_reply) \ +_(lisp_gpe_enable_disable_reply) \ +_(lisp_gpe_add_del_iface_reply) \ +_(lisp_enable_disable_reply) \ +_(lisp_rloc_probe_enable_disable_reply) \ +_(lisp_map_register_enable_disable_reply) \ +_(lisp_pitr_set_locator_set_reply) \ +_(lisp_map_request_mode_reply) \ +_(lisp_add_del_map_request_itr_rlocs_reply) \ +_(lisp_eid_table_add_del_map_reply) \ +_(vxlan_gpe_add_del_tunnel_reply) \ +_(af_packet_delete_reply) \ +_(policer_classify_set_interface_reply) \ +_(netmap_create_reply) \ +_(netmap_delete_reply) \ +_(set_ipfix_exporter_reply) \ +_(set_ipfix_classify_stream_reply) \ +_(ipfix_classify_table_add_del_reply) \ +_(flow_classify_set_interface_reply) \ +_(sw_interface_span_enable_disable_reply) \ +_(pg_capture_reply) \ +_(pg_enable_disable_reply) \ +_(ip_source_and_port_range_check_add_del_reply) \ +_(ip_source_and_port_range_check_interface_add_del_reply)\ +_(delete_subif_reply) \ +_(l2_interface_pbb_tag_rewrite_reply) \ +_(punt_reply) \ +_(feature_enable_disable_reply) \ +_(sw_interface_tag_add_del_reply) \ +_(sw_interface_set_mtu_reply) + +#define _(n) \ + static void vl_api_##n##_t_handler \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = &vat_main; \ + i32 retval = ntohl(mp->retval); \ + if (vam->async_mode) { \ + vam->async_errors += (retval < 0); \ + } else { \ + vam->retval = retval; \ + vam->result_ready = 1; \ + } \ + } +foreach_standard_reply_retval_handler; +#undef _ + +#define _(n) \ + static void vl_api_##n##_t_handler_json \ + (vl_api_##n##_t * mp) \ + { \ + vat_main_t * vam = &vat_main; \ + vat_json_node_t node; \ + vat_json_init_object(&node); \ + vat_json_object_add_int(&node, "retval", ntohl(mp->retval)); \ + vat_json_print(vam->ofp, &node); \ + vam->retval = ntohl(mp->retval); \ + vam->result_ready = 1; \ + } +foreach_standard_reply_retval_handler; +#undef _ + +/* + * Table of message reply handlers, must include boilerplate handlers + * we just generated + */ + +#define foreach_vpe_api_reply_msg \ +_(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ +_(SW_INTERFACE_DETAILS, sw_interface_details) \ +_(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ +_(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ +_(CONTROL_PING_REPLY, control_ping_reply) \ +_(CLI_REPLY, cli_reply) \ +_(CLI_INBAND_REPLY, cli_inband_reply) \ +_(SW_INTERFACE_ADD_DEL_ADDRESS_REPLY, \ + sw_interface_add_del_address_reply) \ +_(SW_INTERFACE_SET_TABLE_REPLY, sw_interface_set_table_reply) \ +_(SW_INTERFACE_SET_MPLS_ENABLE_REPLY, sw_interface_set_mpls_enable_reply) \ +_(SW_INTERFACE_SET_VPATH_REPLY, sw_interface_set_vpath_reply) \ +_(SW_INTERFACE_SET_VXLAN_BYPASS_REPLY, sw_interface_set_vxlan_bypass_reply) \ +_(SW_INTERFACE_SET_L2_XCONNECT_REPLY, \ + sw_interface_set_l2_xconnect_reply) \ +_(SW_INTERFACE_SET_L2_BRIDGE_REPLY, \ + sw_interface_set_l2_bridge_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_PIPE_REPLY, \ + sw_interface_set_dpdk_hqos_pipe_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_SUBPORT_REPLY, \ + sw_interface_set_dpdk_hqos_subport_reply) \ +_(SW_INTERFACE_SET_DPDK_HQOS_TCTBL_REPLY, \ + sw_interface_set_dpdk_hqos_tctbl_reply) \ +_(BRIDGE_DOMAIN_ADD_DEL_REPLY, bridge_domain_add_del_reply) \ +_(BRIDGE_DOMAIN_DETAILS, bridge_domain_details) \ +_(BRIDGE_DOMAIN_SW_IF_DETAILS, bridge_domain_sw_if_details) \ +_(L2FIB_ADD_DEL_REPLY, l2fib_add_del_reply) \ +_(L2_FLAGS_REPLY, l2_flags_reply) \ +_(BRIDGE_FLAGS_REPLY, bridge_flags_reply) \ +_(TAP_CONNECT_REPLY, tap_connect_reply) \ +_(TAP_MODIFY_REPLY, tap_modify_reply) \ +_(TAP_DELETE_REPLY, tap_delete_reply) \ +_(SW_INTERFACE_TAP_DETAILS, sw_interface_tap_details) \ +_(IP_ADD_DEL_ROUTE_REPLY, ip_add_del_route_reply) \ +_(MPLS_ROUTE_ADD_DEL_REPLY, mpls_route_add_del_reply) \ +_(MPLS_IP_BIND_UNBIND_REPLY, mpls_ip_bind_unbind_reply) \ +_(PROXY_ARP_ADD_DEL_REPLY, proxy_arp_add_del_reply) \ +_(PROXY_ARP_INTFC_ENABLE_DISABLE_REPLY, \ + proxy_arp_intfc_enable_disable_reply) \ +_(MPLS_TUNNEL_ADD_DEL_REPLY, mpls_tunnel_add_del_reply) \ +_(SW_INTERFACE_SET_UNNUMBERED_REPLY, \ + sw_interface_set_unnumbered_reply) \ +_(IP_NEIGHBOR_ADD_DEL_REPLY, ip_neighbor_add_del_reply) \ +_(RESET_VRF_REPLY, reset_vrf_reply) \ +_(CREATE_VLAN_SUBIF_REPLY, create_vlan_subif_reply) \ +_(CREATE_SUBIF_REPLY, create_subif_reply) \ +_(OAM_ADD_DEL_REPLY, oam_add_del_reply) \ +_(RESET_FIB_REPLY, reset_fib_reply) \ +_(DHCP_PROXY_CONFIG_REPLY, dhcp_proxy_config_reply) \ +_(DHCP_PROXY_CONFIG_2_REPLY, dhcp_proxy_config_2_reply) \ +_(DHCP_PROXY_SET_VSS_REPLY, dhcp_proxy_set_vss_reply) \ +_(DHCP_CLIENT_CONFIG_REPLY, dhcp_client_config_reply) \ +_(SET_IP_FLOW_HASH_REPLY, set_ip_flow_hash_reply) \ +_(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, \ + sw_interface_ip6_enable_disable_reply) \ +_(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY, \ + sw_interface_ip6_set_link_local_address_reply) \ +_(SW_INTERFACE_IP6ND_RA_PREFIX_REPLY, \ + sw_interface_ip6nd_ra_prefix_reply) \ +_(SW_INTERFACE_IP6ND_RA_CONFIG_REPLY, \ + sw_interface_ip6nd_ra_config_reply) \ +_(SET_ARP_NEIGHBOR_LIMIT_REPLY, set_arp_neighbor_limit_reply) \ +_(L2_PATCH_ADD_DEL_REPLY, l2_patch_add_del_reply) \ +_(SR_TUNNEL_ADD_DEL_REPLY, sr_tunnel_add_del_reply) \ +_(SR_POLICY_ADD_DEL_REPLY, sr_policy_add_del_reply) \ +_(SR_MULTICAST_MAP_ADD_DEL_REPLY, sr_multicast_map_add_del_reply) \ +_(CLASSIFY_ADD_DEL_TABLE_REPLY, classify_add_del_table_reply) \ +_(CLASSIFY_ADD_DEL_SESSION_REPLY, classify_add_del_session_reply) \ +_(CLASSIFY_SET_INTERFACE_IP_TABLE_REPLY, \ +classify_set_interface_ip_table_reply) \ +_(CLASSIFY_SET_INTERFACE_L2_TABLES_REPLY, \ + classify_set_interface_l2_tables_reply) \ +_(GET_NODE_INDEX_REPLY, get_node_index_reply) \ +_(ADD_NODE_NEXT_REPLY, add_node_next_reply) \ +_(L2TPV3_CREATE_TUNNEL_REPLY, l2tpv3_create_tunnel_reply) \ +_(L2TPV3_SET_TUNNEL_COOKIES_REPLY, l2tpv3_set_tunnel_cookies_reply) \ +_(L2TPV3_INTERFACE_ENABLE_DISABLE_REPLY, \ + l2tpv3_interface_enable_disable_reply) \ +_(L2TPV3_SET_LOOKUP_KEY_REPLY, l2tpv3_set_lookup_key_reply) \ +_(SW_IF_L2TPV3_TUNNEL_DETAILS, sw_if_l2tpv3_tunnel_details) \ +_(VXLAN_ADD_DEL_TUNNEL_REPLY, vxlan_add_del_tunnel_reply) \ +_(VXLAN_TUNNEL_DETAILS, vxlan_tunnel_details) \ +_(GRE_ADD_DEL_TUNNEL_REPLY, gre_add_del_tunnel_reply) \ +_(GRE_TUNNEL_DETAILS, gre_tunnel_details) \ +_(L2_FIB_CLEAR_TABLE_REPLY, l2_fib_clear_table_reply) \ +_(L2_INTERFACE_EFP_FILTER_REPLY, l2_interface_efp_filter_reply) \ +_(L2_INTERFACE_VLAN_TAG_REWRITE_REPLY, l2_interface_vlan_tag_rewrite_reply) \ +_(SW_INTERFACE_VHOST_USER_DETAILS, sw_interface_vhost_user_details) \ +_(CREATE_VHOST_USER_IF_REPLY, create_vhost_user_if_reply) \ +_(MODIFY_VHOST_USER_IF_REPLY, modify_vhost_user_if_reply) \ +_(DELETE_VHOST_USER_IF_REPLY, delete_vhost_user_if_reply) \ +_(SHOW_VERSION_REPLY, show_version_reply) \ +_(L2_FIB_TABLE_ENTRY, l2_fib_table_entry) \ +_(VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, vxlan_gpe_add_del_tunnel_reply) \ +_(VXLAN_GPE_TUNNEL_DETAILS, vxlan_gpe_tunnel_details) \ +_(INTERFACE_NAME_RENUMBER_REPLY, interface_name_renumber_reply) \ +_(WANT_IP4_ARP_EVENTS_REPLY, want_ip4_arp_events_reply) \ +_(IP4_ARP_EVENT, ip4_arp_event) \ +_(WANT_IP6_ND_EVENTS_REPLY, want_ip6_nd_events_reply) \ +_(IP6_ND_EVENT, ip6_nd_event) \ +_(INPUT_ACL_SET_INTERFACE_REPLY, input_acl_set_interface_reply) \ +_(IP_ADDRESS_DETAILS, ip_address_details) \ +_(IP_DETAILS, ip_details) \ +_(IPSEC_SPD_ADD_DEL_REPLY, ipsec_spd_add_del_reply) \ +_(IPSEC_INTERFACE_ADD_DEL_SPD_REPLY, ipsec_interface_add_del_spd_reply) \ +_(IPSEC_SPD_ADD_DEL_ENTRY_REPLY, ipsec_spd_add_del_entry_reply) \ +_(IPSEC_SAD_ADD_DEL_ENTRY_REPLY, ipsec_sad_add_del_entry_reply) \ +_(IPSEC_SA_SET_KEY_REPLY, ipsec_sa_set_key_reply) \ +_(IKEV2_PROFILE_ADD_DEL_REPLY, ikev2_profile_add_del_reply) \ +_(IKEV2_PROFILE_SET_AUTH_REPLY, ikev2_profile_set_auth_reply) \ +_(IKEV2_PROFILE_SET_ID_REPLY, ikev2_profile_set_id_reply) \ +_(IKEV2_PROFILE_SET_TS_REPLY, ikev2_profile_set_ts_reply) \ +_(IKEV2_SET_LOCAL_KEY_REPLY, ikev2_set_local_key_reply) \ +_(DELETE_LOOPBACK_REPLY, delete_loopback_reply) \ +_(BD_IP_MAC_ADD_DEL_REPLY, bd_ip_mac_add_del_reply) \ +_(DHCP_COMPL_EVENT, dhcp_compl_event) \ +_(VNET_INTERFACE_COUNTERS, vnet_interface_counters) \ +_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \ +_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \ +_(MAP_ADD_DOMAIN_REPLY, map_add_domain_reply) \ +_(MAP_DEL_DOMAIN_REPLY, map_del_domain_reply) \ +_(MAP_ADD_DEL_RULE_REPLY, map_add_del_rule_reply) \ +_(MAP_DOMAIN_DETAILS, map_domain_details) \ +_(MAP_RULE_DETAILS, map_rule_details) \ +_(WANT_INTERFACE_EVENTS_REPLY, want_interface_events_reply) \ +_(WANT_STATS_REPLY, want_stats_reply) \ +_(GET_FIRST_MSG_ID_REPLY, get_first_msg_id_reply) \ +_(COP_INTERFACE_ENABLE_DISABLE_REPLY, cop_interface_enable_disable_reply) \ +_(COP_WHITELIST_ENABLE_DISABLE_REPLY, cop_whitelist_enable_disable_reply) \ +_(GET_NODE_GRAPH_REPLY, get_node_graph_reply) \ +_(SW_INTERFACE_CLEAR_STATS_REPLY, sw_interface_clear_stats_reply) \ +_(IOAM_ENABLE_REPLY, ioam_enable_reply) \ +_(IOAM_DISABLE_REPLY, ioam_disable_reply) \ +_(LISP_ADD_DEL_LOCATOR_SET_REPLY, lisp_add_del_locator_set_reply) \ +_(LISP_ADD_DEL_LOCATOR_REPLY, lisp_add_del_locator_reply) \ +_(LISP_ADD_DEL_LOCAL_EID_REPLY, lisp_add_del_local_eid_reply) \ +_(LISP_ADD_DEL_REMOTE_MAPPING_REPLY, lisp_add_del_remote_mapping_reply) \ +_(LISP_ADD_DEL_ADJACENCY_REPLY, lisp_add_del_adjacency_reply) \ +_(LISP_GPE_ADD_DEL_FWD_ENTRY_REPLY, lisp_gpe_add_del_fwd_entry_reply) \ +_(LISP_ADD_DEL_MAP_RESOLVER_REPLY, lisp_add_del_map_resolver_reply) \ +_(LISP_ADD_DEL_MAP_SERVER_REPLY, lisp_add_del_map_server_reply) \ +_(LISP_GPE_ENABLE_DISABLE_REPLY, lisp_gpe_enable_disable_reply) \ +_(LISP_ENABLE_DISABLE_REPLY, lisp_enable_disable_reply) \ +_(LISP_MAP_REGISTER_ENABLE_DISABLE_REPLY, \ + lisp_map_register_enable_disable_reply) \ +_(LISP_RLOC_PROBE_ENABLE_DISABLE_REPLY, \ + lisp_rloc_probe_enable_disable_reply) \ +_(LISP_PITR_SET_LOCATOR_SET_REPLY, lisp_pitr_set_locator_set_reply) \ +_(LISP_MAP_REQUEST_MODE_REPLY, lisp_map_request_mode_reply) \ +_(LISP_EID_TABLE_ADD_DEL_MAP_REPLY, lisp_eid_table_add_del_map_reply) \ +_(LISP_GPE_ADD_DEL_IFACE_REPLY, lisp_gpe_add_del_iface_reply) \ +_(LISP_LOCATOR_SET_DETAILS, lisp_locator_set_details) \ +_(LISP_LOCATOR_DETAILS, lisp_locator_details) \ +_(LISP_EID_TABLE_DETAILS, lisp_eid_table_details) \ +_(LISP_EID_TABLE_MAP_DETAILS, lisp_eid_table_map_details) \ +_(LISP_EID_TABLE_VNI_DETAILS, lisp_eid_table_vni_details) \ +_(LISP_GPE_TUNNEL_DETAILS, lisp_gpe_tunnel_details) \ +_(LISP_MAP_RESOLVER_DETAILS, lisp_map_resolver_details) \ +_(LISP_MAP_SERVER_DETAILS, lisp_map_server_details) \ +_(LISP_ADJACENCIES_GET_REPLY, lisp_adjacencies_get_reply) \ +_(SHOW_LISP_STATUS_REPLY, show_lisp_status_reply) \ +_(LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS_REPLY, \ + lisp_add_del_map_request_itr_rlocs_reply) \ +_(LISP_GET_MAP_REQUEST_ITR_RLOCS_REPLY, \ + lisp_get_map_request_itr_rlocs_reply) \ +_(SHOW_LISP_PITR_REPLY, show_lisp_pitr_reply) \ +_(SHOW_LISP_MAP_REQUEST_MODE_REPLY, show_lisp_map_request_mode_reply) \ +_(SHOW_LISP_RLOC_PROBE_STATE_REPLY, show_lisp_rloc_probe_state_reply) \ +_(SHOW_LISP_MAP_REGISTER_STATE_REPLY, \ + show_lisp_map_register_state_reply) \ +_(AF_PACKET_CREATE_REPLY, af_packet_create_reply) \ +_(AF_PACKET_DELETE_REPLY, af_packet_delete_reply) \ +_(POLICER_ADD_DEL_REPLY, policer_add_del_reply) \ +_(POLICER_DETAILS, policer_details) \ +_(POLICER_CLASSIFY_SET_INTERFACE_REPLY, policer_classify_set_interface_reply) \ +_(POLICER_CLASSIFY_DETAILS, policer_classify_details) \ +_(NETMAP_CREATE_REPLY, netmap_create_reply) \ +_(NETMAP_DELETE_REPLY, netmap_delete_reply) \ +_(MPLS_TUNNEL_DETAILS, mpls_tunnel_details) \ +_(MPLS_FIB_DETAILS, mpls_fib_details) \ +_(CLASSIFY_TABLE_IDS_REPLY, classify_table_ids_reply) \ +_(CLASSIFY_TABLE_BY_INTERFACE_REPLY, classify_table_by_interface_reply) \ +_(CLASSIFY_TABLE_INFO_REPLY, classify_table_info_reply) \ +_(CLASSIFY_SESSION_DETAILS, classify_session_details) \ +_(SET_IPFIX_EXPORTER_REPLY, set_ipfix_exporter_reply) \ +_(IPFIX_EXPORTER_DETAILS, ipfix_exporter_details) \ +_(SET_IPFIX_CLASSIFY_STREAM_REPLY, set_ipfix_classify_stream_reply) \ +_(IPFIX_CLASSIFY_STREAM_DETAILS, ipfix_classify_stream_details) \ +_(IPFIX_CLASSIFY_TABLE_ADD_DEL_REPLY, ipfix_classify_table_add_del_reply) \ +_(IPFIX_CLASSIFY_TABLE_DETAILS, ipfix_classify_table_details) \ +_(FLOW_CLASSIFY_SET_INTERFACE_REPLY, flow_classify_set_interface_reply) \ +_(FLOW_CLASSIFY_DETAILS, flow_classify_details) \ +_(SW_INTERFACE_SPAN_ENABLE_DISABLE_REPLY, sw_interface_span_enable_disable_reply) \ +_(SW_INTERFACE_SPAN_DETAILS, sw_interface_span_details) \ +_(GET_NEXT_INDEX_REPLY, get_next_index_reply) \ +_(PG_CREATE_INTERFACE_REPLY, pg_create_interface_reply) \ +_(PG_CAPTURE_REPLY, pg_capture_reply) \ +_(PG_ENABLE_DISABLE_REPLY, pg_enable_disable_reply) \ +_(IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL_REPLY, \ + ip_source_and_port_range_check_add_del_reply) \ +_(IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL_REPLY, \ + ip_source_and_port_range_check_interface_add_del_reply) \ +_(IPSEC_GRE_ADD_DEL_TUNNEL_REPLY, ipsec_gre_add_del_tunnel_reply) \ +_(IPSEC_GRE_TUNNEL_DETAILS, ipsec_gre_tunnel_details) \ +_(DELETE_SUBIF_REPLY, delete_subif_reply) \ +_(L2_INTERFACE_PBB_TAG_REWRITE_REPLY, l2_interface_pbb_tag_rewrite_reply) \ +_(PUNT_REPLY, punt_reply) \ +_(IP_FIB_DETAILS, ip_fib_details) \ +_(IP6_FIB_DETAILS, ip6_fib_details) \ +_(FEATURE_ENABLE_DISABLE_REPLY, feature_enable_disable_reply) \ +_(SW_INTERFACE_TAG_ADD_DEL_REPLY, sw_interface_tag_add_del_reply) \ +_(L2_XCONNECT_DETAILS, l2_xconnect_details) \ +_(SW_INTERFACE_SET_MTU_REPLY, sw_interface_set_mtu_reply) \ +_(IP_NEIGHBOR_DETAILS, ip_neighbor_details) \ +_(SW_INTERFACE_GET_TABLE_REPLY, sw_interface_get_table_reply) + +/* M: construct, but don't yet send a message */ + +#define M(T,t) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T); \ + mp->client_index = vam->my_client_index; \ +} while(0); + +#define M2(T,t,n) \ +do { \ + vam->result_ready = 0; \ + mp = vl_msg_api_alloc_as_if_client(sizeof(*mp)+(n)); \ + memset (mp, 0, sizeof (*mp)); \ + mp->_vl_msg_id = ntohs (VL_API_##T); \ + mp->client_index = vam->my_client_index; \ +} while(0); + + +/* S: send a message */ +#define S (vl_msg_api_send_shmem (vam->vl_input_queue, (u8 *)&mp)) + +/* W: wait for results, with timeout */ +#define W \ +do { \ + timeout = vat_time_now (vam) + 1.0; \ + \ + while (vat_time_now (vam) < timeout) { \ + if (vam->result_ready == 1) { \ + return (vam->retval); \ + } \ + vat_suspend (vam->vlib_main, 1e-3); \ + } \ + return -99; \ +} while(0); + +/* W2: wait for results, with timeout */ +#define W2(body) \ +do { \ + timeout = vat_time_now (vam) + 1.0; \ + \ + while (vat_time_now (vam) < timeout) { \ + if (vam->result_ready == 1) { \ + (body); \ + return (vam->retval); \ + } \ + vat_suspend (vam->vlib_main, 1e-3); \ + } \ + return -99; \ +} while(0); + +typedef struct +{ + u8 *name; + u32 value; +} name_sort_t; + + +#define STR_VTR_OP_CASE(op) \ + case L2_VTR_ ## op: \ + return "" # op; + +static const char * +str_vtr_op (u32 vtr_op) +{ + switch (vtr_op) + { + STR_VTR_OP_CASE (DISABLED); + STR_VTR_OP_CASE (PUSH_1); + STR_VTR_OP_CASE (PUSH_2); + STR_VTR_OP_CASE (POP_1); + STR_VTR_OP_CASE (POP_2); + STR_VTR_OP_CASE (TRANSLATE_1_1); + STR_VTR_OP_CASE (TRANSLATE_1_2); + STR_VTR_OP_CASE (TRANSLATE_2_1); + STR_VTR_OP_CASE (TRANSLATE_2_2); + } + + return "UNKNOWN"; +} + +static int +dump_sub_interface_table (vat_main_t * vam) +{ + const sw_interface_subif_t *sub = NULL; + + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + print (vam->ofp, + "%-30s%-12s%-11s%-7s%-5s%-9s%-9s%-6s%-8s%-10s%-10s", + "Interface", "sw_if_index", + "sub id", "dot1ad", "tags", "outer id", + "inner id", "exact", "default", "outer any", "inner any"); + + vec_foreach (sub, vam->sw_if_subif_table) + { + print (vam->ofp, + "%-30s%-12d%-11d%-7s%-5d%-9d%-9d%-6d%-8d%-10d%-10d", + sub->interface_name, + sub->sw_if_index, + sub->sub_id, sub->sub_dot1ad ? "dot1ad" : "dot1q", + sub->sub_number_of_tags, sub->sub_outer_vlan_id, + sub->sub_inner_vlan_id, sub->sub_exact_match, sub->sub_default, + sub->sub_outer_vlan_id_any, sub->sub_inner_vlan_id_any); + if (sub->vtr_op != L2_VTR_DISABLED) + { + print (vam->ofp, + " vlan-tag-rewrite - op: %-14s [ dot1q: %d " + "tag1: %d tag2: %d ]", + str_vtr_op (sub->vtr_op), sub->vtr_push_dot1q, + sub->vtr_tag1, sub->vtr_tag2); + } + } + + return 0; +} + +static int +name_sort_cmp (void *a1, void *a2) +{ + name_sort_t *n1 = a1; + name_sort_t *n2 = a2; + + return strcmp ((char *) n1->name, (char *) n2->name); +} + +static int +dump_interface_table (vat_main_t * vam) +{ + hash_pair_t *p; + name_sort_t *nses = 0, *ns; + + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(p->key); + ns->value = (u32) p->value[0]; + })); + /* *INDENT-ON* */ + + vec_sort_with_function (nses, name_sort_cmp); + + print (vam->ofp, "%-25s%-15s", "Interface", "sw_if_index"); + vec_foreach (ns, nses) + { + print (vam->ofp, "%-25s%-15d", ns->name, ns->value); + } + vec_free (nses); + return 0; +} + +static int +dump_ip_table (vat_main_t * vam, int is_ipv6) +{ + const ip_details_t *det = NULL; + const ip_address_details_t *address = NULL; + u32 i = ~0; + + print (vam->ofp, "%-12s", "sw_if_index"); + + vec_foreach (det, vam->ip_details_by_sw_if_index[is_ipv6]) + { + i++; + if (!det->present) + { + continue; + } + print (vam->ofp, "%-12d", i); + print (vam->ofp, " %-30s%-13s", "Address", "Prefix length"); + if (!det->addr) + { + continue; + } + vec_foreach (address, det->addr) + { + print (vam->ofp, + " %-30U%-13d", + is_ipv6 ? format_ip6_address : format_ip4_address, + address->ip, address->prefix_length); + } + } + + return 0; +} + +static int +dump_ipv4_table (vat_main_t * vam) +{ + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + return dump_ip_table (vam, 0); +} + +static int +dump_ipv6_table (vat_main_t * vam) +{ + if (vam->json_output) + { + clib_warning + ("JSON output supported only for VPE API calls and dump_stats_table"); + return -99; + } + + return dump_ip_table (vam, 1); +} + +static char * +counter_type_to_str (u8 counter_type, u8 is_combined) +{ + if (!is_combined) + { + switch (counter_type) + { + case VNET_INTERFACE_COUNTER_DROP: + return "drop"; + case VNET_INTERFACE_COUNTER_PUNT: + return "punt"; + case VNET_INTERFACE_COUNTER_IP4: + return "ip4"; + case VNET_INTERFACE_COUNTER_IP6: + return "ip6"; + case VNET_INTERFACE_COUNTER_RX_NO_BUF: + return "rx-no-buf"; + case VNET_INTERFACE_COUNTER_RX_MISS: + return "rx-miss"; + case VNET_INTERFACE_COUNTER_RX_ERROR: + return "rx-error"; + case VNET_INTERFACE_COUNTER_TX_ERROR: + return "tx-error"; + default: + return "INVALID-COUNTER-TYPE"; + } + } + else + { + switch (counter_type) + { + case VNET_INTERFACE_COUNTER_RX: + return "rx"; + case VNET_INTERFACE_COUNTER_TX: + return "tx"; + default: + return "INVALID-COUNTER-TYPE"; + } + } +} + +static int +dump_stats_table (vat_main_t * vam) +{ + vat_json_node_t node; + vat_json_node_t *msg_array; + vat_json_node_t *msg; + vat_json_node_t *counter_array; + vat_json_node_t *counter; + interface_counter_t c; + u64 packets; + ip4_fib_counter_t *c4; + ip6_fib_counter_t *c6; + int i, j; + + if (!vam->json_output) + { + clib_warning ("dump_stats_table supported only in JSON format"); + return -99; + } + + vat_json_init_object (&node); + + /* interface counters */ + msg_array = vat_json_object_add (&node, "interface_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->simple_interface_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_string_copy (msg, "vnet_counter_type", + (u8 *) counter_type_to_str (i, 0)); + vat_json_object_add_int (msg, "is_combined", 0); + counter_array = vat_json_object_add (msg, "data"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->simple_interface_counters[i]); j++) + { + packets = vam->simple_interface_counters[i][j]; + vat_json_array_add_uint (counter_array, packets); + } + } + for (i = 0; i < vec_len (vam->combined_interface_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_string_copy (msg, "vnet_counter_type", + (u8 *) counter_type_to_str (i, 1)); + vat_json_object_add_int (msg, "is_combined", 1); + counter_array = vat_json_object_add (msg, "data"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->combined_interface_counters[i]); j++) + { + c = vam->combined_interface_counters[i][j]; + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + vat_json_object_add_uint (counter, "packets", c.packets); + vat_json_object_add_uint (counter, "bytes", c.bytes); + } + } + + /* ip4 fib counters */ + msg_array = vat_json_object_add (&node, "ip4_fib_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->ip4_fib_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_uint (msg, "vrf_id", + vam->ip4_fib_counters_vrf_id_by_index[i]); + counter_array = vat_json_object_add (msg, "c"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->ip4_fib_counters[i]); j++) + { + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + c4 = &vam->ip4_fib_counters[i][j]; + vat_json_object_add_ip4 (counter, "address", c4->address); + vat_json_object_add_uint (counter, "address_length", + c4->address_length); + vat_json_object_add_uint (counter, "packets", c4->packets); + vat_json_object_add_uint (counter, "bytes", c4->bytes); + } + } + + /* ip6 fib counters */ + msg_array = vat_json_object_add (&node, "ip6_fib_counters"); + vat_json_init_array (msg_array); + for (i = 0; i < vec_len (vam->ip6_fib_counters); i++) + { + msg = vat_json_array_add (msg_array); + vat_json_init_object (msg); + vat_json_object_add_uint (msg, "vrf_id", + vam->ip6_fib_counters_vrf_id_by_index[i]); + counter_array = vat_json_object_add (msg, "c"); + vat_json_init_array (counter_array); + for (j = 0; j < vec_len (vam->ip6_fib_counters[i]); j++) + { + counter = vat_json_array_add (counter_array); + vat_json_init_object (counter); + c6 = &vam->ip6_fib_counters[i][j]; + vat_json_object_add_ip6 (counter, "address", c6->address); + vat_json_object_add_uint (counter, "address_length", + c6->address_length); + vat_json_object_add_uint (counter, "packets", c6->packets); + vat_json_object_add_uint (counter, "bytes", c6->bytes); + } + } + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + return 0; +} + +int +exec (vat_main_t * vam) +{ + api_main_t *am = &api_main; + vl_api_cli_request_t *mp; + f64 timeout; + void *oldheap; + u8 *cmd = 0; + unformat_input_t *i = vam->input; + + if (vec_len (i->buffer) == 0) + return -1; + + if (vam->exec_mode == 0 && unformat (i, "mode")) + { + vam->exec_mode = 1; + return 0; + } + if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) + { + vam->exec_mode = 0; + return 0; + } + + + M (CLI_REQUEST, cli_request); + + /* + * Copy cmd into shared memory. + * In order for the CLI command to work, it + * must be a vector ending in \n, not a C-string ending + * in \n\0. + */ + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + vec_validate (cmd, vec_len (vam->input->buffer) - 1); + clib_memcpy (cmd, vam->input->buffer, vec_len (vam->input->buffer)); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + + mp->cmd_in_shmem = (u64) cmd; + S; + timeout = vat_time_now (vam) + 10.0; + + while (vat_time_now (vam) < timeout) + { + if (vam->result_ready == 1) + { + u8 *free_me; + if (vam->shmem_result != NULL) + print (vam->ofp, "%s", vam->shmem_result); + pthread_mutex_lock (&am->vlib_rp->mutex); + oldheap = svm_push_data_heap (am->vlib_rp); + + free_me = (u8 *) vam->shmem_result; + vec_free (free_me); + + svm_pop_heap (oldheap); + pthread_mutex_unlock (&am->vlib_rp->mutex); + return 0; + } + } + return -99; +} + +/* + * Future replacement of exec() that passes CLI buffers directly in + * the API messages instead of an additional shared memory area. + */ +static int +exec_inband (vat_main_t * vam) +{ + vl_api_cli_inband_t *mp; + f64 timeout; + unformat_input_t *i = vam->input; + + if (vec_len (i->buffer) == 0) + return -1; + + if (vam->exec_mode == 0 && unformat (i, "mode")) + { + vam->exec_mode = 1; + return 0; + } + if (vam->exec_mode == 1 && (unformat (i, "exit") || unformat (i, "quit"))) + { + vam->exec_mode = 0; + return 0; + } + + /* + * In order for the CLI command to work, it + * must be a vector ending in \n, not a C-string ending + * in \n\0. + */ + u32 len = vec_len (vam->input->buffer); + M2 (CLI_INBAND, cli_inband, len); + clib_memcpy (mp->cmd, vam->input->buffer, len); + mp->length = htonl (len); + + S; + W2 (print (vam->ofp, "%s", vam->cmd_reply)); +} + +static int +api_create_loopback (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_loopback_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 mac_set = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + mac_set = 1; + else + break; + } + + /* Construct the API message */ + M (CREATE_LOOPBACK, create_loopback); + if (mac_set) + clib_memcpy (mp->mac_address, mac_address, sizeof (mac_address)); + + S; + W; +} + +static int +api_delete_loopback (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_loopback_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (DELETE_LOOPBACK, delete_loopback); + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; +} + +static int +api_want_stats (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_want_stats_t *mp; + f64 timeout; + int enable = -1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (enable == -1) + { + errmsg ("missing enable|disable"); + return -99; + } + + M (WANT_STATS, want_stats); + mp->enable_disable = enable; + + S; + W; +} + +static int +api_want_interface_events (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_want_interface_events_t *mp; + f64 timeout; + int enable = -1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (enable == -1) + { + errmsg ("missing enable|disable"); + return -99; + } + + M (WANT_INTERFACE_EVENTS, want_interface_events); + mp->enable_disable = enable; + + vam->interface_event_display = enable; + + S; + W; +} + + +/* Note: non-static, called once to set up the initial intfc table */ +int +api_sw_interface_dump (vat_main_t * vam) +{ + vl_api_sw_interface_dump_t *mp; + f64 timeout; + hash_pair_t *p; + name_sort_t *nses = 0, *ns; + sw_interface_subif_t *sub = NULL; + + /* Toss the old name table */ + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(p->key); + ns->value = (u32) p->value[0]; + })); + /* *INDENT-ON* */ + + hash_free (vam->sw_if_index_by_interface_name); + + vec_foreach (ns, nses) vec_free (ns->name); + + vec_free (nses); + + vec_foreach (sub, vam->sw_if_subif_table) + { + vec_free (sub->interface_name); + } + vec_free (vam->sw_if_subif_table); + + /* recreate the interface name hash table */ + vam->sw_if_index_by_interface_name = hash_create_string (0, sizeof (uword)); + + /* Get list of ethernets */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "Ether", sizeof (mp->name_filter) - 1); + S; + + /* and local / loopback interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "lo", sizeof (mp->name_filter) - 1); + S; + + /* and packet-generator interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "pg", sizeof (mp->name_filter) - 1); + S; + + /* and vxlan-gpe tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "vxlan_gpe", + sizeof (mp->name_filter) - 1); + S; + + /* and vxlan tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "vxlan", sizeof (mp->name_filter) - 1); + S; + + /* and host (af_packet) interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "host", sizeof (mp->name_filter) - 1); + S; + + /* and l2tpv3 tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "l2tpv3_tunnel", + sizeof (mp->name_filter) - 1); + S; + + /* and GRE tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "gre", sizeof (mp->name_filter) - 1); + S; + + /* and LISP-GPE interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "lisp_gpe", + sizeof (mp->name_filter) - 1); + S; + + /* and IPSEC tunnel interfaces */ + M (SW_INTERFACE_DUMP, sw_interface_dump); + mp->name_filter_valid = 1; + strncpy ((char *) mp->name_filter, "ipsec", sizeof (mp->name_filter) - 1); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_sw_interface_set_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_flags_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 admin_up = 0, link_up = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "admin-up")) + admin_up = 1; + else if (unformat (i, "admin-down")) + admin_up = 0; + else if (unformat (i, "link-up")) + link_up = 1; + else if (unformat (i, "link-down")) + link_up = 0; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_FLAGS, sw_interface_set_flags); + mp->sw_if_index = ntohl (sw_if_index); + mp->admin_up_down = admin_up; + mp->link_up_down = link_up; + + /* send it... */ + S; + + /* Wait for a reply, return the good/bad news... */ + W; +} + +static int +api_sw_interface_clear_stats (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_clear_stats_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + /* Construct the API message */ + M (SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats); + + if (sw_if_index_set == 1) + mp->sw_if_index = ntohl (sw_if_index); + else + mp->sw_if_index = ~0; + + /* send it... */ + S; + + /* Wait for a reply, return the good/bad news... */ + W; +} + +static int +api_sw_interface_set_dpdk_hqos_pipe (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_pipe_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 pipe; + u8 pipe_set = 0; + u32 profile; + u8 profile_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "pipe %u", &pipe)) + pipe_set = 1; + else if (unformat (i, "profile %u", &profile)) + profile_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + if (pipe_set == 0) + { + errmsg ("missing pipe"); + return -99; + } + + if (profile_set == 0) + { + errmsg ("missing profile"); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_PIPE, sw_interface_set_dpdk_hqos_pipe); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->pipe = ntohl (pipe); + mp->profile = ntohl (profile); + + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_subport (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_subport_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 subport; + u8 subport_set = 0; + u32 tb_rate = 1250000000; /* 10GbE */ + u32 tb_size = 1000000; + u32 tc_rate[] = { 1250000000, 1250000000, 1250000000, 1250000000 }; + u32 tc_period = 10; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "subport %u", &subport)) + subport_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "rate %u", &tb_rate)) + { + u32 tc_id; + + for (tc_id = 0; tc_id < (sizeof (tc_rate) / sizeof (tc_rate[0])); + tc_id++) + tc_rate[tc_id] = tb_rate; + } + else if (unformat (i, "bktsize %u", &tb_size)) + ; + else if (unformat (i, "tc0 %u", &tc_rate[0])) + ; + else if (unformat (i, "tc1 %u", &tc_rate[1])) + ; + else if (unformat (i, "tc2 %u", &tc_rate[2])) + ; + else if (unformat (i, "tc3 %u", &tc_rate[3])) + ; + else if (unformat (i, "period %u", &tc_period)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (subport_set == 0) + { + errmsg ("missing subport "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_SUBPORT, sw_interface_set_dpdk_hqos_subport); + + mp->sw_if_index = ntohl (sw_if_index); + mp->subport = ntohl (subport); + mp->tb_rate = ntohl (tb_rate); + mp->tb_size = ntohl (tb_size); + mp->tc_rate[0] = ntohl (tc_rate[0]); + mp->tc_rate[1] = ntohl (tc_rate[1]); + mp->tc_rate[2] = ntohl (tc_rate[2]); + mp->tc_rate[3] = ntohl (tc_rate[3]); + mp->tc_period = ntohl (tc_period); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_dpdk_hqos_tctbl (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_dpdk_hqos_tctbl_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 entry_set = 0; + u8 tc_set = 0; + u8 queue_set = 0; + u32 entry, tc, queue; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx %U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %u", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "entry %d", &entry)) + entry_set = 1; + else if (unformat (i, "tc %d", &tc)) + tc_set = 1; + else if (unformat (i, "queue %d", &queue)) + queue_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (entry_set == 0) + { + errmsg ("missing entry "); + return -99; + } + + if (tc_set == 0) + { + errmsg ("missing traffic class "); + return -99; + } + + if (queue_set == 0) + { + errmsg ("missing queue "); + return -99; + } + + M (SW_INTERFACE_SET_DPDK_HQOS_TCTBL, sw_interface_set_dpdk_hqos_tctbl); + + mp->sw_if_index = ntohl (sw_if_index); + mp->entry = ntohl (entry); + mp->tc = ntohl (tc); + mp->queue = ntohl (queue); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_add_del_address (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_add_del_address_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1, del_all = 0; + u32 address_length = 0; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del-all")) + del_all = 1; + else if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "%U/%d", + unformat_ip4_address, &v4address, &address_length)) + v4_address_set = 1; + else if (unformat (i, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set && !del_all) + { + errmsg ("no addresses set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->del_all = del_all; + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + } + else + { + clib_memcpy (mp->address, &v4address, sizeof (v4address)); + } + mp->address_length = address_length; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_sw_interface_set_mpls_enable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_mpls_enable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "disable")) + enable = 0; + else if (unformat (i, "dis")) + enable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_MPLS_ENABLE, sw_interface_set_mpls_enable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_table_t *mp; + f64 timeout; + u32 sw_if_index, vrf_id = 0; + u8 sw_if_index_set = 0; + u8 is_ipv6 = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_TABLE, sw_interface_set_table); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_ipv6 = is_ipv6; + mp->vrf_id = ntohl (vrf_id); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static void vl_api_sw_interface_get_table_reply_t_handler + (vl_api_sw_interface_get_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%d", ntohl (mp->vrf_id)); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; + +} + +static void vl_api_sw_interface_get_table_reply_t_handler_json + (vl_api_sw_interface_get_table_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_int (&node, "vrf_id", ntohl (mp->vrf_id)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static int +api_sw_interface_get_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_get_table_t *mp; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_ipv6 = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_GET_TABLE, sw_interface_get_table); + mp->sw_if_index = htonl (sw_if_index); + mp->is_ipv6 = is_ipv6; + + S; + W; +} + +static int +api_sw_interface_set_vpath (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_vpath_t *mp; + f64 timeout; + u32 sw_if_index = 0; + u8 sw_if_index_set = 0; + u8 is_enable = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + is_enable = 1; + else if (unformat (i, "disable")) + is_enable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_VPATH, sw_interface_set_vpath); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = is_enable; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_vxlan_bypass (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_vxlan_bypass_t *mp; + f64 timeout; + u32 sw_if_index = 0; + u8 sw_if_index_set = 0; + u8 is_enable = 0; + u8 is_ipv6 = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + is_enable = 1; + else if (unformat (i, "disable")) + is_enable = 0; + else if (unformat (i, "ip4")) + is_ipv6 = 0; + else if (unformat (i, "ip6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_VXLAN_BYPASS, sw_interface_set_vxlan_bypass); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = is_enable; + mp->is_ipv6 = is_ipv6; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_sw_interface_set_l2_xconnect (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_l2_xconnect_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 tx_sw_if_index; + u8 tx_sw_if_index_set = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index)) + tx_sw_if_index_set = 1; + else if (unformat (i, "rx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &rx_sw_if_index)) + rx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "tx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &tx_sw_if_index)) + tx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or rx_sw_if_index"); + return -99; + } + + if (enable && (tx_sw_if_index_set == 0)) + { + errmsg ("missing tx interface name or tx_sw_if_index"); + return -99; + } + + M (SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->tx_sw_if_index = ntohl (tx_sw_if_index); + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_l2_bridge (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_l2_bridge_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 bd_id; + u8 bd_id_set = 0; + u8 bvi = 0; + u32 shg = 0; + u8 enable = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "shg %d", &shg)) + ; + else if (unformat (i, "bvi")) + bvi = 1; + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or sw_if_index"); + return -99; + } + + if (enable && (bd_id_set == 0)) + { + errmsg ("missing bridge domain"); + return -99; + } + + M (SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->bd_id = ntohl (bd_id); + mp->shg = (u8) shg; + mp->bvi = bvi; + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_domain_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_dump_t *mp; + f64 timeout; + u32 bd_id = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + ; + else + break; + } + + M (BRIDGE_DOMAIN_DUMP, bridge_domain_dump); + mp->bd_id = ntohl (bd_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_domain_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_domain_add_del_t *mp; + f64 timeout; + u32 bd_id = ~0; + u8 is_add = 1; + u32 flood = 1, forward = 1, learn = 1, uu_flood = 1, arp_term = 0; + u32 mac_age = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + ; + else if (unformat (i, "flood %d", &flood)) + ; + else if (unformat (i, "uu-flood %d", &uu_flood)) + ; + else if (unformat (i, "forward %d", &forward)) + ; + else if (unformat (i, "learn %d", &learn)) + ; + else if (unformat (i, "arp-term %d", &arp_term)) + ; + else if (unformat (i, "mac-age %d", &mac_age)) + ; + else if (unformat (i, "del")) + { + is_add = 0; + flood = uu_flood = forward = learn = 0; + } + else + break; + } + + if (bd_id == ~0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (mac_age > 255) + { + errmsg ("mac age must be less than 256 "); + return -99; + } + + M (BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del); + + mp->bd_id = ntohl (bd_id); + mp->flood = flood; + mp->uu_flood = uu_flood; + mp->forward = forward; + mp->learn = learn; + mp->arp_term = arp_term; + mp->is_add = is_add; + mp->mac_age = (u8) mac_age; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2fib_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2fib_add_del_t *mp; + f64 timeout; + u64 mac = 0; + u8 mac_set = 0; + u32 bd_id; + u8 bd_id_set = 0; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 is_add = 1; + u8 static_mac = 0; + u8 filter_mac = 0; + u8 bvi_mac = 0; + int count = 1; + f64 before = 0; + int j; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, &mac)) + mac_set = 1; + else if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "static")) + static_mac = 1; + else if (unformat (i, "filter")) + { + filter_mac = 1; + static_mac = 1; + } + else if (unformat (i, "bvi")) + { + bvi_mac = 1; + static_mac = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "count %d", &count)) + ; + else + break; + } + + if (mac_set == 0) + { + errmsg ("missing mac address"); + return -99; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + if (is_add && sw_if_index_set == 0 && filter_mac == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + M (L2FIB_ADD_DEL, l2fib_add_del); + + mp->mac = mac; + mp->bd_id = ntohl (bd_id); + mp->is_add = is_add; + + if (is_add) + { + mp->sw_if_index = ntohl (sw_if_index); + mp->static_mac = static_mac; + mp->filter_mac = filter_mac; + mp->bvi_mac = bvi_mac; + } + increment_mac_address (&mac); + /* send it... */ + S; + } + + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_l2_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_flags_t *mp; + f64 timeout; + u32 sw_if_index; + u32 feature_bitmap = 0; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "learn")) + feature_bitmap |= L2INPUT_FEAT_LEARN; + else if (unformat (i, "forward")) + feature_bitmap |= L2INPUT_FEAT_FWD; + else if (unformat (i, "flood")) + feature_bitmap |= L2INPUT_FEAT_FLOOD; + else if (unformat (i, "uu-flood")) + feature_bitmap |= L2INPUT_FEAT_UU_FLOOD; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2_FLAGS, l2_flags); + + mp->sw_if_index = ntohl (sw_if_index); + mp->feature_bitmap = ntohl (feature_bitmap); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bridge_flags (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bridge_flags_t *mp; + f64 timeout; + u32 bd_id; + u8 bd_id_set = 0; + u8 is_set = 1; + u32 flags = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else if (unformat (i, "learn")) + flags |= L2_LEARN; + else if (unformat (i, "forward")) + flags |= L2_FWD; + else if (unformat (i, "flood")) + flags |= L2_FLOOD; + else if (unformat (i, "uu-flood")) + flags |= L2_UU_FLOOD; + else if (unformat (i, "arp-term")) + flags |= L2_ARP_TERM; + else if (unformat (i, "off")) + is_set = 0; + else if (unformat (i, "disable")) + is_set = 0; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + M (BRIDGE_FLAGS, bridge_flags); + + mp->bd_id = ntohl (bd_id); + mp->feature_bitmap = ntohl (flags); + mp->is_set = is_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_bd_ip_mac_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_bd_ip_mac_add_del_t *mp; + f64 timeout; + u32 bd_id; + u8 is_ipv6 = 0; + u8 is_add = 1; + u8 bd_id_set = 0; + u8 ip_set = 0; + u8 mac_set = 0; + ip4_address_t v4addr; + ip6_address_t v6addr; + u8 macaddr[6]; + + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + { + bd_id_set++; + } + else if (unformat (i, "%U", unformat_ip4_address, &v4addr)) + { + ip_set++; + } + else if (unformat (i, "%U", unformat_ip6_address, &v6addr)) + { + ip_set++; + is_ipv6++; + } + else if (unformat (i, "%U", unformat_ethernet_address, macaddr)) + { + mac_set++; + } + else if (unformat (i, "del")) + is_add = 0; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + else if (ip_set == 0) + { + errmsg ("missing IP address"); + return -99; + } + else if (mac_set == 0) + { + errmsg ("missing MAC address"); + return -99; + } + + M (BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del); + + mp->bd_id = ntohl (bd_id); + mp->is_ipv6 = is_ipv6; + mp->is_add = is_add; + if (is_ipv6) + clib_memcpy (mp->ip_address, &v6addr, sizeof (v6addr)); + else + clib_memcpy (mp->ip_address, &v4addr, sizeof (v4addr)); + clib_memcpy (mp->mac_address, macaddr, 6); + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_tap_connect (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_connect_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 random_mac = 1; + u8 name_set = 0; + u8 *tap_name; + u8 *tag = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + { + random_mac = 0; + } + else if (unformat (i, "random-mac")) + random_mac = 1; + else if (unformat (i, "tapname %s", &tap_name)) + name_set = 1; + else if (unformat (i, "tag %s", &tag)) + ; + else + break; + } + + if (name_set == 0) + { + errmsg ("missing tap name"); + return -99; + } + if (vec_len (tap_name) > 63) + { + errmsg ("tap name too long"); + return -99; + } + vec_add1 (tap_name, 0); + + if (vec_len (tag) > 63) + { + errmsg ("tag too long"); + return -99; + } + + /* Construct the API message */ + M (TAP_CONNECT, tap_connect); + + mp->use_random_mac = random_mac; + clib_memcpy (mp->mac_address, mac_address, 6); + clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name)); + if (tag) + clib_memcpy (mp->tag, tag, vec_len (tag)); + + vec_free (tap_name); + vec_free (tag); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_tap_modify (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_modify_t *mp; + f64 timeout; + u8 mac_address[6]; + u8 random_mac = 1; + u8 name_set = 0; + u8 *tap_name; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + { + random_mac = 0; + } + else if (unformat (i, "random-mac")) + random_mac = 1; + else if (unformat (i, "tapname %s", &tap_name)) + name_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing vpp interface name"); + return -99; + } + if (name_set == 0) + { + errmsg ("missing tap name"); + return -99; + } + if (vec_len (tap_name) > 63) + { + errmsg ("tap name too long"); + } + vec_add1 (tap_name, 0); + + /* Construct the API message */ + M (TAP_MODIFY, tap_modify); + + mp->use_random_mac = random_mac; + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->mac_address, mac_address, 6); + clib_memcpy (mp->tap_name, tap_name, vec_len (tap_name)); + vec_free (tap_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_tap_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_tap_delete_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing vpp interface name"); + return -99; + } + + /* Construct the API message */ + M (TAP_DELETE, tap_delete); + + mp->sw_if_index = ntohl (sw_if_index); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_ip_add_del_route (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_add_del_route_t *mp; + f64 timeout; + u32 sw_if_index = ~0, vrf_id = 0; + u8 is_ipv6 = 0; + u8 is_local = 0, is_drop = 0; + u8 is_unreach = 0, is_prohibit = 0; + u8 create_vrf_if_needed = 0; + u8 is_add = 1; + u32 next_hop_weight = 1; + u8 not_last = 0; + u8 is_multipath = 0; + u8 address_set = 0; + u8 address_length_set = 0; + u32 next_hop_table_id = 0; + u32 resolve_attempts = 0; + u32 dst_address_length = 0; + u8 next_hop_set = 0; + ip4_address_t v4_dst_address, v4_next_hop_address; + ip6_address_t v6_dst_address, v6_next_hop_address; + int count = 1; + int j; + f64 before = 0; + u32 random_add_del = 0; + u32 *random_vector = 0; + uword *random_hash; + u32 random_seed = 0xdeaddabe; + u32 classify_table_index = ~0; + u8 is_classify = 0; + u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t *next_hop_out_label_stack = NULL; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; + mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%U", unformat_ip4_address, &v4_dst_address)) + { + address_set = 1; + is_ipv6 = 0; + } + else if (unformat (i, "%U", unformat_ip6_address, &v6_dst_address)) + { + address_set = 1; + is_ipv6 = 1; + } + else if (unformat (i, "/%d", &dst_address_length)) + { + address_length_set = 1; + } + + else if (is_ipv6 == 0 && unformat (i, "via %U", unformat_ip4_address, + &v4_next_hop_address)) + { + next_hop_set = 1; + } + else if (is_ipv6 == 1 && unformat (i, "via %U", unformat_ip6_address, + &v6_next_hop_address)) + { + next_hop_set = 1; + } + else if (unformat (i, "resolve-attempts %d", &resolve_attempts)) + ; + else if (unformat (i, "weight %d", &next_hop_weight)) + ; + else if (unformat (i, "drop")) + { + is_drop = 1; + } + else if (unformat (i, "null-send-unreach")) + { + is_unreach = 1; + } + else if (unformat (i, "null-send-prohibit")) + { + is_prohibit = 1; + } + else if (unformat (i, "local")) + { + is_local = 1; + } + else if (unformat (i, "classify %d", &classify_table_index)) + { + is_classify = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "not-last")) + not_last = 1; + else if (unformat (i, "resolve-via-host")) + resolve_host = 1; + else if (unformat (i, "resolve-via-attached")) + resolve_attached = 1; + else if (unformat (i, "multipath")) + is_multipath = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "create-vrf")) + create_vrf_if_needed = 1; + else if (unformat (i, "count %d", &count)) + ; + else if (unformat (i, "lookup-in-vrf %d", &next_hop_table_id)) + ; + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (next_hop_out_label_stack, ntohl (next_hop_out_label)); + else if (unformat (i, "via-label %d", &next_hop_via_label)) + ; + else if (unformat (i, "random")) + random_add_del = 1; + else if (unformat (i, "seed %d", &random_seed)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!next_hop_set && !is_drop && !is_local && + !is_classify && !is_unreach && !is_prohibit && + MPLS_LABEL_INVALID == next_hop_via_label) + { + errmsg + ("next hop / local / drop / unreach / prohibit / classify not set"); + return -99; + } + + if (next_hop_set && MPLS_LABEL_INVALID != next_hop_via_label) + { + errmsg ("next hop and next-hop via label set"); + return -99; + } + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + if (address_length_set == 0) + { + errmsg ("missing address length"); + return -99; + } + + /* Generate a pile of unique, random routes */ + if (random_add_del) + { + u32 this_random_address; + random_hash = hash_create (count, sizeof (uword)); + + hash_set (random_hash, v4_next_hop_address.as_u32, 1); + for (j = 0; j <= count; j++) + { + do + { + this_random_address = random_u32 (&random_seed); + this_random_address = + clib_host_to_net_u32 (this_random_address); + } + while (hash_get (random_hash, this_random_address)); + vec_add1 (random_vector, this_random_address); + hash_set (random_hash, this_random_address, 1); + } + hash_free (random_hash); + v4_dst_address.as_u32 = random_vector[0]; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + /* Construct the API message */ + M2 (IP_ADD_DEL_ROUTE, ip_add_del_route, + sizeof (mpls_label_t) * vec_len (next_hop_out_label_stack)); + + mp->next_hop_sw_if_index = ntohl (sw_if_index); + mp->table_id = ntohl (vrf_id); + mp->create_vrf_if_needed = create_vrf_if_needed; + + mp->is_add = is_add; + mp->is_drop = is_drop; + mp->is_unreach = is_unreach; + mp->is_prohibit = is_prohibit; + mp->is_ipv6 = is_ipv6; + mp->is_local = is_local; + mp->is_classify = is_classify; + mp->is_multipath = is_multipath; + mp->is_resolve_host = resolve_host; + mp->is_resolve_attached = resolve_attached; + mp->not_last = not_last; + mp->next_hop_weight = next_hop_weight; + mp->dst_address_length = dst_address_length; + mp->next_hop_table_id = ntohl (next_hop_table_id); + mp->classify_table_index = ntohl (classify_table_index); + mp->next_hop_via_label = ntohl (next_hop_via_label); + mp->next_hop_n_out_labels = vec_len (next_hop_out_label_stack); + if (0 != mp->next_hop_n_out_labels) + { + memcpy (mp->next_hop_out_label_stack, + next_hop_out_label_stack, + vec_len (next_hop_out_label_stack) * sizeof (mpls_label_t)); + vec_free (next_hop_out_label_stack); + } + + if (is_ipv6) + { + clib_memcpy (mp->dst_address, &v6_dst_address, + sizeof (v6_dst_address)); + if (next_hop_set) + clib_memcpy (mp->next_hop_address, &v6_next_hop_address, + sizeof (v6_next_hop_address)); + increment_v6_address (&v6_dst_address); + } + else + { + clib_memcpy (mp->dst_address, &v4_dst_address, + sizeof (v4_dst_address)); + if (next_hop_set) + clib_memcpy (mp->next_hop_address, &v4_next_hop_address, + sizeof (v4_next_hop_address)); + if (random_add_del) + v4_dst_address.as_u32 = random_vector[j + 1]; + else + increment_v4_address (&v4_dst_address); + } + /* send it... */ + S; + /* If we receive SIGTERM, stop now... */ + if (vam->do_exit) + break; + } + + /* When testing multiple add/del ops, use a control-ping to sync */ + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + /* slim chance, but we might have eaten SIGTERM on the first iteration */ + if (j > 0) + count = j; + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_mpls_route_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_route_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0, table_id = 0; + u8 create_table_if_needed = 0; + u8 is_add = 1; + u32 next_hop_weight = 1; + u8 is_multipath = 0; + u32 next_hop_table_id = 0; + u8 next_hop_set = 0; + ip4_address_t v4_next_hop_address = { + .as_u32 = 0, + }; + ip6_address_t v6_next_hop_address = { {0} }; + int count = 1; + int j; + f64 before = 0; + u32 classify_table_index = ~0; + u8 is_classify = 0; + u8 resolve_host = 0, resolve_attached = 0; + mpls_label_t next_hop_via_label = MPLS_LABEL_INVALID; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID; + mpls_label_t *next_hop_out_label_stack = NULL; + mpls_label_t local_label = MPLS_LABEL_INVALID; + u8 is_eos = 0; + u8 next_hop_proto_is_ip4 = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "eos")) + is_eos = 1; + else if (unformat (i, "non-eos")) + is_eos = 0; + else if (unformat (i, "via %U", unformat_ip4_address, + &v4_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "via %U", unformat_ip6_address, + &v6_next_hop_address)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "weight %d", &next_hop_weight)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "classify %d", &classify_table_index)) + { + is_classify = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "resolve-via-host")) + resolve_host = 1; + else if (unformat (i, "resolve-via-attached")) + resolve_attached = 1; + else if (unformat (i, "multipath")) + is_multipath = 1; + else if (unformat (i, "count %d", &count)) + ; + else if (unformat (i, "lookup-in-ip4-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "lookup-in-ip6-table %d", &next_hop_table_id)) + { + next_hop_set = 1; + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "via-label %d", &next_hop_via_label)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (next_hop_out_label_stack, ntohl (next_hop_out_label)); + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!next_hop_set && !is_classify) + { + errmsg ("next hop / classify not set"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label"); + return -99; + } + + if (count > 1) + { + /* Turn on async mode */ + vam->async_mode = 1; + vam->async_errors = 0; + before = vat_time_now (vam); + } + + for (j = 0; j < count; j++) + { + /* Construct the API message */ + M2 (MPLS_ROUTE_ADD_DEL, mpls_route_add_del, + sizeof (mpls_label_t) * vec_len (next_hop_out_label_stack)); + + mp->mr_next_hop_sw_if_index = ntohl (sw_if_index); + mp->mr_table_id = ntohl (table_id); + mp->mr_create_table_if_needed = create_table_if_needed; + + mp->mr_is_add = is_add; + mp->mr_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + mp->mr_is_classify = is_classify; + mp->mr_is_multipath = is_multipath; + mp->mr_is_resolve_host = resolve_host; + mp->mr_is_resolve_attached = resolve_attached; + mp->mr_next_hop_weight = next_hop_weight; + mp->mr_next_hop_table_id = ntohl (next_hop_table_id); + mp->mr_classify_table_index = ntohl (classify_table_index); + mp->mr_next_hop_via_label = ntohl (next_hop_via_label); + mp->mr_label = ntohl (local_label); + mp->mr_eos = is_eos; + + mp->mr_next_hop_n_out_labels = vec_len (next_hop_out_label_stack); + if (0 != mp->mr_next_hop_n_out_labels) + { + memcpy (mp->mr_next_hop_out_label_stack, + next_hop_out_label_stack, + vec_len (next_hop_out_label_stack) * sizeof (mpls_label_t)); + vec_free (next_hop_out_label_stack); + } + + if (next_hop_set) + { + if (next_hop_proto_is_ip4) + { + clib_memcpy (mp->mr_next_hop, + &v4_next_hop_address, + sizeof (v4_next_hop_address)); + } + else + { + clib_memcpy (mp->mr_next_hop, + &v6_next_hop_address, + sizeof (v6_next_hop_address)); + } + } + local_label++; + + /* send it... */ + S; + /* If we receive SIGTERM, stop now... */ + if (vam->do_exit) + break; + } + + /* When testing multiple add/del ops, use a control-ping to sync */ + if (count > 1) + { + vl_api_control_ping_t *mp; + f64 after; + + /* Shut off async mode */ + vam->async_mode = 0; + + M (CONTROL_PING, control_ping); + S; + + timeout = vat_time_now (vam) + 1.0; + while (vat_time_now (vam) < timeout) + if (vam->result_ready == 1) + goto out; + vam->retval = -99; + + out: + if (vam->retval == -99) + errmsg ("timeout"); + + if (vam->async_errors > 0) + { + errmsg ("%d asynchronous errors", vam->async_errors); + vam->retval = -98; + } + vam->async_errors = 0; + after = vat_time_now (vam); + + /* slim chance, but we might have eaten SIGTERM on the first iteration */ + if (j > 0) + count = j; + + print (vam->ofp, "%d routes in %.6f secs, %.2f routes/sec", + count, after - before, count / (after - before)); + } + else + { + /* Wait for a reply... */ + W; + } + + /* Return the good/bad news */ + return (vam->retval); +} + +static int +api_mpls_ip_bind_unbind (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_ip_bind_unbind_t *mp; + f64 timeout; + u32 ip_table_id = 0; + u8 create_table_if_needed = 0; + u8 is_bind = 1; + u8 is_ip4 = 1; + ip4_address_t v4_address; + ip6_address_t v6_address; + u32 address_length; + u8 address_set = 0; + mpls_label_t local_label = MPLS_LABEL_INVALID; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U/%d", unformat_ip4_address, + &v4_address, &address_length)) + { + is_ip4 = 1; + address_set = 1; + } + else if (unformat (i, "%U/%d", unformat_ip6_address, + &v6_address, &address_length)) + { + is_ip4 = 0; + address_set = 1; + } + else if (unformat (i, "%d", &local_label)) + ; + else if (unformat (i, "create-table")) + create_table_if_needed = 1; + else if (unformat (i, "table-id %d", &ip_table_id)) + ; + else if (unformat (i, "unbind")) + is_bind = 0; + else if (unformat (i, "bind")) + is_bind = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!address_set) + { + errmsg ("IP addres not set"); + return -99; + } + + if (MPLS_LABEL_INVALID == local_label) + { + errmsg ("missing label"); + return -99; + } + + /* Construct the API message */ + M (MPLS_IP_BIND_UNBIND, mpls_ip_bind_unbind); + + mp->mb_create_table_if_needed = create_table_if_needed; + mp->mb_is_bind = is_bind; + mp->mb_is_ip4 = is_ip4; + mp->mb_ip_table_id = ntohl (ip_table_id); + mp->mb_mpls_table_id = 0; + mp->mb_label = ntohl (local_label); + mp->mb_address_length = address_length; + + if (is_ip4) + clib_memcpy (mp->mb_address, &v4_address, sizeof (v4_address)); + else + clib_memcpy (mp->mb_address, &v6_address, sizeof (v6_address)); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_proxy_arp_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_proxy_arp_add_del_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + ip4_address_t lo, hi; + u8 range_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "%U - %U", unformat_ip4_address, &lo, + unformat_ip4_address, &hi)) + range_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (range_set == 0) + { + errmsg ("address range not set"); + return -99; + } + + M (PROXY_ARP_ADD_DEL, proxy_arp_add_del); + + mp->vrf_id = ntohl (vrf_id); + mp->is_add = is_add; + clib_memcpy (mp->low_address, &lo, sizeof (mp->low_address)); + clib_memcpy (mp->hi_address, &hi, sizeof (mp->hi_address)); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_proxy_arp_intfc_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_proxy_arp_intfc_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 enable = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_mpls_tunnel_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_mpls_tunnel_add_del_t *mp; + f64 timeout; + + u8 is_add = 1; + u8 l2_only = 0; + u32 sw_if_index = ~0; + u32 next_hop_sw_if_index = ~0; + u32 next_hop_proto_is_ip4 = 1; + + u32 next_hop_table_id = 0; + ip4_address_t v4_next_hop_address = { + .as_u32 = 0, + }; + ip6_address_t v6_next_hop_address = { {0} }; + mpls_label_t next_hop_out_label = MPLS_LABEL_INVALID, *labels = NULL; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "del sw_if_index %d", &sw_if_index)) + is_add = 0; + else if (unformat (i, "sw_if_index %d", &next_hop_sw_if_index)) + ; + else if (unformat (i, "via %U", + unformat_ip4_address, &v4_next_hop_address)) + { + next_hop_proto_is_ip4 = 1; + } + else if (unformat (i, "via %U", + unformat_ip6_address, &v6_next_hop_address)) + { + next_hop_proto_is_ip4 = 0; + } + else if (unformat (i, "l2-only")) + l2_only = 1; + else if (unformat (i, "next-hop-table %d", &next_hop_table_id)) + ; + else if (unformat (i, "out-label %d", &next_hop_out_label)) + vec_add1 (labels, ntohl (next_hop_out_label)); + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M2 (MPLS_TUNNEL_ADD_DEL, mpls_tunnel_add_del, + sizeof (mpls_label_t) * vec_len (labels)); + + mp->mt_next_hop_sw_if_index = ntohl (next_hop_sw_if_index); + mp->mt_sw_if_index = ntohl (sw_if_index); + mp->mt_is_add = is_add; + mp->mt_l2_only = l2_only; + mp->mt_next_hop_table_id = ntohl (next_hop_table_id); + mp->mt_next_hop_proto_is_ip4 = next_hop_proto_is_ip4; + + mp->mt_next_hop_n_out_labels = vec_len (labels); + + if (0 != mp->mt_next_hop_n_out_labels) + { + clib_memcpy (mp->mt_next_hop_out_label_stack, labels, + sizeof (mpls_label_t) * mp->mt_next_hop_n_out_labels); + vec_free (labels); + } + + if (next_hop_proto_is_ip4) + { + clib_memcpy (mp->mt_next_hop, + &v4_next_hop_address, sizeof (v4_next_hop_address)); + } + else + { + clib_memcpy (mp->mt_next_hop, + &v6_next_hop_address, sizeof (v6_next_hop_address)); + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_set_unnumbered (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_unnumbered_t *mp; + f64 timeout; + u32 sw_if_index; + u32 unnum_sw_index = ~0; + u8 is_add = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "unnum_if_index %d", &unnum_sw_index)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered); + + mp->sw_if_index = ntohl (sw_if_index); + mp->unnumbered_sw_if_index = ntohl (unnum_sw_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ip_neighbor_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_neighbor_add_del_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 vrf_id = 0; + u8 is_add = 1; + u8 is_static = 0; + u8 mac_address[6]; + u8 mac_set = 0; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + + memset (mac_address, 0, sizeof (mac_address)); + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) + { + mac_set = 1; + } + else if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "is_static")) + is_static = 1; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "dst %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "dst %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (IP_NEIGHBOR_ADD_DEL, ip_neighbor_add_del); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->vrf_id = ntohl (vrf_id); + mp->is_static = is_static; + if (mac_set) + clib_memcpy (mp->mac_address, mac_address, 6); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dst_address, &v6address, sizeof (v6address)); + } + else + { + /* mp->is_ipv6 = 0; via memset in M macro above */ + clib_memcpy (mp->dst_address, &v4address, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_reset_vrf (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_reset_vrf_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (RESET_VRF, reset_vrf); + + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_create_vlan_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_vlan_subif_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 vlan_id; + u8 vlan_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "vlan %d", &vlan_id)) + vlan_id_set = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (vlan_id_set == 0) + { + errmsg ("missing vlan_id"); + return -99; + } + M (CREATE_VLAN_SUBIF, create_vlan_subif); + + mp->sw_if_index = ntohl (sw_if_index); + mp->vlan_id = ntohl (vlan_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +#define foreach_create_subif_bit \ +_(no_tags) \ +_(one_tag) \ +_(two_tags) \ +_(dot1ad) \ +_(exact_match) \ +_(default_sub) \ +_(outer_vlan_id_any) \ +_(inner_vlan_id_any) + +static int +api_create_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_subif_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 sub_id; + u8 sub_id_set = 0; + u32 no_tags = 0; + u32 one_tag = 0; + u32 two_tags = 0; + u32 dot1ad = 0; + u32 exact_match = 0; + u32 default_sub = 0; + u32 outer_vlan_id_any = 0; + u32 inner_vlan_id_any = 0; + u32 tmp; + u16 outer_vlan_id = 0; + u16 inner_vlan_id = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sub_id %d", &sub_id)) + sub_id_set = 1; + else if (unformat (i, "outer_vlan_id %d", &tmp)) + outer_vlan_id = tmp; + else if (unformat (i, "inner_vlan_id %d", &tmp)) + inner_vlan_id = tmp; + +#define _(a) else if (unformat (i, #a)) a = 1 ; + foreach_create_subif_bit +#undef _ + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (sub_id_set == 0) + { + errmsg ("missing sub_id"); + return -99; + } + M (CREATE_SUBIF, create_subif); + + mp->sw_if_index = ntohl (sw_if_index); + mp->sub_id = ntohl (sub_id); + +#define _(a) mp->a = a; + foreach_create_subif_bit; +#undef _ + + mp->outer_vlan_id = ntohs (outer_vlan_id); + mp->inner_vlan_id = ntohs (inner_vlan_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_oam_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_oam_add_del_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + ip4_address_t src, dst; + u8 src_set = 0; + u8 dst_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "src %U", unformat_ip4_address, &src)) + src_set = 1; + else if (unformat (i, "dst %U", unformat_ip4_address, &dst)) + dst_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("missing src addr"); + return -99; + } + + if (dst_set == 0) + { + errmsg ("missing dst addr"); + return -99; + } + + M (OAM_ADD_DEL, oam_add_del); + + mp->vrf_id = ntohl (vrf_id); + mp->is_add = is_add; + clib_memcpy (mp->src_address, &src, sizeof (mp->src_address)); + clib_memcpy (mp->dst_address, &dst, sizeof (mp->dst_address)); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_reset_fib (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_reset_fib_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (RESET_FIB, reset_fib); + + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_config_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_add = 1; + u8 insert_cid = 1; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + u8 v4_src_address_set = 0; + u8 v6_src_address_set = 0; + ip4_address_t v4srcaddress; + ip6_address_t v6srcaddress; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "vrf %d", &vrf_id)) + ; + else if (unformat (i, "insert-cid %d", &insert_cid)) + ; + else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) + v4_src_address_set = 1; + else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) + v6_src_address_set = 1; + else + break; + } + + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 server addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no server addresses set"); + return -99; + } + + if (v4_src_address_set && v6_src_address_set) + { + errmsg ("both v4 and v6 src addresses set"); + return -99; + } + if (!v4_src_address_set && !v6_src_address_set) + { + errmsg ("no src addresses set"); + return -99; + } + + if (!(v4_src_address_set && v4_address_set) && + !(v6_src_address_set && v6_address_set)) + { + errmsg ("no matching server and src addresses set"); + return -99; + } + + /* Construct the API message */ + M (DHCP_PROXY_CONFIG, dhcp_proxy_config); + + mp->insert_circuit_id = insert_cid; + mp->is_add = is_add; + mp->vrf_id = ntohl (vrf_id); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); + clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); + } + else + { + clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); + clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_config_2 (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_config_2_t *mp; + f64 timeout; + u32 rx_vrf_id = 0; + u32 server_vrf_id = 0; + u8 is_add = 1; + u8 insert_cid = 1; + u8 v4_address_set = 0; + u8 v6_address_set = 0; + ip4_address_t v4address; + ip6_address_t v6address; + u8 v4_src_address_set = 0; + u8 v6_src_address_set = 0; + ip4_address_t v4srcaddress; + ip6_address_t v6srcaddress; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "rx_vrf_id %d", &rx_vrf_id)) + ; + else if (unformat (i, "server_vrf_id %d", &server_vrf_id)) + ; + else if (unformat (i, "insert-cid %d", &insert_cid)) + ; + else if (unformat (i, "svr %U", unformat_ip4_address, &v4address)) + v4_address_set = 1; + else if (unformat (i, "svr %U", unformat_ip6_address, &v6address)) + v6_address_set = 1; + else if (unformat (i, "src %U", unformat_ip4_address, &v4srcaddress)) + v4_src_address_set = 1; + else if (unformat (i, "src %U", unformat_ip6_address, &v6srcaddress)) + v6_src_address_set = 1; + else + break; + } + + if (v4_address_set && v6_address_set) + { + errmsg ("both v4 and v6 server addresses set"); + return -99; + } + if (!v4_address_set && !v6_address_set) + { + errmsg ("no server addresses set"); + return -99; + } + + if (v4_src_address_set && v6_src_address_set) + { + errmsg ("both v4 and v6 src addresses set"); + return -99; + } + if (!v4_src_address_set && !v6_src_address_set) + { + errmsg ("no src addresses set"); + return -99; + } + + if (!(v4_src_address_set && v4_address_set) && + !(v6_src_address_set && v6_address_set)) + { + errmsg ("no matching server and src addresses set"); + return -99; + } + + /* Construct the API message */ + M (DHCP_PROXY_CONFIG_2, dhcp_proxy_config_2); + + mp->insert_circuit_id = insert_cid; + mp->is_add = is_add; + mp->rx_vrf_id = ntohl (rx_vrf_id); + mp->server_vrf_id = ntohl (server_vrf_id); + if (v6_address_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->dhcp_server, &v6address, sizeof (v6address)); + clib_memcpy (mp->dhcp_src_address, &v6srcaddress, sizeof (v6address)); + } + else + { + clib_memcpy (mp->dhcp_server, &v4address, sizeof (v4address)); + clib_memcpy (mp->dhcp_src_address, &v4srcaddress, sizeof (v4address)); + } + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_proxy_set_vss (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_proxy_set_vss_t *mp; + f64 timeout; + u8 is_ipv6 = 0; + u8 is_add = 1; + u32 tbl_id; + u8 tbl_id_set = 0; + u32 oui; + u8 oui_set = 0; + u32 fib_id; + u8 fib_id_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "tbl_id %d", &tbl_id)) + tbl_id_set = 1; + if (unformat (i, "fib_id %d", &fib_id)) + fib_id_set = 1; + if (unformat (i, "oui %d", &oui)) + oui_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (tbl_id_set == 0) + { + errmsg ("missing tbl id"); + return -99; + } + + if (fib_id_set == 0) + { + errmsg ("missing fib id"); + return -99; + } + if (oui_set == 0) + { + errmsg ("missing oui"); + return -99; + } + + M (DHCP_PROXY_SET_VSS, dhcp_proxy_set_vss); + mp->tbl_id = ntohl (tbl_id); + mp->fib_id = ntohl (fib_id); + mp->oui = ntohl (oui); + mp->is_ipv6 = is_ipv6; + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_dhcp_client_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_dhcp_client_config_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 is_add = 1; + u8 *hostname = 0; + u8 disable_event = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "hostname %s", &hostname)) + ; + else if (unformat (i, "disable_event")) + disable_event = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (vec_len (hostname) > 63) + { + errmsg ("hostname too long"); + } + vec_add1 (hostname, 0); + + /* Construct the API message */ + M (DHCP_CLIENT_CONFIG, dhcp_client_config); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->hostname, hostname, vec_len (hostname)); + vec_free (hostname); + mp->is_add = is_add; + mp->want_dhcp_event = disable_event ? 0 : 1; + mp->pid = getpid (); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + /* NOTREACHED */ + return 0; +} + +static int +api_set_ip_flow_hash (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ip_flow_hash_t *mp; + f64 timeout; + u32 vrf_id = 0; + u8 is_ipv6 = 0; + u8 vrf_id_set = 0; + u8 src = 0; + u8 dst = 0; + u8 sport = 0; + u8 dport = 0; + u8 proto = 0; + u8 reverse = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vrf %d", &vrf_id)) + vrf_id_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else if (unformat (i, "src")) + src = 1; + else if (unformat (i, "dst")) + dst = 1; + else if (unformat (i, "sport")) + sport = 1; + else if (unformat (i, "dport")) + dport = 1; + else if (unformat (i, "proto")) + proto = 1; + else if (unformat (i, "reverse")) + reverse = 1; + + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (vrf_id_set == 0) + { + errmsg ("missing vrf id"); + return -99; + } + + M (SET_IP_FLOW_HASH, set_ip_flow_hash); + mp->src = src; + mp->dst = dst; + mp->sport = sport; + mp->dport = dport; + mp->proto = proto; + mp->reverse = reverse; + mp->vrf_id = ntohl (vrf_id); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (SW_INTERFACE_IP6_ENABLE_DISABLE, sw_interface_ip6_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6_set_link_local_address (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6_set_link_local_address_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 address_length = 0; + u8 v6_address_set = 0; + ip6_address_t v6address; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (!v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS, + sw_interface_ip6_set_link_local_address); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + mp->address_length = address_length; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + + +static int +api_sw_interface_ip6nd_ra_prefix (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6nd_ra_prefix_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 address_length = 0; + u8 v6_address_set = 0; + ip6_address_t v6address; + u8 use_default = 0; + u8 no_advertise = 0; + u8 off_link = 0; + u8 no_autoconfig = 0; + u8 no_onlink = 0; + u8 is_no = 0; + u32 val_lifetime = 0; + u32 pref_lifetime = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "%U/%d", + unformat_ip6_address, &v6address, &address_length)) + v6_address_set = 1; + else if (unformat (i, "val_life %d", &val_lifetime)) + ; + else if (unformat (i, "pref_life %d", &pref_lifetime)) + ; + else if (unformat (i, "def")) + use_default = 1; + else if (unformat (i, "noadv")) + no_advertise = 1; + else if (unformat (i, "offl")) + off_link = 1; + else if (unformat (i, "noauto")) + no_autoconfig = 1; + else if (unformat (i, "nolink")) + no_onlink = 1; + else if (unformat (i, "isno")) + is_no = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + if (!v6_address_set) + { + errmsg ("no address set"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6ND_RA_PREFIX, sw_interface_ip6nd_ra_prefix); + + mp->sw_if_index = ntohl (sw_if_index); + clib_memcpy (mp->address, &v6address, sizeof (v6address)); + mp->address_length = address_length; + mp->use_default = use_default; + mp->no_advertise = no_advertise; + mp->off_link = off_link; + mp->no_autoconfig = no_autoconfig; + mp->no_onlink = no_onlink; + mp->is_no = is_no; + mp->val_lifetime = ntohl (val_lifetime); + mp->pref_lifetime = ntohl (pref_lifetime); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_sw_interface_ip6nd_ra_config (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_ip6nd_ra_config_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 suppress = 0; + u8 managed = 0; + u8 other = 0; + u8 ll_option = 0; + u8 send_unicast = 0; + u8 cease = 0; + u8 is_no = 0; + u8 default_router = 0; + u32 max_interval = 0; + u32 min_interval = 0; + u32 lifetime = 0; + u32 initial_count = 0; + u32 initial_interval = 0; + + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "maxint %d", &max_interval)) + ; + else if (unformat (i, "minint %d", &min_interval)) + ; + else if (unformat (i, "life %d", &lifetime)) + ; + else if (unformat (i, "count %d", &initial_count)) + ; + else if (unformat (i, "interval %d", &initial_interval)) + ; + else if (unformat (i, "suppress") || unformat (i, "surpress")) + suppress = 1; + else if (unformat (i, "managed")) + managed = 1; + else if (unformat (i, "other")) + other = 1; + else if (unformat (i, "ll")) + ll_option = 1; + else if (unformat (i, "send")) + send_unicast = 1; + else if (unformat (i, "cease")) + cease = 1; + else if (unformat (i, "isno")) + is_no = 1; + else if (unformat (i, "def")) + default_router = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_IP6ND_RA_CONFIG, sw_interface_ip6nd_ra_config); + + mp->sw_if_index = ntohl (sw_if_index); + mp->max_interval = ntohl (max_interval); + mp->min_interval = ntohl (min_interval); + mp->lifetime = ntohl (lifetime); + mp->initial_count = ntohl (initial_count); + mp->initial_interval = ntohl (initial_interval); + mp->suppress = suppress; + mp->managed = managed; + mp->other = other; + mp->ll_option = ll_option; + mp->send_unicast = send_unicast; + mp->cease = cease; + mp->is_no = is_no; + mp->default_router = default_router; + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_set_arp_neighbor_limit (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_arp_neighbor_limit_t *mp; + f64 timeout; + u32 arp_nbr_limit; + u8 limit_set = 0; + u8 is_ipv6 = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "arp_nbr_limit %d", &arp_nbr_limit)) + limit_set = 1; + else if (unformat (i, "ipv6")) + is_ipv6 = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (limit_set == 0) + { + errmsg ("missing limit value"); + return -99; + } + + M (SET_ARP_NEIGHBOR_LIMIT, set_arp_neighbor_limit); + + mp->arp_neighbor_limit = ntohl (arp_nbr_limit); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2_patch_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_patch_add_del_t *mp; + f64 timeout; + u32 rx_sw_if_index; + u8 rx_sw_if_index_set = 0; + u32 tx_sw_if_index; + u8 tx_sw_if_index_set = 0; + u8 is_add = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "rx_sw_if_index %d", &rx_sw_if_index)) + rx_sw_if_index_set = 1; + else if (unformat (i, "tx_sw_if_index %d", &tx_sw_if_index)) + tx_sw_if_index_set = 1; + else if (unformat (i, "rx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &rx_sw_if_index)) + rx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "tx")) + { + if (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, + &tx_sw_if_index)) + tx_sw_if_index_set = 1; + } + else + break; + } + else if (unformat (i, "del")) + is_add = 0; + else + break; + } + + if (rx_sw_if_index_set == 0) + { + errmsg ("missing rx interface name or rx_sw_if_index"); + return -99; + } + + if (tx_sw_if_index_set == 0) + { + errmsg ("missing tx interface name or tx_sw_if_index"); + return -99; + } + + M (L2_PATCH_ADD_DEL, l2_patch_add_del); + + mp->rx_sw_if_index = ntohl (rx_sw_if_index); + mp->tx_sw_if_index = ntohl (tx_sw_if_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ioam_enable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ioam_enable_t *mp; + f64 timeout; + u32 id = 0; + int has_trace_option = 0; + int has_pot_option = 0; + int has_seqno_option = 0; + int has_analyse_option = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "trace")) + has_trace_option = 1; + else if (unformat (input, "pot")) + has_pot_option = 1; + else if (unformat (input, "seqno")) + has_seqno_option = 1; + else if (unformat (input, "analyse")) + has_analyse_option = 1; + else + break; + } + M (IOAM_ENABLE, ioam_enable); + mp->id = htons (id); + mp->seqno = has_seqno_option; + mp->analyse = has_analyse_option; + mp->pot_enable = has_pot_option; + mp->trace_enable = has_trace_option; + + S; + W; + + return (0); + +} + + +static int +api_ioam_disable (vat_main_t * vam) +{ + vl_api_ioam_disable_t *mp; + f64 timeout; + + M (IOAM_DISABLE, ioam_disable); + S; + W; + return 0; +} + +static int +api_sr_tunnel_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sr_tunnel_add_del_t *mp; + f64 timeout; + int is_del = 0; + int pl_index; + ip6_address_t src_address; + int src_address_set = 0; + ip6_address_t dst_address; + u32 dst_mask_width; + int dst_address_set = 0; + u16 flags = 0; + u32 rx_table_id = 0; + u32 tx_table_id = 0; + ip6_address_t *segments = 0; + ip6_address_t *this_seg; + ip6_address_t *tags = 0; + ip6_address_t *this_tag; + ip6_address_t next_address, tag; + u8 *name = 0; + u8 *policy_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_del = 1; + else if (unformat (i, "name %s", &name)) + ; + else if (unformat (i, "policy %s", &policy_name)) + ; + else if (unformat (i, "rx_fib_id %d", &rx_table_id)) + ; + else if (unformat (i, "tx_fib_id %d", &tx_table_id)) + ; + else if (unformat (i, "src %U", unformat_ip6_address, &src_address)) + src_address_set = 1; + else if (unformat (i, "dst %U/%d", + unformat_ip6_address, &dst_address, &dst_mask_width)) + dst_address_set = 1; + else if (unformat (i, "next %U", unformat_ip6_address, &next_address)) + { + vec_add2 (segments, this_seg, 1); + clib_memcpy (this_seg->as_u8, next_address.as_u8, + sizeof (*this_seg)); + } + else if (unformat (i, "tag %U", unformat_ip6_address, &tag)) + { + vec_add2 (tags, this_tag, 1); + clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag)); + } + else if (unformat (i, "clean")) + flags |= IP6_SR_HEADER_FLAG_CLEANUP; + else if (unformat (i, "protected")) + flags |= IP6_SR_HEADER_FLAG_PROTECTED; + else if (unformat (i, "InPE %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + { + pl_index_range_error: + errmsg ("pl index %d out of range", pl_index); + return -99; + } + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE << (3 * (pl_index - 1)); + } + else if (unformat (i, "EgPE %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + goto pl_index_range_error; + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE << (3 * (pl_index - 1)); + } + else if (unformat (i, "OrgSrc %d", &pl_index)) + { + if (pl_index <= 0 || pl_index > 4) + goto pl_index_range_error; + flags |= + IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR << (3 * (pl_index - 1)); + } + else + break; + } + + if (!src_address_set) + { + errmsg ("src address required"); + return -99; + } + + if (!dst_address_set) + { + errmsg ("dst address required"); + return -99; + } + + if (!segments) + { + errmsg ("at least one sr segment required"); + return -99; + } + + M2 (SR_TUNNEL_ADD_DEL, sr_tunnel_add_del, + vec_len (segments) * sizeof (ip6_address_t) + + vec_len (tags) * sizeof (ip6_address_t)); + + clib_memcpy (mp->src_address, &src_address, sizeof (mp->src_address)); + clib_memcpy (mp->dst_address, &dst_address, sizeof (mp->dst_address)); + mp->dst_mask_width = dst_mask_width; + mp->flags_net_byte_order = clib_host_to_net_u16 (flags); + mp->n_segments = vec_len (segments); + mp->n_tags = vec_len (tags); + mp->is_add = is_del == 0; + clib_memcpy (mp->segs_and_tags, segments, + vec_len (segments) * sizeof (ip6_address_t)); + clib_memcpy (mp->segs_and_tags + + vec_len (segments) * sizeof (ip6_address_t), tags, + vec_len (tags) * sizeof (ip6_address_t)); + + mp->outer_vrf_id = ntohl (rx_table_id); + mp->inner_vrf_id = ntohl (tx_table_id); + memcpy (mp->name, name, vec_len (name)); + memcpy (mp->policy_name, policy_name, vec_len (policy_name)); + + vec_free (segments); + vec_free (tags); + + S; + W; + /* NOTREACHED */ +} + +static int +api_sr_policy_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_sr_policy_add_del_t *mp; + f64 timeout; + int is_del = 0; + u8 *name = 0; + u8 *tunnel_name = 0; + u8 **tunnel_names = 0; + + int name_set = 0; + int tunnel_set = 0; + int j = 0; + int tunnel_names_length = 1; // Init to 1 to offset the #tunnel_names counter byte + int tun_name_len = 0; // Different naming convention used as confusing these would be "bad" (TM) + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_del = 1; + else if (unformat (input, "name %s", &name)) + name_set = 1; + else if (unformat (input, "tunnel %s", &tunnel_name)) + { + if (tunnel_name) + { + vec_add1 (tunnel_names, tunnel_name); + /* For serializer: + - length = #bytes to store in serial vector + - +1 = byte to store that length + */ + tunnel_names_length += (vec_len (tunnel_name) + 1); + tunnel_set = 1; + tunnel_name = 0; + } + } + else + break; + } + + if (!name_set) + { + errmsg ("policy name required"); + return -99; + } + + if ((!tunnel_set) && (!is_del)) + { + errmsg ("tunnel name required"); + return -99; + } + + M2 (SR_POLICY_ADD_DEL, sr_policy_add_del, tunnel_names_length); + + + + mp->is_add = !is_del; + + memcpy (mp->name, name, vec_len (name)); + // Since mp->tunnel_names is of type u8[0] and not a u8 *, u8 ** needs to be serialized + u8 *serial_orig = 0; + vec_validate (serial_orig, tunnel_names_length); + *serial_orig = vec_len (tunnel_names); // Store the number of tunnels as length in first byte of serialized vector + serial_orig += 1; // Move along one byte to store the length of first tunnel_name + + for (j = 0; j < vec_len (tunnel_names); j++) + { + tun_name_len = vec_len (tunnel_names[j]); + *serial_orig = tun_name_len; // Store length of tunnel name in first byte of Length/Value pair + serial_orig += 1; // Move along one byte to store the actual tunnel name + memcpy (serial_orig, tunnel_names[j], tun_name_len); + serial_orig += tun_name_len; // Advance past the copy + } + memcpy (mp->tunnel_names, serial_orig - tunnel_names_length, tunnel_names_length); // Regress serial_orig to head then copy fwd + + vec_free (tunnel_names); + vec_free (tunnel_name); + + S; + W; + /* NOTREACHED */ +} + +static int +api_sr_multicast_map_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_sr_multicast_map_add_del_t *mp; + f64 timeout; + int is_del = 0; + ip6_address_t multicast_address; + u8 *policy_name = 0; + int multicast_address_set = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_del = 1; + else + if (unformat + (input, "address %U", unformat_ip6_address, &multicast_address)) + multicast_address_set = 1; + else if (unformat (input, "sr-policy %s", &policy_name)) + ; + else + break; + } + + if (!is_del && !policy_name) + { + errmsg ("sr-policy name required"); + return -99; + } + + + if (!multicast_address_set) + { + errmsg ("address required"); + return -99; + } + + M (SR_MULTICAST_MAP_ADD_DEL, sr_multicast_map_add_del); + + mp->is_add = !is_del; + memcpy (mp->policy_name, policy_name, vec_len (policy_name)); + clib_memcpy (mp->multicast_address, &multicast_address, + sizeof (mp->multicast_address)); + + + vec_free (policy_name); + + S; + W; + /* NOTREACHED */ +} + + +#define foreach_tcp_proto_field \ +_(src_port) \ +_(dst_port) + +#define foreach_udp_proto_field \ +_(src_port) \ +_(dst_port) + +#define foreach_ip4_proto_field \ +_(src_address) \ +_(dst_address) \ +_(tos) \ +_(length) \ +_(fragment_id) \ +_(ttl) \ +_(protocol) \ +_(checksum) + +uword +unformat_tcp_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + tcp_header_t *tcp; + +#define _(a) u8 a=0; + foreach_tcp_proto_field; +#undef _ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (0); +#define _(a) else if (unformat (input, #a)) a=1; + foreach_tcp_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_tcp_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*tcp) - 1); + + tcp = (tcp_header_t *) mask; + +#define _(a) if (a) memset (&tcp->a, 0xff, sizeof (tcp->a)); + foreach_tcp_proto_field; +#undef _ + + *maskp = mask; + return 1; +} + +uword +unformat_udp_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + udp_header_t *udp; + +#define _(a) u8 a=0; + foreach_udp_proto_field; +#undef _ + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (0); +#define _(a) else if (unformat (input, #a)) a=1; + foreach_udp_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_udp_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*udp) - 1); + + udp = (udp_header_t *) mask; + +#define _(a) if (a) memset (&udp->a, 0xff, sizeof (udp->a)); + foreach_udp_proto_field; +#undef _ + + *maskp = mask; + return 1; +} + +typedef struct +{ + u16 src_port, dst_port; +} tcpudp_header_t; + +uword +unformat_l4_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u16 src_port = 0, dst_port = 0; + tcpudp_header_t *tcpudp; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "tcp %U", unformat_tcp_mask, maskp)) + return 1; + else if (unformat (input, "udp %U", unformat_udp_mask, maskp)) + return 1; + else if (unformat (input, "src_port")) + src_port = 0xFFFF; + else if (unformat (input, "dst_port")) + dst_port = 0xFFFF; + else + return 0; + } + + if (!src_port && !dst_port) + return 0; + + u8 *mask = 0; + vec_validate (mask, sizeof (tcpudp_header_t) - 1); + + tcpudp = (tcpudp_header_t *) mask; + tcpudp->src_port = src_port; + tcpudp->dst_port = dst_port; + + *maskp = mask; + + return 1; +} + +uword +unformat_ip4_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + ip4_header_t *ip; + +#define _(a) u8 a=0; + foreach_ip4_proto_field; +#undef _ + u8 version = 0; + u8 hdr_length = 0; + + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version")) + version = 1; + else if (unformat (input, "hdr_length")) + hdr_length = 1; + else if (unformat (input, "src")) + src_address = 1; + else if (unformat (input, "dst")) + dst_address = 1; + else if (unformat (input, "proto")) + protocol = 1; + +#define _(a) else if (unformat (input, #a)) a=1; + foreach_ip4_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_ip4_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*ip) - 1); + + ip = (ip4_header_t *) mask; + +#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a)); + foreach_ip4_proto_field; +#undef _ + + ip->ip_version_and_header_length = 0; + + if (version) + ip->ip_version_and_header_length |= 0xF0; + + if (hdr_length) + ip->ip_version_and_header_length |= 0x0F; + + *maskp = mask; + return 1; +} + +#define foreach_ip6_proto_field \ +_(src_address) \ +_(dst_address) \ +_(payload_length) \ +_(hop_limit) \ +_(protocol) + +uword +unformat_ip6_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 found_something = 0; + ip6_header_t *ip; + u32 ip_version_traffic_class_and_flow_label; + +#define _(a) u8 a=0; + foreach_ip6_proto_field; +#undef _ + u8 version = 0; + u8 traffic_class = 0; + u8 flow_label = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version")) + version = 1; + else if (unformat (input, "traffic-class")) + traffic_class = 1; + else if (unformat (input, "flow-label")) + flow_label = 1; + else if (unformat (input, "src")) + src_address = 1; + else if (unformat (input, "dst")) + dst_address = 1; + else if (unformat (input, "proto")) + protocol = 1; + +#define _(a) else if (unformat (input, #a)) a=1; + foreach_ip6_proto_field +#undef _ + else + break; + } + +#define _(a) found_something += a; + foreach_ip6_proto_field; +#undef _ + + if (found_something == 0) + return 0; + + vec_validate (mask, sizeof (*ip) - 1); + + ip = (ip6_header_t *) mask; + +#define _(a) if (a) memset (&ip->a, 0xff, sizeof (ip->a)); + foreach_ip6_proto_field; +#undef _ + + ip_version_traffic_class_and_flow_label = 0; + + if (version) + ip_version_traffic_class_and_flow_label |= 0xF0000000; + + if (traffic_class) + ip_version_traffic_class_and_flow_label |= 0x0FF00000; + + if (flow_label) + ip_version_traffic_class_and_flow_label |= 0x000FFFFF; + + ip->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label); + + *maskp = mask; + return 1; +} + +uword +unformat_l3_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ip4 %U", unformat_ip4_mask, maskp)) + return 1; + else if (unformat (input, "ip6 %U", unformat_ip6_mask, maskp)) + return 1; + else + break; + } + return 0; +} + +uword +unformat_l2_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u8 *mask = 0; + u8 src = 0; + u8 dst = 0; + u8 proto = 0; + u8 tag1 = 0; + u8 tag2 = 0; + u8 ignore_tag1 = 0; + u8 ignore_tag2 = 0; + u8 cos1 = 0; + u8 cos2 = 0; + u8 dot1q = 0; + u8 dot1ad = 0; + int len = 14; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src")) + src = 1; + else if (unformat (input, "dst")) + dst = 1; + else if (unformat (input, "proto")) + proto = 1; + else if (unformat (input, "tag1")) + tag1 = 1; + else if (unformat (input, "tag2")) + tag2 = 1; + else if (unformat (input, "ignore-tag1")) + ignore_tag1 = 1; + else if (unformat (input, "ignore-tag2")) + ignore_tag2 = 1; + else if (unformat (input, "cos1")) + cos1 = 1; + else if (unformat (input, "cos2")) + cos2 = 1; + else if (unformat (input, "dot1q")) + dot1q = 1; + else if (unformat (input, "dot1ad")) + dot1ad = 1; + else + break; + } + if ((src + dst + proto + tag1 + tag2 + dot1q + dot1ad + + ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0) + return 0; + + if (tag1 || ignore_tag1 || cos1 || dot1q) + len = 18; + if (tag2 || ignore_tag2 || cos2 || dot1ad) + len = 22; + + vec_validate (mask, len - 1); + + if (dst) + memset (mask, 0xff, 6); + + if (src) + memset (mask + 6, 0xff, 6); + + if (tag2 || dot1ad) + { + /* inner vlan tag */ + if (tag2) + { + mask[19] = 0xff; + mask[18] = 0x0f; + } + if (cos2) + mask[18] |= 0xe0; + if (proto) + mask[21] = mask[20] = 0xff; + if (tag1) + { + mask[15] = 0xff; + mask[14] = 0x0f; + } + if (cos1) + mask[14] |= 0xe0; + *maskp = mask; + return 1; + } + if (tag1 | dot1q) + { + if (tag1) + { + mask[15] = 0xff; + mask[14] = 0x0f; + } + if (cos1) + mask[14] |= 0xe0; + if (proto) + mask[16] = mask[17] = 0xff; + + *maskp = mask; + return 1; + } + if (cos2) + mask[18] |= 0xe0; + if (cos1) + mask[14] |= 0xe0; + if (proto) + mask[12] = mask[13] = 0xff; + + *maskp = mask; + return 1; +} + +uword +unformat_classify_mask (unformat_input_t * input, va_list * args) +{ + u8 **maskp = va_arg (*args, u8 **); + u32 *skipp = va_arg (*args, u32 *); + u32 *matchp = va_arg (*args, u32 *); + u32 match; + u8 *mask = 0; + u8 *l2 = 0; + u8 *l3 = 0; + u8 *l4 = 0; + int i; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "hex %U", unformat_hex_string, &mask)) + ; + else if (unformat (input, "l2 %U", unformat_l2_mask, &l2)) + ; + else if (unformat (input, "l3 %U", unformat_l3_mask, &l3)) + ; + else if (unformat (input, "l4 %U", unformat_l4_mask, &l4)) + ; + else + break; + } + + if (l4 && !l3) + { + vec_free (mask); + vec_free (l2); + vec_free (l4); + return 0; + } + + if (mask || l2 || l3 || l4) + { + if (l2 || l3 || l4) + { + /* "With a free Ethernet header in every package" */ + if (l2 == 0) + vec_validate (l2, 13); + mask = l2; + if (vec_len (l3)) + { + vec_append (mask, l3); + vec_free (l3); + } + if (vec_len (l4)) + { + vec_append (mask, l4); + vec_free (l4); + } + } + + /* Scan forward looking for the first significant mask octet */ + for (i = 0; i < vec_len (mask); i++) + if (mask[i]) + break; + + /* compute (skip, match) params */ + *skipp = i / sizeof (u32x4); + vec_delete (mask, *skipp * sizeof (u32x4), 0); + + /* Pad mask to an even multiple of the vector size */ + while (vec_len (mask) % sizeof (u32x4)) + vec_add1 (mask, 0); + + match = vec_len (mask) / sizeof (u32x4); + + for (i = match * sizeof (u32x4); i > 0; i -= sizeof (u32x4)) + { + u64 *tmp = (u64 *) (mask + (i - sizeof (u32x4))); + if (*tmp || *(tmp + 1)) + break; + match--; + } + if (match == 0) + clib_warning ("BUG: match 0"); + + _vec_len (mask) = match * sizeof (u32x4); + + *matchp = match; + *maskp = mask; + + return 1; + } + + return 0; +} + +#define foreach_l2_next \ +_(drop, DROP) \ +_(ethernet, ETHERNET_INPUT) \ +_(ip4, IP4_INPUT) \ +_(ip6, IP6_INPUT) + +uword +unformat_l2_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = L2_INPUT_CLASSIFY_NEXT_##N; goto out;} + foreach_l2_next; +#undef _ + + if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +#define foreach_ip_next \ +_(drop, DROP) \ +_(local, LOCAL) \ +_(rewrite, REWRITE) + +uword +unformat_ip_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = IP_LOOKUP_NEXT_##N; goto out;} + foreach_ip_next; +#undef _ + + if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +#define foreach_acl_next \ +_(deny, DENY) + +uword +unformat_acl_next_index (unformat_input_t * input, va_list * args) +{ + u32 *miss_next_indexp = va_arg (*args, u32 *); + u32 next_index = 0; + u32 tmp; + +#define _(n,N) \ + if (unformat (input, #n)) { next_index = ACL_NEXT_INDEX_##N; goto out;} + foreach_acl_next; +#undef _ + + if (unformat (input, "permit")) + { + next_index = ~0; + goto out; + } + else if (unformat (input, "%d", &tmp)) + { + next_index = tmp; + goto out; + } + + return 0; + +out: + *miss_next_indexp = next_index; + return 1; +} + +uword +unformat_policer_precolor (unformat_input_t * input, va_list * args) +{ + u32 *r = va_arg (*args, u32 *); + + if (unformat (input, "conform-color")) + *r = POLICE_CONFORM; + else if (unformat (input, "exceed-color")) + *r = POLICE_EXCEED; + else + return 0; + + return 1; +} + +static int +api_classify_add_del_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_add_del_table_t *mp; + + u32 nbuckets = 2; + u32 skip = ~0; + u32 match = ~0; + int is_add = 1; + int del_chain = 0; + u32 table_index = ~0; + u32 next_table_index = ~0; + u32 miss_next_index = ~0; + u32 memory_size = 32 << 20; + u8 *mask = 0; + f64 timeout; + u32 current_data_flag = 0; + int current_data_offset = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "del-chain")) + { + is_add = 0; + del_chain = 1; + } + else if (unformat (i, "buckets %d", &nbuckets)) + ; + else if (unformat (i, "memory_size %d", &memory_size)) + ; + else if (unformat (i, "skip %d", &skip)) + ; + else if (unformat (i, "match %d", &match)) + ; + else if (unformat (i, "table %d", &table_index)) + ; + else if (unformat (i, "mask %U", unformat_classify_mask, + &mask, &skip, &match)) + ; + else if (unformat (i, "next-table %d", &next_table_index)) + ; + else if (unformat (i, "miss-next %U", unformat_ip_next_index, + &miss_next_index)) + ; + else if (unformat (i, "l2-miss-next %U", unformat_l2_next_index, + &miss_next_index)) + ; + else if (unformat (i, "acl-miss-next %U", unformat_acl_next_index, + &miss_next_index)) + ; + else if (unformat (i, "current-data-flag %d", ¤t_data_flag)) + ; + else if (unformat (i, "current-data-offset %d", ¤t_data_offset)) + ; + else + break; + } + + if (is_add && mask == 0) + { + errmsg ("Mask required"); + return -99; + } + + if (is_add && skip == ~0) + { + errmsg ("skip count required"); + return -99; + } + + if (is_add && match == ~0) + { + errmsg ("match count required"); + return -99; + } + + if (!is_add && table_index == ~0) + { + errmsg ("table index required for delete"); + return -99; + } + + M2 (CLASSIFY_ADD_DEL_TABLE, classify_add_del_table, vec_len (mask)); + + mp->is_add = is_add; + mp->del_chain = del_chain; + mp->table_index = ntohl (table_index); + mp->nbuckets = ntohl (nbuckets); + mp->memory_size = ntohl (memory_size); + mp->skip_n_vectors = ntohl (skip); + mp->match_n_vectors = ntohl (match); + mp->next_table_index = ntohl (next_table_index); + mp->miss_next_index = ntohl (miss_next_index); + mp->current_data_flag = ntohl (current_data_flag); + mp->current_data_offset = ntohl (current_data_offset); + clib_memcpy (mp->mask, mask, vec_len (mask)); + + vec_free (mask); + + S; + W; + /* NOTREACHED */ +} + +uword +unformat_l4_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + + u8 *proto_header = 0; + int src_port = 0; + int dst_port = 0; + + tcpudp_header_t h; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src_port %d", &src_port)) + ; + else if (unformat (input, "dst_port %d", &dst_port)) + ; + else + return 0; + } + + h.src_port = clib_host_to_net_u16 (src_port); + h.dst_port = clib_host_to_net_u16 (dst_port); + vec_validate (proto_header, sizeof (h) - 1); + memcpy (proto_header, &h, sizeof (h)); + + *matchp = proto_header; + + return 1; +} + +uword +unformat_ip4_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + ip4_header_t *ip; + int version = 0; + u32 version_val; + int hdr_length = 0; + u32 hdr_length_val; + int src = 0, dst = 0; + ip4_address_t src_val, dst_val; + int proto = 0; + u32 proto_val; + int tos = 0; + u32 tos_val; + int length = 0; + u32 length_val; + int fragment_id = 0; + u32 fragment_id_val; + int ttl = 0; + int ttl_val; + int checksum = 0; + u32 checksum_val; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version %d", &version_val)) + version = 1; + else if (unformat (input, "hdr_length %d", &hdr_length_val)) + hdr_length = 1; + else if (unformat (input, "src %U", unformat_ip4_address, &src_val)) + src = 1; + else if (unformat (input, "dst %U", unformat_ip4_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %d", &proto_val)) + proto = 1; + else if (unformat (input, "tos %d", &tos_val)) + tos = 1; + else if (unformat (input, "length %d", &length_val)) + length = 1; + else if (unformat (input, "fragment_id %d", &fragment_id_val)) + fragment_id = 1; + else if (unformat (input, "ttl %d", &ttl_val)) + ttl = 1; + else if (unformat (input, "checksum %d", &checksum_val)) + checksum = 1; + else + break; + } + + if (version + hdr_length + src + dst + proto + tos + length + fragment_id + + ttl + checksum == 0) + return 0; + + /* + * Aligned because we use the real comparison functions + */ + vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4)); + + ip = (ip4_header_t *) match; + + /* These are realistically matched in practice */ + if (src) + ip->src_address.as_u32 = src_val.as_u32; + + if (dst) + ip->dst_address.as_u32 = dst_val.as_u32; + + if (proto) + ip->protocol = proto_val; + + + /* These are not, but they're included for completeness */ + if (version) + ip->ip_version_and_header_length |= (version_val & 0xF) << 4; + + if (hdr_length) + ip->ip_version_and_header_length |= (hdr_length_val & 0xF); + + if (tos) + ip->tos = tos_val; + + if (length) + ip->length = clib_host_to_net_u16 (length_val); + + if (ttl) + ip->ttl = ttl_val; + + if (checksum) + ip->checksum = clib_host_to_net_u16 (checksum_val); + + *matchp = match; + return 1; +} + +uword +unformat_ip6_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + ip6_header_t *ip; + int version = 0; + u32 version_val; + u8 traffic_class = 0; + u32 traffic_class_val = 0; + u8 flow_label = 0; + u8 flow_label_val; + int src = 0, dst = 0; + ip6_address_t src_val, dst_val; + int proto = 0; + u32 proto_val; + int payload_length = 0; + u32 payload_length_val; + int hop_limit = 0; + int hop_limit_val; + u32 ip_version_traffic_class_and_flow_label; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "version %d", &version_val)) + version = 1; + else if (unformat (input, "traffic_class %d", &traffic_class_val)) + traffic_class = 1; + else if (unformat (input, "flow_label %d", &flow_label_val)) + flow_label = 1; + else if (unformat (input, "src %U", unformat_ip6_address, &src_val)) + src = 1; + else if (unformat (input, "dst %U", unformat_ip6_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %d", &proto_val)) + proto = 1; + else if (unformat (input, "payload_length %d", &payload_length_val)) + payload_length = 1; + else if (unformat (input, "hop_limit %d", &hop_limit_val)) + hop_limit = 1; + else + break; + } + + if (version + traffic_class + flow_label + src + dst + proto + + payload_length + hop_limit == 0) + return 0; + + /* + * Aligned because we use the real comparison functions + */ + vec_validate_aligned (match, sizeof (*ip) - 1, sizeof (u32x4)); + + ip = (ip6_header_t *) match; + + if (src) + clib_memcpy (&ip->src_address, &src_val, sizeof (ip->src_address)); + + if (dst) + clib_memcpy (&ip->dst_address, &dst_val, sizeof (ip->dst_address)); + + if (proto) + ip->protocol = proto_val; + + ip_version_traffic_class_and_flow_label = 0; + + if (version) + ip_version_traffic_class_and_flow_label |= (version_val & 0xF) << 28; + + if (traffic_class) + ip_version_traffic_class_and_flow_label |= + (traffic_class_val & 0xFF) << 20; + + if (flow_label) + ip_version_traffic_class_and_flow_label |= (flow_label_val & 0xFFFFF); + + ip->ip_version_traffic_class_and_flow_label = + clib_host_to_net_u32 (ip_version_traffic_class_and_flow_label); + + if (payload_length) + ip->payload_length = clib_host_to_net_u16 (payload_length_val); + + if (hop_limit) + ip->hop_limit = hop_limit_val; + + *matchp = match; + return 1; +} + +uword +unformat_l3_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ip4 %U", unformat_ip4_match, matchp)) + return 1; + else if (unformat (input, "ip6 %U", unformat_ip6_match, matchp)) + return 1; + else + break; + } + return 0; +} + +uword +unformat_vlan_tag (unformat_input_t * input, va_list * args) +{ + u8 *tagp = va_arg (*args, u8 *); + u32 tag; + + if (unformat (input, "%d", &tag)) + { + tagp[0] = (tag >> 8) & 0x0F; + tagp[1] = tag & 0xFF; + return 1; + } + + return 0; +} + +uword +unformat_l2_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u8 *match = 0; + u8 src = 0; + u8 src_val[6]; + u8 dst = 0; + u8 dst_val[6]; + u8 proto = 0; + u16 proto_val; + u8 tag1 = 0; + u8 tag1_val[2]; + u8 tag2 = 0; + u8 tag2_val[2]; + int len = 14; + u8 ignore_tag1 = 0; + u8 ignore_tag2 = 0; + u8 cos1 = 0; + u8 cos2 = 0; + u32 cos1_val = 0; + u32 cos2_val = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "src %U", unformat_ethernet_address, &src_val)) + src = 1; + else + if (unformat (input, "dst %U", unformat_ethernet_address, &dst_val)) + dst = 1; + else if (unformat (input, "proto %U", + unformat_ethernet_type_host_byte_order, &proto_val)) + proto = 1; + else if (unformat (input, "tag1 %U", unformat_vlan_tag, tag1_val)) + tag1 = 1; + else if (unformat (input, "tag2 %U", unformat_vlan_tag, tag2_val)) + tag2 = 1; + else if (unformat (input, "ignore-tag1")) + ignore_tag1 = 1; + else if (unformat (input, "ignore-tag2")) + ignore_tag2 = 1; + else if (unformat (input, "cos1 %d", &cos1_val)) + cos1 = 1; + else if (unformat (input, "cos2 %d", &cos2_val)) + cos2 = 1; + else + break; + } + if ((src + dst + proto + tag1 + tag2 + + ignore_tag1 + ignore_tag2 + cos1 + cos2) == 0) + return 0; + + if (tag1 || ignore_tag1 || cos1) + len = 18; + if (tag2 || ignore_tag2 || cos2) + len = 22; + + vec_validate_aligned (match, len - 1, sizeof (u32x4)); + + if (dst) + clib_memcpy (match, dst_val, 6); + + if (src) + clib_memcpy (match + 6, src_val, 6); + + if (tag2) + { + /* inner vlan tag */ + match[19] = tag2_val[1]; + match[18] = tag2_val[0]; + if (cos2) + match[18] |= (cos2_val & 0x7) << 5; + if (proto) + { + match[21] = proto_val & 0xff; + match[20] = proto_val >> 8; + } + if (tag1) + { + match[15] = tag1_val[1]; + match[14] = tag1_val[0]; + } + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + *matchp = match; + return 1; + } + if (tag1) + { + match[15] = tag1_val[1]; + match[14] = tag1_val[0]; + if (proto) + { + match[17] = proto_val & 0xff; + match[16] = proto_val >> 8; + } + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + + *matchp = match; + return 1; + } + if (cos2) + match[18] |= (cos2_val & 0x7) << 5; + if (cos1) + match[14] |= (cos1_val & 0x7) << 5; + if (proto) + { + match[13] = proto_val & 0xff; + match[12] = proto_val >> 8; + } + + *matchp = match; + return 1; +} + + +uword +unformat_classify_match (unformat_input_t * input, va_list * args) +{ + u8 **matchp = va_arg (*args, u8 **); + u32 skip_n_vectors = va_arg (*args, u32); + u32 match_n_vectors = va_arg (*args, u32); + + u8 *match = 0; + u8 *l2 = 0; + u8 *l3 = 0; + u8 *l4 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "hex %U", unformat_hex_string, &match)) + ; + else if (unformat (input, "l2 %U", unformat_l2_match, &l2)) + ; + else if (unformat (input, "l3 %U", unformat_l3_match, &l3)) + ; + else if (unformat (input, "l4 %U", unformat_l4_match, &l4)) + ; + else + break; + } + + if (l4 && !l3) + { + vec_free (match); + vec_free (l2); + vec_free (l4); + return 0; + } + + if (match || l2 || l3 || l4) + { + if (l2 || l3 || l4) + { + /* "Win a free Ethernet header in every packet" */ + if (l2 == 0) + vec_validate_aligned (l2, 13, sizeof (u32x4)); + match = l2; + if (vec_len (l3)) + { + vec_append_aligned (match, l3, sizeof (u32x4)); + vec_free (l3); + } + if (vec_len (l4)) + { + vec_append_aligned (match, l4, sizeof (u32x4)); + vec_free (l4); + } + } + + /* Make sure the vector is big enough even if key is all 0's */ + vec_validate_aligned + (match, ((match_n_vectors + skip_n_vectors) * sizeof (u32x4)) - 1, + sizeof (u32x4)); + + /* Set size, include skipped vectors */ + _vec_len (match) = (match_n_vectors + skip_n_vectors) * sizeof (u32x4); + + *matchp = match; + + return 1; + } + + return 0; +} + +static int +api_classify_add_del_session (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_add_del_session_t *mp; + int is_add = 1; + u32 table_index = ~0; + u32 hit_next_index = ~0; + u32 opaque_index = ~0; + u8 *match = 0; + i32 advance = 0; + f64 timeout; + u32 skip_n_vectors = 0; + u32 match_n_vectors = 0; + u32 action = 0; + u32 metadata = 0; + + /* + * Warning: you have to supply skip_n and match_n + * because the API client cant simply look at the classify + * table object. + */ + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "hit-next %U", unformat_ip_next_index, + &hit_next_index)) + ; + else if (unformat (i, "l2-hit-next %U", unformat_l2_next_index, + &hit_next_index)) + ; + else if (unformat (i, "acl-hit-next %U", unformat_acl_next_index, + &hit_next_index)) + ; + else if (unformat (i, "policer-hit-next %d", &hit_next_index)) + ; + else if (unformat (i, "%U", unformat_policer_precolor, &opaque_index)) + ; + else if (unformat (i, "opaque-index %d", &opaque_index)) + ; + else if (unformat (i, "skip_n %d", &skip_n_vectors)) + ; + else if (unformat (i, "match_n %d", &match_n_vectors)) + ; + else if (unformat (i, "match %U", unformat_classify_match, + &match, skip_n_vectors, match_n_vectors)) + ; + else if (unformat (i, "advance %d", &advance)) + ; + else if (unformat (i, "table-index %d", &table_index)) + ; + else if (unformat (i, "action set-ip4-fib-id %d", &metadata)) + action = 1; + else if (unformat (i, "action set-ip6-fib-id %d", &metadata)) + action = 2; + else if (unformat (i, "action %d", &action)) + ; + else if (unformat (i, "metadata %d", &metadata)) + ; + else + break; + } + + if (table_index == ~0) + { + errmsg ("Table index required"); + return -99; + } + + if (is_add && match == 0) + { + errmsg ("Match value required"); + return -99; + } + + M2 (CLASSIFY_ADD_DEL_SESSION, classify_add_del_session, vec_len (match)); + + mp->is_add = is_add; + mp->table_index = ntohl (table_index); + mp->hit_next_index = ntohl (hit_next_index); + mp->opaque_index = ntohl (opaque_index); + mp->advance = ntohl (advance); + mp->action = action; + mp->metadata = ntohl (metadata); + clib_memcpy (mp->match, match, vec_len (match)); + vec_free (match); + + S; + W; + /* NOTREACHED */ +} + +static int +api_classify_set_interface_ip_table (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_set_interface_ip_table_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 table_index = ~0; + u8 is_ipv6 = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "table %d", &table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + + M (CLASSIFY_SET_INTERFACE_IP_TABLE, classify_set_interface_ip_table); + + mp->sw_if_index = ntohl (sw_if_index); + mp->table_index = ntohl (table_index); + mp->is_ipv6 = is_ipv6; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_classify_set_interface_l2_tables (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_classify_set_interface_l2_tables_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 other_table_index = ~0; + u32 is_input = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "other-table %d", &other_table_index)) + ; + else if (unformat (i, "is-input %d", &is_input)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + + M (CLASSIFY_SET_INTERFACE_L2_TABLES, classify_set_interface_l2_tables); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->other_table_index = ntohl (other_table_index); + mp->is_input = (u8) is_input; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_set_ipfix_exporter (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ipfix_exporter_t *mp; + ip4_address_t collector_address; + u8 collector_address_set = 0; + u32 collector_port = ~0; + ip4_address_t src_address; + u8 src_address_set = 0; + u32 vrf_id = ~0; + u32 path_mtu = ~0; + u32 template_interval = ~0; + u8 udp_checksum = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "collector_address %U", unformat_ip4_address, + &collector_address)) + collector_address_set = 1; + else if (unformat (i, "collector_port %d", &collector_port)) + ; + else if (unformat (i, "src_address %U", unformat_ip4_address, + &src_address)) + src_address_set = 1; + else if (unformat (i, "vrf_id %d", &vrf_id)) + ; + else if (unformat (i, "path_mtu %d", &path_mtu)) + ; + else if (unformat (i, "template_interval %d", &template_interval)) + ; + else if (unformat (i, "udp_checksum")) + udp_checksum = 1; + else + break; + } + + if (collector_address_set == 0) + { + errmsg ("collector_address required"); + return -99; + } + + if (src_address_set == 0) + { + errmsg ("src_address required"); + return -99; + } + + M (SET_IPFIX_EXPORTER, set_ipfix_exporter); + + memcpy (mp->collector_address, collector_address.data, + sizeof (collector_address.data)); + mp->collector_port = htons ((u16) collector_port); + memcpy (mp->src_address, src_address.data, sizeof (src_address.data)); + mp->vrf_id = htonl (vrf_id); + mp->path_mtu = htonl (path_mtu); + mp->template_interval = htonl (template_interval); + mp->udp_checksum = udp_checksum; + + S; + W; + /* NOTREACHED */ +} + +static int +api_set_ipfix_classify_stream (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_set_ipfix_classify_stream_t *mp; + u32 domain_id = 0; + u32 src_port = UDP_DST_PORT_ipfix; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "domain %d", &domain_id)) + ; + else if (unformat (i, "src_port %d", &src_port)) + ; + else + { + errmsg ("unknown input `%U'", format_unformat_error, i); + return -99; + } + } + + M (SET_IPFIX_CLASSIFY_STREAM, set_ipfix_classify_stream); + + mp->domain_id = htonl (domain_id); + mp->src_port = htons ((u16) src_port); + + S; + W; + /* NOTREACHED */ +} + +static int +api_ipfix_classify_table_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipfix_classify_table_add_del_t *mp; + int is_add = -1; + u32 classify_table_index = ~0; + u8 ip_version = 0; + u8 transport_protocol = 255; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "add")) + is_add = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "table %d", &classify_table_index)) + ; + else if (unformat (i, "ip4")) + ip_version = 4; + else if (unformat (i, "ip6")) + ip_version = 6; + else if (unformat (i, "tcp")) + transport_protocol = 6; + else if (unformat (i, "udp")) + transport_protocol = 17; + else + { + errmsg ("unknown input `%U'", format_unformat_error, i); + return -99; + } + } + + if (is_add == -1) + { + errmsg ("expecting: add|del"); + return -99; + } + if (classify_table_index == ~0) + { + errmsg ("classifier table not specified"); + return -99; + } + if (ip_version == 0) + { + errmsg ("IP version not specified"); + return -99; + } + + M (IPFIX_CLASSIFY_TABLE_ADD_DEL, ipfix_classify_table_add_del); + + mp->is_add = is_add; + mp->table_id = htonl (classify_table_index); + mp->ip_version = ip_version; + mp->transport_protocol = transport_protocol; + + S; + W; + /* NOTREACHED */ +} + +static int +api_get_node_index (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_node_index_t *mp; + f64 timeout; + u8 *name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + M (GET_NODE_INDEX, get_node_index); + clib_memcpy (mp->node_name, name, vec_len (name)); + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_get_next_index (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_get_next_index_t *mp; + f64 timeout; + u8 *node_name = 0, *next_node_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node-name %s", &node_name)) + ; + else if (unformat (i, "next-node-name %s", &next_node_name)) + break; + } + + if (node_name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (node_name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + + if (next_node_name == 0) + { + errmsg ("next node name required"); + return -99; + } + if (vec_len (next_node_name) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next node name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (GET_NEXT_INDEX, get_next_index); + clib_memcpy (mp->node_name, node_name, vec_len (node_name)); + clib_memcpy (mp->next_name, next_node_name, vec_len (next_node_name)); + vec_free (node_name); + vec_free (next_node_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_add_node_next (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_add_node_next_t *mp; + f64 timeout; + u8 *name = 0; + u8 *next = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "node %s", &name)) + ; + else if (unformat (i, "next %s", &next)) + ; + else + break; + } + if (name == 0) + { + errmsg ("node name required"); + return -99; + } + if (vec_len (name) >= ARRAY_LEN (mp->node_name)) + { + errmsg ("node name too long, max %d", ARRAY_LEN (mp->node_name)); + return -99; + } + if (next == 0) + { + errmsg ("next node required"); + return -99; + } + if (vec_len (next) >= ARRAY_LEN (mp->next_name)) + { + errmsg ("next name too long, max %d", ARRAY_LEN (mp->next_name)); + return -99; + } + + M (ADD_NODE_NEXT, add_node_next); + clib_memcpy (mp->node_name, name, vec_len (name)); + clib_memcpy (mp->next_name, next, vec_len (next)); + vec_free (name); + vec_free (next); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_create_tunnel (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + ip6_address_t client_address, our_address; + int client_address_set = 0; + int our_address_set = 0; + u32 local_session_id = 0; + u32 remote_session_id = 0; + u64 local_cookie = 0; + u64 remote_cookie = 0; + u8 l2_sublayer_present = 0; + vl_api_l2tpv3_create_tunnel_t *mp; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "client_address %U", unformat_ip6_address, + &client_address)) + client_address_set = 1; + else if (unformat (i, "our_address %U", unformat_ip6_address, + &our_address)) + our_address_set = 1; + else if (unformat (i, "local_session_id %d", &local_session_id)) + ; + else if (unformat (i, "remote_session_id %d", &remote_session_id)) + ; + else if (unformat (i, "local_cookie %lld", &local_cookie)) + ; + else if (unformat (i, "remote_cookie %lld", &remote_cookie)) + ; + else if (unformat (i, "l2-sublayer-present")) + l2_sublayer_present = 1; + else + break; + } + + if (client_address_set == 0) + { + errmsg ("client_address required"); + return -99; + } + + if (our_address_set == 0) + { + errmsg ("our_address required"); + return -99; + } + + M (L2TPV3_CREATE_TUNNEL, l2tpv3_create_tunnel); + + clib_memcpy (mp->client_address, client_address.as_u8, + sizeof (mp->client_address)); + + clib_memcpy (mp->our_address, our_address.as_u8, sizeof (mp->our_address)); + + mp->local_session_id = ntohl (local_session_id); + mp->remote_session_id = ntohl (remote_session_id); + mp->local_cookie = clib_host_to_net_u64 (local_cookie); + mp->remote_cookie = clib_host_to_net_u64 (remote_cookie); + mp->l2_sublayer_present = l2_sublayer_present; + mp->is_ipv6 = 1; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_set_tunnel_cookies (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u64 new_local_cookie = 0; + u64 new_remote_cookie = 0; + vl_api_l2tpv3_set_tunnel_cookies_t *mp; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "new_local_cookie %lld", &new_local_cookie)) + ; + else if (unformat (i, "new_remote_cookie %lld", &new_remote_cookie)) + ; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_SET_TUNNEL_COOKIES, l2tpv3_set_tunnel_cookies); + + mp->sw_if_index = ntohl (sw_if_index); + mp->new_local_cookie = clib_host_to_net_u64 (new_local_cookie); + mp->new_remote_cookie = clib_host_to_net_u64 (new_remote_cookie); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_interface_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_interface_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 enable_disable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + enable_disable = 1; + else if (unformat (i, "disable")) + enable_disable = 0; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (L2TPV3_INTERFACE_ENABLE_DISABLE, l2tpv3_interface_enable_disable); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable_disable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2tpv3_set_lookup_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2tpv3_set_lookup_key_t *mp; + f64 timeout; + u8 key = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "lookup_v6_src")) + key = L2T_LOOKUP_SRC_ADDRESS; + else if (unformat (i, "lookup_v6_dst")) + key = L2T_LOOKUP_DST_ADDRESS; + else if (unformat (i, "lookup_session_id")) + key = L2T_LOOKUP_SESSION_ID; + else + break; + } + + if (key == (u8) ~ 0) + { + errmsg ("l2tp session lookup key unset"); + return -99; + } + + M (L2TPV3_SET_LOOKUP_KEY, l2tpv3_set_lookup_key); + + mp->key = key; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler + (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "* %U (our) %U (client) (sw_if_index %d)", + format_ip6_address, mp->our_address, + format_ip6_address, mp->client_address, + clib_net_to_host_u32 (mp->sw_if_index)); + + print (vam->ofp, + " local cookies %016llx %016llx remote cookie %016llx", + clib_net_to_host_u64 (mp->local_cookie[0]), + clib_net_to_host_u64 (mp->local_cookie[1]), + clib_net_to_host_u64 (mp->remote_cookie)); + + print (vam->ofp, " local session-id %d remote session-id %d", + clib_net_to_host_u32 (mp->local_session_id), + clib_net_to_host_u32 (mp->remote_session_id)); + + print (vam->ofp, " l2 specific sublayer %s\n", + mp->l2_sublayer_present ? "preset" : "absent"); + +} + +static void vl_api_sw_if_l2tpv3_tunnel_details_t_handler_json + (vl_api_sw_if_l2tpv3_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in6_addr addr; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + + clib_memcpy (&addr, mp->our_address, sizeof (addr)); + vat_json_object_add_ip6 (node, "our_address", addr); + clib_memcpy (&addr, mp->client_address, sizeof (addr)); + vat_json_object_add_ip6 (node, "client_address", addr); + + vat_json_node_t *lc = vat_json_object_add (node, "local_cookie"); + vat_json_init_array (lc); + vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[0])); + vat_json_array_add_uint (lc, clib_net_to_host_u64 (mp->local_cookie[1])); + vat_json_object_add_uint (node, "remote_cookie", + clib_net_to_host_u64 (mp->remote_cookie)); + + printf ("local id: %u", clib_net_to_host_u32 (mp->local_session_id)); + vat_json_object_add_uint (node, "local_session_id", + clib_net_to_host_u32 (mp->local_session_id)); + vat_json_object_add_uint (node, "remote_session_id", + clib_net_to_host_u32 (mp->remote_session_id)); + vat_json_object_add_string_copy (node, "l2_sublayer", + mp->l2_sublayer_present ? (u8 *) "present" + : (u8 *) "absent"); +} + +static int +api_sw_if_l2tpv3_tunnel_dump (vat_main_t * vam) +{ + vl_api_sw_if_l2tpv3_tunnel_dump_t *mp; + f64 timeout; + + /* Get list of l2tpv3-tunnel interfaces */ + M (SW_IF_L2TPV3_TUNNEL_DUMP, sw_if_l2tpv3_tunnel_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + + +static void vl_api_sw_interface_tap_details_t_handler + (vl_api_sw_interface_tap_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%-16s %d", + mp->dev_name, clib_net_to_host_u32 (mp->sw_if_index)); +} + +static void vl_api_sw_interface_tap_details_t_handler_json + (vl_api_sw_interface_tap_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_string_copy (node, "dev_name", mp->dev_name); +} + +static int +api_sw_interface_tap_dump (vat_main_t * vam) +{ + vl_api_sw_interface_tap_dump_t *mp; + f64 timeout; + + print (vam->ofp, "\n%-16s %s", "dev_name", "sw_if_index"); + /* Get list of tap interfaces */ + M (SW_INTERFACE_TAP_DUMP, sw_interface_tap_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static uword unformat_vxlan_decap_next + (unformat_input_t * input, va_list * args) +{ + u32 *result = va_arg (*args, u32 *); + u32 tmp; + + if (unformat (input, "l2")) + *result = VXLAN_INPUT_NEXT_L2_INPUT; + else if (unformat (input, "%d", &tmp)) + *result = tmp; + else + return 0; + return 1; +} + +static int +api_vxlan_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_vxlan_add_del_tunnel_t *mp; + f64 timeout; + ip46_address_t src, dst; + u8 is_add = 1; + u8 ipv4_set = 0, ipv6_set = 0; + u8 src_set = 0; + u8 dst_set = 0; + u8 grp_set = 0; + u32 mcast_sw_if_index = ~0; + u32 encap_vrf_id = 0; + u32 decap_next_index = ~0; + u32 vni = 0; + + /* Can't "universally zero init" (={0}) due to GCC bug 53119 */ + memset (&src, 0, sizeof src); + memset (&dst, 0, sizeof dst); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else + if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4)) + { + ipv4_set = 1; + src_set = 1; + } + else + if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4)) + { + ipv4_set = 1; + dst_set = 1; + } + else + if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6)) + { + ipv6_set = 1; + src_set = 1; + } + else + if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6)) + { + ipv6_set = 1; + dst_set = 1; + } + else if (unformat (line_input, "group %U %U", + unformat_ip4_address, &dst.ip4, + api_unformat_sw_if_index, vam, &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "group %U", + unformat_ip4_address, &dst.ip4)) + { + grp_set = dst_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "group %U %U", + unformat_ip6_address, &dst.ip6, + api_unformat_sw_if_index, vam, &mcast_sw_if_index)) + { + grp_set = dst_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "group %U", + unformat_ip6_address, &dst.ip6)) + { + grp_set = dst_set = 1; + ipv6_set = 1; + } + else + if (unformat (line_input, "mcast_sw_if_index %u", &mcast_sw_if_index)) + ; + else if (unformat (line_input, "encap-vrf-id %d", &encap_vrf_id)) + ; + else if (unformat (line_input, "decap-next %U", + unformat_vxlan_decap_next, &decap_next_index)) + ; + else if (unformat (line_input, "vni %d", &vni)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("tunnel src address not specified"); + return -99; + } + if (dst_set == 0) + { + errmsg ("tunnel dst address not specified"); + return -99; + } + + if (grp_set && !ip46_address_is_multicast (&dst)) + { + errmsg ("tunnel group address not multicast"); + return -99; + } + if (grp_set && mcast_sw_if_index == ~0) + { + errmsg ("tunnel nonexistent multicast device"); + return -99; + } + if (grp_set == 0 && ip46_address_is_multicast (&dst)) + { + errmsg ("tunnel dst address must be unicast"); + return -99; + } + + + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if ((vni == 0) || (vni >> 24)) + { + errmsg ("vni not specified or out of range"); + return -99; + } + + M (VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel); + + if (ipv6_set) + { + clib_memcpy (mp->src_address, &src.ip6, sizeof (src.ip6)); + clib_memcpy (mp->dst_address, &dst.ip6, sizeof (dst.ip6)); + } + else + { + clib_memcpy (mp->src_address, &src.ip4, sizeof (src.ip4)); + clib_memcpy (mp->dst_address, &dst.ip4, sizeof (dst.ip4)); + } + mp->encap_vrf_id = ntohl (encap_vrf_id); + mp->decap_next_index = ntohl (decap_next_index); + mp->mcast_sw_if_index = ntohl (mcast_sw_if_index); + mp->vni = ntohl (vni); + mp->is_add = is_add; + mp->is_ipv6 = ipv6_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_vxlan_tunnel_details_t_handler + (vl_api_vxlan_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + ip46_address_t src, dst; + + ip46_from_addr_buf (mp->is_ipv6, mp->src_address, &src); + ip46_from_addr_buf (mp->is_ipv6, mp->dst_address, &dst); + + print (vam->ofp, "%11d%24U%24U%14d%18d%13d%19d", + ntohl (mp->sw_if_index), + format_ip46_address, &src, IP46_TYPE_ANY, + format_ip46_address, &dst, IP46_TYPE_ANY, + ntohl (mp->encap_vrf_id), + ntohl (mp->decap_next_index), ntohl (mp->vni), + ntohl (mp->mcast_sw_if_index)); +} + +static void vl_api_vxlan_tunnel_details_t_handler_json + (vl_api_vxlan_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + if (mp->is_ipv6) + { + struct in6_addr ip6; + + clib_memcpy (&ip6, mp->src_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "src_address", ip6); + clib_memcpy (&ip6, mp->dst_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "dst_address", ip6); + } + else + { + struct in_addr ip4; + + clib_memcpy (&ip4, mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + } + vat_json_object_add_uint (node, "encap_vrf_id", ntohl (mp->encap_vrf_id)); + vat_json_object_add_uint (node, "decap_next_index", + ntohl (mp->decap_next_index)); + vat_json_object_add_uint (node, "vni", ntohl (mp->vni)); + vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6 ? 1 : 0); + vat_json_object_add_uint (node, "mcast_sw_if_index", + ntohl (mp->mcast_sw_if_index)); +} + +static int +api_vxlan_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_vxlan_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%24s%24s%14s%18s%13s%19s", + "sw_if_index", "src_address", "dst_address", + "encap_vrf_id", "decap_next_index", "vni", "mcast_sw_if_index"); + } + + /* Get list of vxlan-tunnel interfaces */ + M (VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_gre_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_gre_add_del_tunnel_t *mp; + f64 timeout; + ip4_address_t src4, dst4; + u8 is_add = 1; + u8 teb = 0; + u8 src_set = 0; + u8 dst_set = 0; + u32 outer_fib_id = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "src %U", unformat_ip4_address, &src4)) + src_set = 1; + else if (unformat (line_input, "dst %U", unformat_ip4_address, &dst4)) + dst_set = 1; + else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id)) + ; + else if (unformat (line_input, "teb")) + teb = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (src_set == 0) + { + errmsg ("tunnel src address not specified"); + return -99; + } + if (dst_set == 0) + { + errmsg ("tunnel dst address not specified"); + return -99; + } + + + M (GRE_ADD_DEL_TUNNEL, gre_add_del_tunnel); + + clib_memcpy (&mp->src_address, &src4, sizeof (src4)); + clib_memcpy (&mp->dst_address, &dst4, sizeof (dst4)); + mp->outer_fib_id = ntohl (outer_fib_id); + mp->is_add = is_add; + mp->teb = teb; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_gre_tunnel_details_t_handler + (vl_api_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%15U%15U%6d%14d", + ntohl (mp->sw_if_index), + format_ip4_address, &mp->src_address, + format_ip4_address, &mp->dst_address, + mp->teb, ntohl (mp->outer_fib_id)); +} + +static void vl_api_gre_tunnel_details_t_handler_json + (vl_api_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + clib_memcpy (&ip4, &mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + vat_json_object_add_uint (node, "teb", mp->teb); + vat_json_object_add_uint (node, "outer_fib_id", ntohl (mp->outer_fib_id)); +} + +static int +api_gre_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_gre_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%15s%15s%6s%14s", + "sw_if_index", "src_address", "dst_address", "teb", + "outer_fib_id"); + } + + /* Get list of gre-tunnel interfaces */ + M (GRE_TUNNEL_DUMP, gre_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_l2_fib_clear_table (vat_main_t * vam) +{ +// unformat_input_t * i = vam->input; + vl_api_l2_fib_clear_table_t *mp; + f64 timeout; + + M (L2_FIB_CLEAR_TABLE, l2_fib_clear_table); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_l2_interface_efp_filter (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_efp_filter_t *mp; + f64 timeout; + u32 sw_if_index; + u8 enable = 1; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "enable")) + enable = 1; + else if (unformat (i, "disable")) + enable = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + M (L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter); + + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable; + + S; + W; + /* NOTREACHED */ + return 0; +} + +#define foreach_vtr_op \ +_("disable", L2_VTR_DISABLED) \ +_("push-1", L2_VTR_PUSH_1) \ +_("push-2", L2_VTR_PUSH_2) \ +_("pop-1", L2_VTR_POP_1) \ +_("pop-2", L2_VTR_POP_2) \ +_("translate-1-1", L2_VTR_TRANSLATE_1_1) \ +_("translate-1-2", L2_VTR_TRANSLATE_1_2) \ +_("translate-2-1", L2_VTR_TRANSLATE_2_1) \ +_("translate-2-2", L2_VTR_TRANSLATE_2_2) + +static int +api_l2_interface_vlan_tag_rewrite (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_vlan_tag_rewrite_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u8 vtr_op_set = 0; + u32 vtr_op = 0; + u32 push_dot1q = 1; + u32 tag1 = ~0; + u32 tag2 = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "vtr_op %d", &vtr_op)) + vtr_op_set = 1; +#define _(n,v) else if (unformat(i, n)) {vtr_op = v; vtr_op_set = 1;} + foreach_vtr_op +#undef _ + else if (unformat (i, "push_dot1q %d", &push_dot1q)) + ; + else if (unformat (i, "tag1 %d", &tag1)) + ; + else if (unformat (i, "tag2 %d", &tag2)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if ((sw_if_index_set == 0) || (vtr_op_set == 0)) + { + errmsg ("missing vtr operation or sw_if_index"); + return -99; + } + + M (L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) + mp->sw_if_index = ntohl (sw_if_index); + mp->vtr_op = ntohl (vtr_op); + mp->push_dot1q = ntohl (push_dot1q); + mp->tag1 = ntohl (tag1); + mp->tag2 = ntohl (tag2); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_create_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_create_vhost_user_if_t *mp; + f64 timeout; + u8 *file_name; + u8 is_server = 0; + u8 file_name_set = 0; + u32 custom_dev_instance = ~0; + u8 hwaddr[6]; + u8 use_custom_mac = 0; + u8 *tag = 0; + + /* Shut up coverity */ + memset (hwaddr, 0, sizeof (hwaddr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "socket %s", &file_name)) + { + file_name_set = 1; + } + else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance)) + ; + else if (unformat (i, "mac %U", unformat_ethernet_address, hwaddr)) + use_custom_mac = 1; + else if (unformat (i, "server")) + is_server = 1; + else if (unformat (i, "tag %s", &tag)) + ; + else + break; + } + + if (file_name_set == 0) + { + errmsg ("missing socket file name"); + return -99; + } + + if (vec_len (file_name) > 255) + { + errmsg ("socket file name too long"); + return -99; + } + vec_add1 (file_name, 0); + + M (CREATE_VHOST_USER_IF, create_vhost_user_if); + + mp->is_server = is_server; + clib_memcpy (mp->sock_filename, file_name, vec_len (file_name)); + vec_free (file_name); + if (custom_dev_instance != ~0) + { + mp->renumber = 1; + mp->custom_dev_instance = ntohl (custom_dev_instance); + } + mp->use_custom_mac = use_custom_mac; + clib_memcpy (mp->mac_address, hwaddr, 6); + if (tag) + strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1); + vec_free (tag); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_modify_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_modify_vhost_user_if_t *mp; + f64 timeout; + u8 *file_name; + u8 is_server = 0; + u8 file_name_set = 0; + u32 custom_dev_instance = ~0; + u8 sw_if_index_set = 0; + u32 sw_if_index = (u32) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "socket %s", &file_name)) + { + file_name_set = 1; + } + else if (unformat (i, "renumber %" PRIu32, &custom_dev_instance)) + ; + else if (unformat (i, "server")) + is_server = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index or interface name"); + return -99; + } + + if (file_name_set == 0) + { + errmsg ("missing socket file name"); + return -99; + } + + if (vec_len (file_name) > 255) + { + errmsg ("socket file name too long"); + return -99; + } + vec_add1 (file_name, 0); + + M (MODIFY_VHOST_USER_IF, modify_vhost_user_if); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_server = is_server; + clib_memcpy (mp->sock_filename, file_name, vec_len (file_name)); + vec_free (file_name); + if (custom_dev_instance != ~0) + { + mp->renumber = 1; + mp->custom_dev_instance = ntohl (custom_dev_instance); + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_delete_vhost_user_if (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_vhost_user_if_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing sw_if_index or interface name"); + return -99; + } + + + M (DELETE_VHOST_USER_IF, delete_vhost_user_if); + + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_sw_interface_vhost_user_details_t_handler + (vl_api_sw_interface_vhost_user_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%-25s %3" PRIu32 " %6" PRIu32 " %8x %6d %7d %s", + (char *) mp->interface_name, + ntohl (mp->sw_if_index), ntohl (mp->virtio_net_hdr_sz), + clib_net_to_host_u64 (mp->features), mp->is_server, + ntohl (mp->num_regions), (char *) mp->sock_filename); + print (vam->ofp, " Status: '%s'", strerror (ntohl (mp->sock_errno))); +} + +static void vl_api_sw_interface_vhost_user_details_t_handler_json + (vl_api_sw_interface_vhost_user_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_string_copy (node, "interface_name", + mp->interface_name); + vat_json_object_add_uint (node, "virtio_net_hdr_sz", + ntohl (mp->virtio_net_hdr_sz)); + vat_json_object_add_uint (node, "features", + clib_net_to_host_u64 (mp->features)); + vat_json_object_add_uint (node, "is_server", mp->is_server); + vat_json_object_add_string_copy (node, "sock_filename", mp->sock_filename); + vat_json_object_add_uint (node, "num_regions", ntohl (mp->num_regions)); + vat_json_object_add_uint (node, "sock_errno", ntohl (mp->sock_errno)); +} + +static int +api_sw_interface_vhost_user_dump (vat_main_t * vam) +{ + vl_api_sw_interface_vhost_user_dump_t *mp; + f64 timeout; + print (vam->ofp, + "Interface name idx hdr_sz features server regions filename"); + + /* Get list of vhost-user interfaces */ + M (SW_INTERFACE_VHOST_USER_DUMP, sw_interface_vhost_user_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_show_version (vat_main_t * vam) +{ + vl_api_show_version_t *mp; + f64 timeout; + + M (SHOW_VERSION, show_version); + + S; + W; + /* NOTREACHED */ + return 0; +} + + +static int +api_vxlan_gpe_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_vxlan_gpe_add_del_tunnel_t *mp; + f64 timeout; + ip4_address_t local4, remote4; + ip6_address_t local6, remote6; + u8 is_add = 1; + u8 ipv4_set = 0, ipv6_set = 0; + u8 local_set = 0; + u8 remote_set = 0; + u32 encap_vrf_id = 0; + u32 decap_vrf_id = 0; + u8 protocol = ~0; + u32 vni; + u8 vni_set = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + else if (unformat (line_input, "local %U", + unformat_ip4_address, &local4)) + { + local_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip4_address, &remote4)) + { + remote_set = 1; + ipv4_set = 1; + } + else if (unformat (line_input, "local %U", + unformat_ip6_address, &local6)) + { + local_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "remote %U", + unformat_ip6_address, &remote6)) + { + remote_set = 1; + ipv6_set = 1; + } + else if (unformat (line_input, "encap-vrf-id %d", &encap_vrf_id)) + ; + else if (unformat (line_input, "decap-vrf-id %d", &decap_vrf_id)) + ; + else if (unformat (line_input, "vni %d", &vni)) + vni_set = 1; + else if (unformat (line_input, "next-ip4")) + protocol = 1; + else if (unformat (line_input, "next-ip6")) + protocol = 2; + else if (unformat (line_input, "next-ethernet")) + protocol = 3; + else if (unformat (line_input, "next-nsh")) + protocol = 4; + else + { + errmsg ("parse error '%U'", format_unformat_error, line_input); + return -99; + } + } + + if (local_set == 0) + { + errmsg ("tunnel local address not specified"); + return -99; + } + if (remote_set == 0) + { + errmsg ("tunnel remote address not specified"); + return -99; + } + if (ipv4_set && ipv6_set) + { + errmsg ("both IPv4 and IPv6 addresses specified"); + return -99; + } + + if (vni_set == 0) + { + errmsg ("vni not specified"); + return -99; + } + + M (VXLAN_GPE_ADD_DEL_TUNNEL, vxlan_gpe_add_del_tunnel); + + + if (ipv6_set) + { + clib_memcpy (&mp->local, &local6, sizeof (local6)); + clib_memcpy (&mp->remote, &remote6, sizeof (remote6)); + } + else + { + clib_memcpy (&mp->local, &local4, sizeof (local4)); + clib_memcpy (&mp->remote, &remote4, sizeof (remote4)); + } + + mp->encap_vrf_id = ntohl (encap_vrf_id); + mp->decap_vrf_id = ntohl (decap_vrf_id); + mp->protocol = protocol; + mp->vni = ntohl (vni); + mp->is_add = is_add; + mp->is_ipv6 = ipv6_set; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_vxlan_gpe_tunnel_details_t_handler + (vl_api_vxlan_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%24U%24U%13d%12d%14d%14d", + ntohl (mp->sw_if_index), + format_ip46_address, &(mp->local[0]), + format_ip46_address, &(mp->remote[0]), + ntohl (mp->vni), + ntohl (mp->protocol), + ntohl (mp->encap_vrf_id), ntohl (mp->decap_vrf_id)); +} + +static void vl_api_vxlan_gpe_tunnel_details_t_handler_json + (vl_api_vxlan_gpe_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + if (mp->is_ipv6) + { + clib_memcpy (&ip6, &(mp->local[0]), sizeof (ip6)); + vat_json_object_add_ip6 (node, "local", ip6); + clib_memcpy (&ip6, &(mp->remote[0]), sizeof (ip6)); + vat_json_object_add_ip6 (node, "remote", ip6); + } + else + { + clib_memcpy (&ip4, &(mp->local[0]), sizeof (ip4)); + vat_json_object_add_ip4 (node, "local", ip4); + clib_memcpy (&ip4, &(mp->remote[0]), sizeof (ip4)); + vat_json_object_add_ip4 (node, "remote", ip4); + } + vat_json_object_add_uint (node, "vni", ntohl (mp->vni)); + vat_json_object_add_uint (node, "protocol", ntohl (mp->protocol)); + vat_json_object_add_uint (node, "encap_vrf_id", ntohl (mp->encap_vrf_id)); + vat_json_object_add_uint (node, "decap_vrf_id", ntohl (mp->decap_vrf_id)); + vat_json_object_add_uint (node, "is_ipv6", mp->is_ipv6 ? 1 : 0); +} + +static int +api_vxlan_gpe_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_vxlan_gpe_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%24s%24s%13s%15s%14s%14s", + "sw_if_index", "local", "remote", "vni", + "protocol", "encap_vrf_id", "decap_vrf_id"); + } + + /* Get list of vxlan-tunnel interfaces */ + M (VXLAN_GPE_TUNNEL_DUMP, vxlan_gpe_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +u8 * +format_l2_fib_mac_address (u8 * s, va_list * args) +{ + u8 *a = va_arg (*args, u8 *); + + return format (s, "%02x:%02x:%02x:%02x:%02x:%02x", + a[2], a[3], a[4], a[5], a[6], a[7]); +} + +static void vl_api_l2_fib_table_entry_t_handler + (vl_api_l2_fib_table_entry_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%3" PRIu32 " %U %3" PRIu32 + " %d %d %d", + ntohl (mp->bd_id), format_l2_fib_mac_address, &mp->mac, + ntohl (mp->sw_if_index), mp->static_mac, mp->filter_mac, + mp->bvi_mac); +} + +static void vl_api_l2_fib_table_entry_t_handler_json + (vl_api_l2_fib_table_entry_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "bd_id", ntohl (mp->bd_id)); + vat_json_object_add_uint (node, "mac", clib_net_to_host_u64 (mp->mac)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "static_mac", mp->static_mac); + vat_json_object_add_uint (node, "filter_mac", mp->filter_mac); + vat_json_object_add_uint (node, "bvi_mac", mp->bvi_mac); +} + +static int +api_l2_fib_table_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_fib_table_dump_t *mp; + f64 timeout; + u32 bd_id; + u8 bd_id_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "bd_id %d", &bd_id)) + bd_id_set = 1; + else + break; + } + + if (bd_id_set == 0) + { + errmsg ("missing bridge domain"); + return -99; + } + + print (vam->ofp, "BD-ID Mac Address sw-ndx Static Filter BVI"); + + /* Get list of l2 fib entries */ + M (L2_FIB_TABLE_DUMP, l2_fib_table_dump); + + mp->bd_id = ntohl (bd_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + + +static int +api_interface_name_renumber (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_interface_name_renumber_t *mp; + u32 sw_if_index = ~0; + f64 timeout; + u32 new_show_dev_instance = ~0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", api_unformat_sw_if_index, vam, + &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "new_show_dev_instance %d", + &new_show_dev_instance)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (new_show_dev_instance == ~0) + { + errmsg ("missing new_show_dev_instance"); + return -99; + } + + M (INTERFACE_NAME_RENUMBER, interface_name_renumber); + + mp->sw_if_index = ntohl (sw_if_index); + mp->new_show_dev_instance = ntohl (new_show_dev_instance); + + S; + W; +} + +static int +api_want_ip4_arp_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_ip4_arp_events_t *mp; + f64 timeout; + ip4_address_t address; + int address_set = 0; + u32 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "address %U", unformat_ip4_address, &address)) + address_set = 1; + else if (unformat (line_input, "del")) + enable_disable = 0; + else + break; + } + + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + M (WANT_IP4_ARP_EVENTS, want_ip4_arp_events); + mp->enable_disable = enable_disable; + mp->pid = getpid (); + mp->address = address.as_u32; + + S; + W; +} + +static int +api_want_ip6_nd_events (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_want_ip6_nd_events_t *mp; + f64 timeout; + ip6_address_t address; + int address_set = 0; + u32 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "address %U", unformat_ip6_address, &address)) + address_set = 1; + else if (unformat (line_input, "del")) + enable_disable = 0; + else + break; + } + + if (address_set == 0) + { + errmsg ("missing addresses"); + return -99; + } + + M (WANT_IP6_ND_EVENTS, want_ip6_nd_events); + mp->enable_disable = enable_disable; + mp->pid = getpid (); + clib_memcpy (mp->address, &address, sizeof (ip6_address_t)); + + S; + W; +} + +static int +api_input_acl_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_input_acl_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 l2_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "l2-table %d", &l2_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (INPUT_ACL_SET_INTERFACE, input_acl_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->l2_table_index = ntohl (l2_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ip_address_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_address_dump_t *mp; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + f64 timeout; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "ipv4")) + ipv4_set = 1; + else if (unformat (i, "ipv6")) + ipv6_set = 1; + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("ipv4 and ipv6 flags cannot be both set"); + return -99; + } + + if ((!ipv4_set) && (!ipv6_set)) + { + errmsg ("no ipv4 nor ipv6 flag set"); + return -99; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + vam->current_sw_if_index = sw_if_index; + vam->is_ipv6 = ipv6_set; + + M (IP_ADDRESS_DUMP, ip_address_dump); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_ipv6 = ipv6_set; + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_ip_dump (vat_main_t * vam) +{ + vl_api_ip_dump_t *mp; + unformat_input_t *in = vam->input; + int ipv4_set = 0; + int ipv6_set = 0; + int is_ipv6; + f64 timeout; + int i; + + while (unformat_check_input (in) != UNFORMAT_END_OF_INPUT) + { + if (unformat (in, "ipv4")) + ipv4_set = 1; + else if (unformat (in, "ipv6")) + ipv6_set = 1; + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("ipv4 and ipv6 flags cannot be both set"); + return -99; + } + + if ((!ipv4_set) && (!ipv6_set)) + { + errmsg ("no ipv4 nor ipv6 flag set"); + return -99; + } + + is_ipv6 = ipv6_set; + vam->is_ipv6 = is_ipv6; + + /* free old data */ + for (i = 0; i < vec_len (vam->ip_details_by_sw_if_index[is_ipv6]); i++) + { + vec_free (vam->ip_details_by_sw_if_index[is_ipv6][i].addr); + } + vec_free (vam->ip_details_by_sw_if_index[is_ipv6]); + + M (IP_DUMP, ip_dump); + mp->is_ipv6 = ipv6_set; + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_ipsec_spd_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_spd_add_del_t *mp; + f64 timeout; + u32 spd_id = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "spd_id %d", &spd_id)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + if (spd_id == ~0) + { + errmsg ("spd_id must be set"); + return -99; + } + + M (IPSEC_SPD_ADD_DEL, ipsec_spd_add_del); + + mp->spd_id = ntohl (spd_id); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_interface_add_del_spd (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_interface_add_del_spd_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + u32 spd_id = (u32) ~ 0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "spd_id %d", &spd_id)) + ; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + + if (spd_id == (u32) ~ 0) + { + errmsg ("spd_id must be set"); + return -99; + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd); + + mp->spd_id = ntohl (spd_id); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_spd_add_del_entry (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_spd_add_del_entry_t *mp; + f64 timeout; + u8 is_add = 1, is_outbound = 0, is_ipv6 = 0, is_ip_any = 1; + u32 spd_id = 0, sa_id = 0, protocol = 0, policy = 0; + i32 priority = 0; + u32 rport_start = 0, rport_stop = (u32) ~ 0; + u32 lport_start = 0, lport_stop = (u32) ~ 0; + ip4_address_t laddr4_start, laddr4_stop, raddr4_start, raddr4_stop; + ip6_address_t laddr6_start, laddr6_stop, raddr6_start, raddr6_stop; + + laddr4_start.as_u32 = raddr4_start.as_u32 = 0; + laddr4_stop.as_u32 = raddr4_stop.as_u32 = (u32) ~ 0; + laddr6_start.as_u64[0] = raddr6_start.as_u64[0] = 0; + laddr6_start.as_u64[1] = raddr6_start.as_u64[1] = 0; + laddr6_stop.as_u64[0] = raddr6_stop.as_u64[0] = (u64) ~ 0; + laddr6_stop.as_u64[1] = raddr6_stop.as_u64[1] = (u64) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + if (unformat (i, "outbound")) + is_outbound = 1; + if (unformat (i, "inbound")) + is_outbound = 0; + else if (unformat (i, "spd_id %d", &spd_id)) + ; + else if (unformat (i, "sa_id %d", &sa_id)) + ; + else if (unformat (i, "priority %d", &priority)) + ; + else if (unformat (i, "protocol %d", &protocol)) + ; + else if (unformat (i, "lport_start %d", &lport_start)) + ; + else if (unformat (i, "lport_stop %d", &lport_stop)) + ; + else if (unformat (i, "rport_start %d", &rport_start)) + ; + else if (unformat (i, "rport_stop %d", &rport_stop)) + ; + else + if (unformat + (i, "laddr_start %U", unformat_ip4_address, &laddr4_start)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat (i, "laddr_stop %U", unformat_ip4_address, &laddr4_stop)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat + (i, "raddr_start %U", unformat_ip4_address, &raddr4_start)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat (i, "raddr_stop %U", unformat_ip4_address, &raddr4_stop)) + { + is_ipv6 = 0; + is_ip_any = 0; + } + else + if (unformat + (i, "laddr_start %U", unformat_ip6_address, &laddr6_start)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "laddr_stop %U", unformat_ip6_address, &laddr6_stop)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat + (i, "raddr_start %U", unformat_ip6_address, &raddr6_start)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "raddr_stop %U", unformat_ip6_address, &raddr6_stop)) + { + is_ipv6 = 1; + is_ip_any = 0; + } + else + if (unformat (i, "action %U", unformat_ipsec_policy_action, &policy)) + { + if (policy == IPSEC_POLICY_ACTION_RESOLVE) + { + clib_warning ("unsupported action: 'resolve'"); + return -99; + } + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + + M (IPSEC_SPD_ADD_DEL_ENTRY, ipsec_spd_add_del_entry); + + mp->spd_id = ntohl (spd_id); + mp->priority = ntohl (priority); + mp->is_outbound = is_outbound; + + mp->is_ipv6 = is_ipv6; + if (is_ipv6 || is_ip_any) + { + clib_memcpy (mp->remote_address_start, &raddr6_start, + sizeof (ip6_address_t)); + clib_memcpy (mp->remote_address_stop, &raddr6_stop, + sizeof (ip6_address_t)); + clib_memcpy (mp->local_address_start, &laddr6_start, + sizeof (ip6_address_t)); + clib_memcpy (mp->local_address_stop, &laddr6_stop, + sizeof (ip6_address_t)); + } + else + { + clib_memcpy (mp->remote_address_start, &raddr4_start, + sizeof (ip4_address_t)); + clib_memcpy (mp->remote_address_stop, &raddr4_stop, + sizeof (ip4_address_t)); + clib_memcpy (mp->local_address_start, &laddr4_start, + sizeof (ip4_address_t)); + clib_memcpy (mp->local_address_stop, &laddr4_stop, + sizeof (ip4_address_t)); + } + mp->protocol = (u8) protocol; + mp->local_port_start = ntohs ((u16) lport_start); + mp->local_port_stop = ntohs ((u16) lport_stop); + mp->remote_port_start = ntohs ((u16) rport_start); + mp->remote_port_stop = ntohs ((u16) rport_stop); + mp->policy = (u8) policy; + mp->sa_id = ntohl (sa_id); + mp->is_add = is_add; + mp->is_ip_any = is_ip_any; + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_sad_add_del_entry (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_sad_add_del_entry_t *mp; + f64 timeout; + u32 sad_id = 0, spi = 0; + u8 *ck = 0, *ik = 0; + u8 is_add = 1; + + u8 protocol = IPSEC_PROTOCOL_AH; + u8 is_tunnel = 0, is_tunnel_ipv6 = 0; + u32 crypto_alg = 0, integ_alg = 0; + ip4_address_t tun_src4; + ip4_address_t tun_dst4; + ip6_address_t tun_src6; + ip6_address_t tun_dst6; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "sad_id %d", &sad_id)) + ; + else if (unformat (i, "spi %d", &spi)) + ; + else if (unformat (i, "esp")) + protocol = IPSEC_PROTOCOL_ESP; + else if (unformat (i, "tunnel_src %U", unformat_ip4_address, &tun_src4)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 0; + } + else if (unformat (i, "tunnel_dst %U", unformat_ip4_address, &tun_dst4)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 0; + } + else if (unformat (i, "tunnel_src %U", unformat_ip6_address, &tun_src6)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 1; + } + else if (unformat (i, "tunnel_dst %U", unformat_ip6_address, &tun_dst6)) + { + is_tunnel = 1; + is_tunnel_ipv6 = 1; + } + else + if (unformat + (i, "crypto_alg %U", unformat_ipsec_crypto_alg, &crypto_alg)) + { + if (crypto_alg < IPSEC_CRYPTO_ALG_AES_CBC_128 || + crypto_alg >= IPSEC_CRYPTO_N_ALG) + { + clib_warning ("unsupported crypto-alg: '%U'", + format_ipsec_crypto_alg, crypto_alg); + return -99; + } + } + else if (unformat (i, "crypto_key %U", unformat_hex_string, &ck)) + ; + else + if (unformat + (i, "integ_alg %U", unformat_ipsec_integ_alg, &integ_alg)) + { +#if DPDK_CRYPTO==1 + if (integ_alg < IPSEC_INTEG_ALG_NONE || +#else + if (integ_alg < IPSEC_INTEG_ALG_SHA1_96 || +#endif + integ_alg >= IPSEC_INTEG_N_ALG) + { + clib_warning ("unsupported integ-alg: '%U'", + format_ipsec_integ_alg, integ_alg); + return -99; + } + } + else if (unformat (i, "integ_key %U", unformat_hex_string, &ik)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + + } + +#if DPDK_CRYPTO==1 + /*Special cases, aes-gcm-128 encryption */ + if (crypto_alg == IPSEC_CRYPTO_ALG_AES_GCM_128) + { + if (integ_alg != IPSEC_INTEG_ALG_NONE + && integ_alg != IPSEC_INTEG_ALG_AES_GCM_128) + { + clib_warning + ("unsupported: aes-gcm-128 crypto-alg needs none as integ-alg"); + return -99; + } + else /*set integ-alg internally to aes-gcm-128 */ + integ_alg = IPSEC_INTEG_ALG_AES_GCM_128; + } + else if (integ_alg == IPSEC_INTEG_ALG_AES_GCM_128) + { + clib_warning ("unsupported integ-alg: aes-gcm-128"); + return -99; + } + else if (integ_alg == IPSEC_INTEG_ALG_NONE) + { + clib_warning ("unsupported integ-alg: none"); + return -99; + } +#endif + + + M (IPSEC_SAD_ADD_DEL_ENTRY, ipsec_sad_add_del_entry); + + mp->sad_id = ntohl (sad_id); + mp->is_add = is_add; + mp->protocol = protocol; + mp->spi = ntohl (spi); + mp->is_tunnel = is_tunnel; + mp->is_tunnel_ipv6 = is_tunnel_ipv6; + mp->crypto_algorithm = crypto_alg; + mp->integrity_algorithm = integ_alg; + mp->crypto_key_length = vec_len (ck); + mp->integrity_key_length = vec_len (ik); + + if (mp->crypto_key_length > sizeof (mp->crypto_key)) + mp->crypto_key_length = sizeof (mp->crypto_key); + + if (mp->integrity_key_length > sizeof (mp->integrity_key)) + mp->integrity_key_length = sizeof (mp->integrity_key); + + if (ck) + clib_memcpy (mp->crypto_key, ck, mp->crypto_key_length); + if (ik) + clib_memcpy (mp->integrity_key, ik, mp->integrity_key_length); + + if (is_tunnel) + { + if (is_tunnel_ipv6) + { + clib_memcpy (mp->tunnel_src_address, &tun_src6, + sizeof (ip6_address_t)); + clib_memcpy (mp->tunnel_dst_address, &tun_dst6, + sizeof (ip6_address_t)); + } + else + { + clib_memcpy (mp->tunnel_src_address, &tun_src4, + sizeof (ip4_address_t)); + clib_memcpy (mp->tunnel_dst_address, &tun_dst4, + sizeof (ip4_address_t)); + } + } + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipsec_sa_set_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_sa_set_key_t *mp; + f64 timeout; + u32 sa_id; + u8 *ck = 0, *ik = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sa_id %d", &sa_id)) + ; + else if (unformat (i, "crypto_key %U", unformat_hex_string, &ck)) + ; + else if (unformat (i, "integ_key %U", unformat_hex_string, &ik)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (IPSEC_SA_SET_KEY, ipsec_set_sa_key); + + mp->sa_id = ntohl (sa_id); + mp->crypto_key_length = vec_len (ck); + mp->integrity_key_length = vec_len (ik); + + if (mp->crypto_key_length > sizeof (mp->crypto_key)) + mp->crypto_key_length = sizeof (mp->crypto_key); + + if (mp->integrity_key_length > sizeof (mp->integrity_key)) + mp->integrity_key_length = sizeof (mp->integrity_key); + + if (ck) + clib_memcpy (mp->crypto_key, ck, mp->crypto_key_length); + if (ik) + clib_memcpy (mp->integrity_key, ik, mp->integrity_key_length); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_add_del_t *mp; + f64 timeout; + u8 is_add = 1; + u8 *name = 0; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + M (IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del); + + clib_memcpy (mp->name, name, vec_len (name)); + mp->is_add = is_add; + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_auth (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_auth_t *mp; + f64 timeout; + u8 *name = 0; + u8 *data = 0; + u32 auth_method = 0; + u8 is_hex = 0; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "auth_method %U", + unformat_ikev2_auth_method, &auth_method)) + ; + else if (unformat (i, "auth_data 0x%U", unformat_hex_string, &data)) + is_hex = 1; + else if (unformat (i, "auth_data %v", &data)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + if (!vec_len (data)) + { + errmsg ("auth_data must be specified"); + return -99; + } + + if (!auth_method) + { + errmsg ("auth_method must be specified"); + return -99; + } + + M (IKEV2_PROFILE_SET_AUTH, ikev2_profile_set_auth); + + mp->is_hex = is_hex; + mp->auth_method = (u8) auth_method; + mp->data_len = vec_len (data); + clib_memcpy (mp->name, name, vec_len (name)); + clib_memcpy (mp->data, data, vec_len (data)); + vec_free (name); + vec_free (data); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_id (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_id_t *mp; + f64 timeout; + u8 *name = 0; + u8 *data = 0; + u8 is_local = 0; + u32 id_type = 0; + ip4_address_t ip4; + + const char *valid_chars = "a-zA-Z0-9_"; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "id_type %U", unformat_ikev2_id_type, &id_type)) + ; + else if (unformat (i, "id_data %U", unformat_ip4_address, &ip4)) + { + data = vec_new (u8, 4); + clib_memcpy (data, ip4.as_u8, 4); + } + else if (unformat (i, "id_data 0x%U", unformat_hex_string, &data)) + ; + else if (unformat (i, "id_data %v", &data)) + ; + else if (unformat (i, "local")) + is_local = 1; + else if (unformat (i, "remote")) + is_local = 0; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + if (!vec_len (data)) + { + errmsg ("id_data must be specified"); + return -99; + } + + if (!id_type) + { + errmsg ("id_type must be specified"); + return -99; + } + + M (IKEV2_PROFILE_SET_ID, ikev2_profile_set_id); + + mp->is_local = is_local; + mp->id_type = (u8) id_type; + mp->data_len = vec_len (data); + clib_memcpy (mp->name, name, vec_len (name)); + clib_memcpy (mp->data, data, vec_len (data)); + vec_free (name); + vec_free (data); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_profile_set_ts (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_profile_set_ts_t *mp; + f64 timeout; + u8 *name = 0; + u8 is_local = 0; + u32 proto = 0, start_port = 0, end_port = (u32) ~ 0; + ip4_address_t start_addr, end_addr; + + const char *valid_chars = "a-zA-Z0-9_"; + + start_addr.as_u32 = 0; + end_addr.as_u32 = (u32) ~ 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %U", unformat_token, valid_chars, &name)) + vec_add1 (name, 0); + else if (unformat (i, "protocol %d", &proto)) + ; + else if (unformat (i, "start_port %d", &start_port)) + ; + else if (unformat (i, "end_port %d", &end_port)) + ; + else + if (unformat (i, "start_addr %U", unformat_ip4_address, &start_addr)) + ; + else if (unformat (i, "end_addr %U", unformat_ip4_address, &end_addr)) + ; + else if (unformat (i, "local")) + is_local = 1; + else if (unformat (i, "remote")) + is_local = 0; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (name)) + { + errmsg ("profile name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("profile name too long"); + return -99; + } + + M (IKEV2_PROFILE_SET_TS, ikev2_profile_set_ts); + + mp->is_local = is_local; + mp->proto = (u8) proto; + mp->start_port = (u16) start_port; + mp->end_port = (u16) end_port; + mp->start_addr = start_addr.as_u32; + mp->end_addr = end_addr.as_u32; + clib_memcpy (mp->name, name, vec_len (name)); + vec_free (name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ikev2_set_local_key (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ikev2_set_local_key_t *mp; + f64 timeout; + u8 *file = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "file %v", &file)) + vec_add1 (file, 0); + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vec_len (file)) + { + errmsg ("RSA key file must be specified"); + return -99; + } + + if (vec_len (file) > 256) + { + errmsg ("file name too long"); + return -99; + } + + M (IKEV2_SET_LOCAL_KEY, ikev2_set_local_key); + + clib_memcpy (mp->key_file, file, vec_len (file)); + vec_free (file); + + S; + W; + /* NOTREACHED */ + return 0; +} + +/* + * MAP + */ +static int +api_map_add_domain (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_add_domain_t *mp; + f64 timeout; + + ip4_address_t ip4_prefix; + ip6_address_t ip6_prefix; + ip6_address_t ip6_src; + u32 num_m_args = 0; + u32 ip6_prefix_len = 0, ip4_prefix_len = 0, ea_bits_len = 0, psid_offset = + 0, psid_length = 0; + u8 is_translation = 0; + u32 mtu = 0; + u32 ip6_src_len = 128; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ip4-pfx %U/%d", unformat_ip4_address, + &ip4_prefix, &ip4_prefix_len)) + num_m_args++; + else if (unformat (i, "ip6-pfx %U/%d", unformat_ip6_address, + &ip6_prefix, &ip6_prefix_len)) + num_m_args++; + else + if (unformat + (i, "ip6-src %U/%d", unformat_ip6_address, &ip6_src, + &ip6_src_len)) + num_m_args++; + else if (unformat (i, "ip6-src %U", unformat_ip6_address, &ip6_src)) + num_m_args++; + else if (unformat (i, "ea-bits-len %d", &ea_bits_len)) + num_m_args++; + else if (unformat (i, "psid-offset %d", &psid_offset)) + num_m_args++; + else if (unformat (i, "psid-len %d", &psid_length)) + num_m_args++; + else if (unformat (i, "mtu %d", &mtu)) + num_m_args++; + else if (unformat (i, "map-t")) + is_translation = 1; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (num_m_args < 3) + { + errmsg ("mandatory argument(s) missing"); + return -99; + } + + /* Construct the API message */ + M (MAP_ADD_DOMAIN, map_add_domain); + + clib_memcpy (mp->ip4_prefix, &ip4_prefix, sizeof (ip4_prefix)); + mp->ip4_prefix_len = ip4_prefix_len; + + clib_memcpy (mp->ip6_prefix, &ip6_prefix, sizeof (ip6_prefix)); + mp->ip6_prefix_len = ip6_prefix_len; + + clib_memcpy (mp->ip6_src, &ip6_src, sizeof (ip6_src)); + mp->ip6_src_prefix_len = ip6_src_len; + + mp->ea_bits_len = ea_bits_len; + mp->psid_offset = psid_offset; + mp->psid_length = psid_length; + mp->is_translation = is_translation; + mp->mtu = htons (mtu); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_del_domain (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_del_domain_t *mp; + f64 timeout; + + u32 num_m_args = 0; + u32 index; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %d", &index)) + num_m_args++; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (num_m_args != 1) + { + errmsg ("mandatory argument(s) missing"); + return -99; + } + + /* Construct the API message */ + M (MAP_DEL_DOMAIN, map_del_domain); + + mp->index = ntohl (index); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_add_del_rule (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_add_del_rule_t *mp; + f64 timeout; + u8 is_add = 1; + ip6_address_t ip6_dst; + u32 num_m_args = 0, index, psid = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %d", &index)) + num_m_args++; + else if (unformat (i, "psid %d", &psid)) + num_m_args++; + else if (unformat (i, "dst %U", unformat_ip6_address, &ip6_dst)) + num_m_args++; + else if (unformat (i, "del")) + { + is_add = 0; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + /* Construct the API message */ + M (MAP_ADD_DEL_RULE, map_add_del_rule); + + mp->index = ntohl (index); + mp->is_add = is_add; + clib_memcpy (mp->ip6_dst, &ip6_dst, sizeof (ip6_dst)); + mp->psid = ntohs (psid); + + /* send it... */ + S; + + /* Wait for a reply, return good/bad news */ + W; +} + +static int +api_map_domain_dump (vat_main_t * vam) +{ + vl_api_map_domain_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (MAP_DOMAIN_DUMP, map_domain_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_map_rule_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_map_rule_dump_t *mp; + f64 timeout; + u32 domain_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "index %u", &domain_index)) + ; + else + break; + } + + if (domain_index == ~0) + { + clib_warning ("parse error: domain index expected"); + return -99; + } + + /* Construct the API message */ + M (MAP_RULE_DUMP, map_rule_dump); + + mp->domain_index = htonl (domain_index); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void vl_api_map_add_domain_reply_t_handler + (vl_api_map_add_domain_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + if (vam->async_mode) + { + vam->async_errors += (retval < 0); + } + else + { + vam->retval = retval; + vam->result_ready = 1; + } +} + +static void vl_api_map_add_domain_reply_t_handler_json + (vl_api_map_add_domain_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "index", ntohl (mp->index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + +static int +api_get_first_msg_id (vat_main_t * vam) +{ + vl_api_get_first_msg_id_t *mp; + f64 timeout; + unformat_input_t *i = vam->input; + u8 *name; + u8 name_set = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "client %s", &name)) + name_set = 1; + else + break; + } + + if (name_set == 0) + { + errmsg ("missing client name"); + return -99; + } + vec_add1 (name, 0); + + if (vec_len (name) > 63) + { + errmsg ("client name too long"); + return -99; + } + + M (GET_FIRST_MSG_ID, get_first_msg_id); + clib_memcpy (mp->name, name, vec_len (name)); + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_cop_interface_enable_disable (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_cop_interface_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 enable_disable = 1; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "disable")) + enable_disable = 0; + if (unformat (line_input, "enable")) + enable_disable = 1; + else if (unformat (line_input, "%U", api_unformat_sw_if_index, + vam, &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (COP_INTERFACE_ENABLE_DISABLE, cop_interface_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->enable_disable = enable_disable; + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +static int +api_cop_whitelist_enable_disable (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + vl_api_cop_whitelist_enable_disable_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 ip4 = 0, ip6 = 0, default_cop = 0; + u32 fib_id = 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "ip4")) + ip4 = 1; + else if (unformat (line_input, "ip6")) + ip6 = 1; + else if (unformat (line_input, "default")) + default_cop = 1; + else if (unformat (line_input, "%U", api_unformat_sw_if_index, + vam, &sw_if_index)) + ; + else if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "fib-id %d", &fib_id)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (COP_WHITELIST_ENABLE_DISABLE, cop_whitelist_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->fib_id = ntohl (fib_id); + mp->ip4 = ip4; + mp->ip6 = ip6; + mp->default_cop = default_cop; + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +static int +api_get_node_graph (vat_main_t * vam) +{ + vl_api_get_node_graph_t *mp; + f64 timeout; + + M (GET_NODE_GRAPH, get_node_graph); + + /* send it... */ + S; + /* Wait for the reply */ + W; +} + +/* *INDENT-OFF* */ +/** Used for parsing LISP eids */ +typedef CLIB_PACKED(struct{ + u8 addr[16]; /**< eid address */ + u32 len; /**< prefix length if IP */ + u8 type; /**< type of eid */ +}) lisp_eid_vat_t; +/* *INDENT-ON* */ + +static uword +unformat_lisp_eid_vat (unformat_input_t * input, va_list * args) +{ + lisp_eid_vat_t *a = va_arg (*args, lisp_eid_vat_t *); + + memset (a, 0, sizeof (a[0])); + + if (unformat (input, "%U/%d", unformat_ip4_address, a->addr, &a->len)) + { + a->type = 0; /* ipv4 type */ + } + else if (unformat (input, "%U/%d", unformat_ip6_address, a->addr, &a->len)) + { + a->type = 1; /* ipv6 type */ + } + else if (unformat (input, "%U", unformat_ethernet_address, a->addr)) + { + a->type = 2; /* mac type */ + } + else + { + return 0; + } + + if ((a->type == 0 && a->len > 32) || (a->type == 1 && a->len > 128)) + { + return 0; + } + + return 1; +} + +static int +lisp_eid_size_vat (u8 type) +{ + switch (type) + { + case 0: + return 4; + case 1: + return 16; + case 2: + return 6; + } + return 0; +} + +static void +lisp_eid_put_vat (u8 * dst, u8 eid[16], u8 type) +{ + clib_memcpy (dst, eid, lisp_eid_size_vat (type)); +} + +/* *INDENT-OFF* */ +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u32 sw_if_index; /**< locator sw_if_index */ + u8 priority; /**< locator priority */ + u8 weight; /**< locator weight */ +}) ls_locator_t; +/* *INDENT-ON* */ + +static int +api_lisp_add_del_locator_set (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_locator_set_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 *locator_set_name = NULL; + u8 locator_set_name_set = 0; + ls_locator_t locator, *locators = 0; + u32 sw_if_index, priority, weight; + u32 data_len = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "sw_if_index %u p %u w %u", + &sw_if_index, &priority, &weight)) + { + locator.sw_if_index = htonl (sw_if_index); + locator.priority = priority; + locator.weight = weight; + vec_add1 (locators, locator); + } + else + if (unformat + (input, "iface %U p %u w %u", api_unformat_sw_if_index, vam, + &sw_if_index, &priority, &weight)) + { + locator.sw_if_index = htonl (sw_if_index); + locator.priority = priority; + locator.weight = weight; + vec_add1 (locators, locator); + } + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + vec_free (locators); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + vec_free (locators); + return -99; + } + vec_add1 (locator_set_name, 0); + + data_len = sizeof (ls_locator_t) * vec_len (locators); + + /* Construct the API message */ + M2 (LISP_ADD_DEL_LOCATOR_SET, lisp_add_del_locator_set, data_len); + + mp->is_add = is_add; + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + vec_free (locator_set_name); + + mp->locator_num = clib_host_to_net_u32 (vec_len (locators)); + if (locators) + clib_memcpy (mp->locators, locators, data_len); + vec_free (locators); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_locator (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_locator_t *mp; + f64 timeout = ~0; + u32 tmp_if_index = ~0; + u32 sw_if_index = ~0; + u8 sw_if_index_set = 0; + u8 sw_if_index_if_name_set = 0; + u32 priority = ~0; + u8 priority_set = 0; + u32 weight = ~0; + u8 weight_set = 0; + u8 is_add = 1; + u8 *locator_set_name = NULL; + u8 locator_set_name_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "iface %U", api_unformat_sw_if_index, vam, + &tmp_if_index)) + { + sw_if_index_if_name_set = 1; + sw_if_index = tmp_if_index; + } + else if (unformat (input, "sw_if_index %d", &tmp_if_index)) + { + sw_if_index_set = 1; + sw_if_index = tmp_if_index; + } + else if (unformat (input, "p %d", &priority)) + { + priority_set = 1; + } + else if (unformat (input, "w %d", &weight)) + { + weight_set = 1; + } + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + return -99; + } + + if (sw_if_index_set == 0 && sw_if_index_if_name_set == 0) + { + errmsg ("missing sw_if_index"); + vec_free (locator_set_name); + return -99; + } + + if (sw_if_index_set != 0 && sw_if_index_if_name_set != 0) + { + errmsg ("cannot use both params interface name and sw_if_index"); + vec_free (locator_set_name); + return -99; + } + + if (priority_set == 0) + { + errmsg ("missing locator-set priority"); + vec_free (locator_set_name); + return -99; + } + + if (weight_set == 0) + { + errmsg ("missing locator-set weight"); + vec_free (locator_set_name); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + vec_add1 (locator_set_name, 0); + + /* Construct the API message */ + M (LISP_ADD_DEL_LOCATOR, lisp_add_del_locator); + + mp->is_add = is_add; + mp->sw_if_index = ntohl (sw_if_index); + mp->priority = priority; + mp->weight = weight; + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + vec_free (locator_set_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +uword +unformat_hmac_key_id (unformat_input_t * input, va_list * args) +{ + u32 *key_id = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "sha1")) + key_id[0] = HMAC_SHA_1_96; + else if (!strcmp ((char *) s, "sha256")) + key_id[0] = HMAC_SHA_256_128; + else + { + clib_warning ("invalid key_id: '%s'", s); + key_id[0] = HMAC_NO_KEY; + } + } + else + return 0; + + vec_free (s); + return 1; +} + +static int +api_lisp_add_del_local_eid (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_local_eid_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 eid_set = 0; + lisp_eid_vat_t _eid, *eid = &_eid; + u8 *locator_set_name = 0; + u8 locator_set_name_set = 0; + u32 vni = 0; + u16 key_id = 0; + u8 *key = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else if (unformat (input, "eid %U", unformat_lisp_eid_vat, eid)) + { + eid_set = 1; + } + else if (unformat (input, "locator-set %s", &locator_set_name)) + { + locator_set_name_set = 1; + } + else if (unformat (input, "key-id %U", unformat_hmac_key_id, &key_id)) + ; + else if (unformat (input, "secret-key %_%v%_", &key)) + ; + else + break; + } + + if (locator_set_name_set == 0) + { + errmsg ("missing locator-set name"); + return -99; + } + + if (0 == eid_set) + { + errmsg ("EID address not set!"); + vec_free (locator_set_name); + return -99; + } + + if (key && (0 == key_id)) + { + errmsg ("invalid key_id!"); + return -99; + } + + if (vec_len (key) > 64) + { + errmsg ("key too long"); + vec_free (key); + return -99; + } + + if (vec_len (locator_set_name) > 64) + { + errmsg ("locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + vec_add1 (locator_set_name, 0); + + /* Construct the API message */ + M (LISP_ADD_DEL_LOCAL_EID, lisp_add_del_local_eid); + + mp->is_add = is_add; + lisp_eid_put_vat (mp->eid, eid->addr, eid->type); + mp->eid_type = eid->type; + mp->prefix_len = eid->len; + mp->vni = clib_host_to_net_u32 (vni); + mp->key_id = clib_host_to_net_u16 (key_id); + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + clib_memcpy (mp->key, key, vec_len (key)); + + vec_free (locator_set_name); + vec_free (key); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/* *INDENT-OFF* */ +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u8 is_ip4; /**< is locator an IPv4 address? */ + u8 priority; /**< locator priority */ + u8 weight; /**< locator weight */ + u8 addr[16]; /**< IPv4/IPv6 address */ +}) rloc_t; +/* *INDENT-ON* */ + +static int +api_lisp_gpe_add_del_fwd_entry (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_add_del_fwd_entry_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + lisp_eid_vat_t _rmt_eid, *rmt_eid = &_rmt_eid; + lisp_eid_vat_t _lcl_eid, *lcl_eid = &_lcl_eid; + u8 rmt_eid_set = 0, lcl_eid_set = 0; + u32 action = ~0, p, w; + ip4_address_t rmt_rloc4, lcl_rloc4; + ip6_address_t rmt_rloc6, lcl_rloc6; + rloc_t *rmt_locs = 0, *lcl_locs = 0, rloc, *curr_rloc = 0; + + memset (&rloc, 0, sizeof (rloc)); + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "rmt_eid %U", unformat_lisp_eid_vat, rmt_eid)) + { + rmt_eid_set = 1; + } + else if (unformat (input, "lcl_eid %U", unformat_lisp_eid_vat, lcl_eid)) + { + lcl_eid_set = 1; + } + else if (unformat (input, "p %d w %d", &p, &w)) + { + if (!curr_rloc) + { + errmsg ("No RLOC configured for setting priority/weight!"); + return -99; + } + curr_rloc->priority = p; + curr_rloc->weight = w; + } + else if (unformat (input, "loc-pair %U %U", unformat_ip4_address, + &lcl_rloc4, unformat_ip4_address, &rmt_rloc4)) + { + rloc.is_ip4 = 1; + + clib_memcpy (&rloc.addr, &lcl_rloc4, sizeof (lcl_rloc4)); + rloc.priority = rloc.weight = 0; + vec_add1 (lcl_locs, rloc); + + clib_memcpy (&rloc.addr, &rmt_rloc4, sizeof (rmt_rloc4)); + vec_add1 (rmt_locs, rloc); + /* priority and weight saved in rmt loc */ + curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1]; + } + else if (unformat (input, "loc-pair %U %U", unformat_ip6_address, + &lcl_rloc6, unformat_ip6_address, &rmt_rloc6)) + { + rloc.is_ip4 = 0; + clib_memcpy (&rloc.addr, &lcl_rloc6, sizeof (lcl_rloc6)); + rloc.priority = rloc.weight = 0; + vec_add1 (lcl_locs, rloc); + + clib_memcpy (&rloc.addr, &rmt_rloc6, sizeof (rmt_rloc6)); + vec_add1 (rmt_locs, rloc); + /* priority and weight saved in rmt loc */ + curr_rloc = &rmt_locs[vec_len (rmt_locs) - 1]; + } + else if (unformat (input, "action %d", &action)) + { + ; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!rmt_eid_set) + { + errmsg ("remote eid addresses not set"); + return -99; + } + + if (lcl_eid_set && rmt_eid->type != lcl_eid->type) + { + errmsg ("eid types don't match"); + return -99; + } + + if (0 == rmt_locs && (u32) ~ 0 == action) + { + errmsg ("action not set for negative mapping"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ADD_DEL_FWD_ENTRY, lisp_gpe_add_del_fwd_entry); + + mp->is_add = is_add; + lisp_eid_put_vat (mp->rmt_eid, rmt_eid->addr, rmt_eid->type); + lisp_eid_put_vat (mp->lcl_eid, lcl_eid->addr, lcl_eid->type); + mp->eid_type = rmt_eid->type; + mp->rmt_len = rmt_eid->len; + mp->lcl_len = lcl_eid->len; + mp->action = action; + + if (0 != rmt_locs && 0 != lcl_locs) + { + mp->loc_num = vec_len (rmt_locs); + clib_memcpy (mp->lcl_locs, lcl_locs, + (sizeof (rloc_t) * vec_len (lcl_locs))); + clib_memcpy (mp->rmt_locs, rmt_locs, + (sizeof (rloc_t) * vec_len (rmt_locs))); + } + vec_free (lcl_locs); + vec_free (rmt_locs); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_map_server (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_server_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + ip4_address_t ipv4; + ip6_address_t ipv6; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%U", unformat_ip4_address, &ipv4)) + { + ipv4_set = 1; + } + else if (unformat (input, "%U", unformat_ip6_address, &ipv6)) + { + ipv6_set = 1; + } + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("both eid v4 and v6 addresses set"); + return -99; + } + + if (!ipv4_set && !ipv6_set) + { + errmsg ("eid addresses not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ADD_DEL_MAP_SERVER, lisp_add_del_map_server); + + mp->is_add = is_add; + if (ipv6_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->ip_address, &ipv6, sizeof (ipv6)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->ip_address, &ipv4, sizeof (ipv4)); + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_add_del_map_resolver (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_resolver_t *mp; + f64 timeout = ~0; + u8 is_add = 1; + u8 ipv4_set = 0; + u8 ipv6_set = 0; + ip4_address_t ipv4; + ip6_address_t ipv6; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%U", unformat_ip4_address, &ipv4)) + { + ipv4_set = 1; + } + else if (unformat (input, "%U", unformat_ip6_address, &ipv6)) + { + ipv6_set = 1; + } + else + break; + } + + if (ipv4_set && ipv6_set) + { + errmsg ("both eid v4 and v6 addresses set"); + return -99; + } + + if (!ipv4_set && !ipv6_set) + { + errmsg ("eid addresses not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver); + + mp->is_add = is_add; + if (ipv6_set) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->ip_address, &ipv6, sizeof (ipv6)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->ip_address, &ipv4, sizeof (ipv4)); + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + is_en = 0; + } + else + break; + } + + if (is_set == 0) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable); + + mp->is_en = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_rloc_probe_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_rloc_probe_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + is_set = 1; + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_RLOC_PROBE_ENABLE_DISABLE, lisp_rloc_probe_enable_disable); + + mp->is_enabled = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_register_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_map_register_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + is_set = 1; + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_MAP_REGISTER_ENABLE_DISABLE, lisp_map_register_enable_disable); + + mp->is_enabled = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_enable_disable_t *mp; + f64 timeout = ~0; + u8 is_set = 0; + u8 is_en = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "enable")) + { + is_set = 1; + is_en = 1; + } + else if (unformat (input, "disable")) + { + is_set = 1; + } + else + break; + } + + if (!is_set) + { + errmsg ("Value not set"); + return -99; + } + + /* Construct the API message */ + M (LISP_ENABLE_DISABLE, lisp_enable_disable); + + mp->is_en = is_en; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_show_lisp_map_register_state (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_map_register_state_t *mp; + + M (SHOW_LISP_MAP_REGISTER_STATE, show_lisp_map_register_state); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_show_lisp_rloc_probe_state (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_rloc_probe_state_t *mp; + + M (SHOW_LISP_RLOC_PROBE_STATE, show_lisp_rloc_probe_state); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_show_lisp_map_request_mode (vat_main_t * vam) +{ + f64 timeout = ~0; + vl_api_show_lisp_map_request_mode_t *mp; + + M (SHOW_LISP_MAP_REQUEST_MODE, show_lisp_map_request_mode); + + /* send */ + S; + + /* wait for reply */ + W; + + return 0; +} + +static int +api_lisp_map_request_mode (vat_main_t * vam) +{ + f64 timeout = ~0; + unformat_input_t *input = vam->input; + vl_api_lisp_map_request_mode_t *mp; + u8 mode = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "dst-only")) + mode = 0; + else if (unformat (input, "src-dst")) + mode = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + M (LISP_MAP_REQUEST_MODE, lisp_map_request_mode); + + mp->mode = mode; + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +/** + * Enable/disable LISP proxy ITR. + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_pitr_set_locator_set (vat_main_t * vam) +{ + f64 timeout = ~0; + u8 ls_name_set = 0; + unformat_input_t *input = vam->input; + vl_api_lisp_pitr_set_locator_set_t *mp; + u8 is_add = 1; + u8 *ls_name = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "locator-set %s", &ls_name)) + ls_name_set = 1; + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!ls_name_set) + { + errmsg ("locator-set name not set!"); + return -99; + } + + M (LISP_PITR_SET_LOCATOR_SET, lisp_pitr_set_locator_set); + + mp->is_add = is_add; + clib_memcpy (mp->ls_name, ls_name, vec_len (ls_name)); + vec_free (ls_name); + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +static int +api_show_lisp_pitr (vat_main_t * vam) +{ + vl_api_show_lisp_pitr_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "lisp status:"); + } + + M (SHOW_LISP_PITR, show_lisp_pitr); + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/delete mapping between vni and vrf + */ +static int +api_lisp_eid_table_add_del_map (vat_main_t * vam) +{ + f64 timeout = ~0; + unformat_input_t *input = vam->input; + vl_api_lisp_eid_table_add_del_map_t *mp; + u8 is_add = 1, vni_set = 0, vrf_set = 0, bd_index_set = 0; + u32 vni, vrf, bd_index; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "vrf %d", &vrf)) + vrf_set = 1; + else if (unformat (input, "bd_index %d", &bd_index)) + bd_index_set = 1; + else if (unformat (input, "vni %d", &vni)) + vni_set = 1; + else + break; + } + + if (!vni_set || (!vrf_set && !bd_index_set)) + { + errmsg ("missing arguments!"); + return -99; + } + + if (vrf_set && bd_index_set) + { + errmsg ("error: both vrf and bd entered!"); + return -99; + } + + M (LISP_EID_TABLE_ADD_DEL_MAP, lisp_eid_table_add_del_map); + + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->dp_table = vrf_set ? htonl (vrf) : htonl (bd_index); + mp->is_l2 = bd_index_set; + + /* send */ + S; + + /* wait for reply */ + W; + + /* notreached */ + return 0; +} + +uword +unformat_negative_mapping_action (unformat_input_t * input, va_list * args) +{ + u32 *action = va_arg (*args, u32 *); + u8 *s = 0; + + if (unformat (input, "%s", &s)) + { + if (!strcmp ((char *) s, "no-action")) + action[0] = 0; + else if (!strcmp ((char *) s, "natively-forward")) + action[0] = 1; + else if (!strcmp ((char *) s, "send-map-request")) + action[0] = 2; + else if (!strcmp ((char *) s, "drop")) + action[0] = 3; + else + { + clib_warning ("invalid action: '%s'", s); + action[0] = 3; + } + } + else + return 0; + + vec_free (s); + return 1; +} + +/** + * Add/del remote mapping to/from LISP control plane + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_remote_mapping (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_remote_mapping_t *mp; + f64 timeout = ~0; + u32 vni = 0; + lisp_eid_vat_t _eid, *eid = &_eid; + lisp_eid_vat_t _seid, *seid = &_seid; + u8 is_add = 1, del_all = 0, eid_set = 0, seid_set = 0; + u32 action = ~0, p, w, data_len; + ip4_address_t rloc4; + ip6_address_t rloc6; + rloc_t *rlocs = 0, rloc, *curr_rloc = 0; + + memset (&rloc, 0, sizeof (rloc)); + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del-all")) + { + del_all = 1; + } + else if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "add")) + { + is_add = 1; + } + else if (unformat (input, "eid %U", unformat_lisp_eid_vat, eid)) + { + eid_set = 1; + } + else if (unformat (input, "seid %U", unformat_lisp_eid_vat, seid)) + { + seid_set = 1; + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else if (unformat (input, "p %d w %d", &p, &w)) + { + if (!curr_rloc) + { + errmsg ("No RLOC configured for setting priority/weight!"); + return -99; + } + curr_rloc->priority = p; + curr_rloc->weight = w; + } + else if (unformat (input, "rloc %U", unformat_ip4_address, &rloc4)) + { + rloc.is_ip4 = 1; + clib_memcpy (&rloc.addr, &rloc4, sizeof (rloc4)); + vec_add1 (rlocs, rloc); + curr_rloc = &rlocs[vec_len (rlocs) - 1]; + } + else if (unformat (input, "rloc %U", unformat_ip6_address, &rloc6)) + { + rloc.is_ip4 = 0; + clib_memcpy (&rloc.addr, &rloc6, sizeof (rloc6)); + vec_add1 (rlocs, rloc); + curr_rloc = &rlocs[vec_len (rlocs) - 1]; + } + else if (unformat (input, "action %U", + unformat_negative_mapping_action, &action)) + { + ; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (0 == eid_set) + { + errmsg ("missing params!"); + return -99; + } + + if (is_add && (~0 == action) && 0 == vec_len (rlocs)) + { + errmsg ("no action set for negative map-reply!"); + return -99; + } + + data_len = vec_len (rlocs) * sizeof (rloc_t); + + M2 (LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping, data_len); + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->action = (u8) action; + mp->is_src_dst = seid_set; + mp->eid_len = eid->len; + mp->seid_len = seid->len; + mp->del_all = del_all; + mp->eid_type = eid->type; + lisp_eid_put_vat (mp->eid, eid->addr, eid->type); + lisp_eid_put_vat (mp->seid, seid->addr, seid->type); + + mp->rloc_num = clib_host_to_net_u32 (vec_len (rlocs)); + clib_memcpy (mp->rlocs, rlocs, data_len); + vec_free (rlocs); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/del LISP adjacency. Saves mapping in LISP control plane and updates + * forwarding entries in data-plane accordingly. + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_adjacency (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_adjacency_t *mp; + f64 timeout = ~0; + u32 vni = 0; + ip4_address_t leid4, reid4; + ip6_address_t leid6, reid6; + u8 reid_mac[6] = { 0 }; + u8 leid_mac[6] = { 0 }; + u8 reid_type, leid_type; + u32 leid_len = 0, reid_len = 0, len; + u8 is_add = 1; + + leid_type = reid_type = (u8) ~ 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "add")) + { + is_add = 1; + } + else if (unformat (input, "reid %U/%d", unformat_ip4_address, + &reid4, &len)) + { + reid_type = 0; /* ipv4 */ + reid_len = len; + } + else if (unformat (input, "reid %U/%d", unformat_ip6_address, + &reid6, &len)) + { + reid_type = 1; /* ipv6 */ + reid_len = len; + } + else if (unformat (input, "reid %U", unformat_ethernet_address, + reid_mac)) + { + reid_type = 2; /* mac */ + } + else if (unformat (input, "leid %U/%d", unformat_ip4_address, + &leid4, &len)) + { + leid_type = 0; /* ipv4 */ + leid_len = len; + } + else if (unformat (input, "leid %U/%d", unformat_ip6_address, + &leid6, &len)) + { + leid_type = 1; /* ipv6 */ + leid_len = len; + } + else if (unformat (input, "leid %U", unformat_ethernet_address, + leid_mac)) + { + leid_type = 2; /* mac */ + } + else if (unformat (input, "vni %d", &vni)) + { + ; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if ((u8) ~ 0 == reid_type) + { + errmsg ("missing params!"); + return -99; + } + + if (leid_type != reid_type) + { + errmsg ("remote and local EIDs are of different types!"); + return -99; + } + + M (LISP_ADD_DEL_ADJACENCY, lisp_add_del_adjacency); + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->leid_len = leid_len; + mp->reid_len = reid_len; + mp->eid_type = reid_type; + + switch (mp->eid_type) + { + case 0: + clib_memcpy (mp->leid, &leid4, sizeof (leid4)); + clib_memcpy (mp->reid, &reid4, sizeof (reid4)); + break; + case 1: + clib_memcpy (mp->leid, &leid6, sizeof (leid6)); + clib_memcpy (mp->reid, &reid6, sizeof (reid6)); + break; + case 2: + clib_memcpy (mp->leid, leid_mac, 6); + clib_memcpy (mp->reid, reid_mac, 6); + break; + default: + errmsg ("unknown EID type %d!", mp->eid_type); + return 0; + } + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_add_del_iface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_gpe_add_del_iface_t *mp; + f64 timeout = ~0; + u8 action_set = 0, is_add = 1, is_l2 = 0, dp_table_set = 0, vni_set = 0; + u32 dp_table = 0, vni = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "up")) + { + action_set = 1; + is_add = 1; + } + else if (unformat (input, "down")) + { + action_set = 1; + is_add = 0; + } + else if (unformat (input, "table_id %d", &dp_table)) + { + dp_table_set = 1; + } + else if (unformat (input, "bd_id %d", &dp_table)) + { + dp_table_set = 1; + is_l2 = 1; + } + else if (unformat (input, "vni %d", &vni)) + { + vni_set = 1; + } + else + break; + } + + if (action_set == 0) + { + errmsg ("Action not set"); + return -99; + } + if (dp_table_set == 0 || vni_set == 0) + { + errmsg ("vni and dp_table must be set"); + return -99; + } + + /* Construct the API message */ + M (LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface); + + mp->is_add = is_add; + mp->dp_table = dp_table; + mp->is_l2 = is_l2; + mp->vni = vni; + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +/** + * Add/del map request itr rlocs from LISP control plane and updates + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_map_request_itr_rlocs (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_add_del_map_request_itr_rlocs_t *mp; + f64 timeout = ~0; + u8 *locator_set_name = 0; + u8 locator_set_name_set = 0; + u8 is_add = 1; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "del")) + { + is_add = 0; + } + else if (unformat (input, "%_%v%_", &locator_set_name)) + { + locator_set_name_set = 1; + } + else + { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (is_add && !locator_set_name_set) + { + errmsg ("itr-rloc is not set!"); + return -99; + } + + if (is_add && vec_len (locator_set_name) > 64) + { + errmsg ("itr-rloc locator-set name too long"); + vec_free (locator_set_name); + return -99; + } + + M (LISP_ADD_DEL_MAP_REQUEST_ITR_RLOCS, lisp_add_del_map_request_itr_rlocs); + mp->is_add = is_add; + if (is_add) + { + clib_memcpy (mp->locator_set_name, locator_set_name, + vec_len (locator_set_name)); + } + else + { + memset (mp->locator_set_name, 0, sizeof (mp->locator_set_name)); + } + vec_free (locator_set_name); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_locator_dump (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_lisp_locator_dump_t *mp; + f64 timeout = ~0; + u8 is_index_set = 0, is_name_set = 0; + u8 *ls_name = 0; + u32 ls_index = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ls_name %_%v%_", &ls_name)) + { + is_name_set = 1; + } + else if (unformat (input, "ls_index %d", &ls_index)) + { + is_index_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!is_index_set && !is_name_set) + { + errmsg ("error: expected one of index or name!"); + return -99; + } + + if (is_index_set && is_name_set) + { + errmsg ("error: only one param expected!"); + return -99; + } + + if (vec_len (ls_name) > 62) + { + errmsg ("error: locator set name too long!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%=16s%=16s%=16s", "locator", "priority", "weight"); + } + + M (LISP_LOCATOR_DUMP, lisp_locator_dump); + mp->is_index_set = is_index_set; + + if (is_index_set) + mp->ls_index = clib_host_to_net_u32 (ls_index); + else + { + vec_add1 (ls_name, 0); + strncpy ((char *) mp->ls_name, (char *) ls_name, + sizeof (mp->ls_name) - 1); + } + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_locator_set_dump (vat_main_t * vam) +{ + vl_api_lisp_locator_set_dump_t *mp; + unformat_input_t *input = vam->input; + f64 timeout = ~0; + u8 filter = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "local")) + { + filter = 1; + } + else if (unformat (input, "remote")) + { + filter = 2; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!vam->json_output) + { + print (vam->ofp, "%=10s%=15s", "ls_index", "ls_name"); + } + + M (LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump); + + mp->filter = filter; + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_map_dump (vat_main_t * vam) +{ + u8 is_l2 = 0; + u8 mode_set = 0; + unformat_input_t *input = vam->input; + vl_api_lisp_eid_table_map_dump_t *mp; + f64 timeout = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "l2")) + { + is_l2 = 1; + mode_set = 1; + } + else if (unformat (input, "l3")) + { + is_l2 = 0; + mode_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!mode_set) + { + errmsg ("expected one of 'l2' or 'l3' parameter!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF"); + } + + M (LISP_EID_TABLE_MAP_DUMP, lisp_eid_table_map_dump); + mp->is_l2 = is_l2; + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_vni_dump (vat_main_t * vam) +{ + vl_api_lisp_eid_table_vni_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "VNI"); + } + + M (LISP_EID_TABLE_VNI_DUMP, lisp_eid_table_vni_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_eid_table_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_lisp_eid_table_dump_t *mp; + f64 timeout = ~0; + struct in_addr ip4; + struct in6_addr ip6; + u8 mac[6]; + u8 eid_type = ~0, eid_set = 0; + u32 prefix_length = ~0, t, vni = 0; + u8 filter = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "eid %U/%d", unformat_ip4_address, &ip4, &t)) + { + eid_set = 1; + eid_type = 0; + prefix_length = t; + } + else if (unformat (i, "eid %U/%d", unformat_ip6_address, &ip6, &t)) + { + eid_set = 1; + eid_type = 1; + prefix_length = t; + } + else if (unformat (i, "eid %U", unformat_ethernet_address, mac)) + { + eid_set = 1; + eid_type = 2; + } + else if (unformat (i, "vni %d", &t)) + { + vni = t; + } + else if (unformat (i, "local")) + { + filter = 1; + } + else if (unformat (i, "remote")) + { + filter = 2; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vam->json_output) + { + print (vam->ofp, "%-35s%-20s%-30s%-20s%-20s%-10s%-20s", "EID", + "type", "ls_index", "ttl", "authoritative", "key_id", "key"); + } + + M (LISP_EID_TABLE_DUMP, lisp_eid_table_dump); + + mp->filter = filter; + if (eid_set) + { + mp->eid_set = 1; + mp->vni = htonl (vni); + mp->eid_type = eid_type; + switch (eid_type) + { + case 0: + mp->prefix_length = prefix_length; + clib_memcpy (mp->eid, &ip4, sizeof (ip4)); + break; + case 1: + mp->prefix_length = prefix_length; + clib_memcpy (mp->eid, &ip6, sizeof (ip6)); + break; + case 2: + clib_memcpy (mp->eid, mac, sizeof (mac)); + break; + default: + errmsg ("unknown EID type %d!", eid_type); + return -99; + } + } + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_gpe_tunnel_dump (vat_main_t * vam) +{ + vl_api_lisp_gpe_tunnel_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s%=30s%=16s%=16s%=16s%=16s" + "%=16s%=16s%=16s%=16s%=16s", + "Tunel", "Source", "Destination", "Fib encap", "Fib decap", + "Decap next", "Lisp version", "Flags", "Next protocol", + "ver_res", "res", "iid"); + } + + M (LISP_GPE_TUNNEL_DUMP, lisp_gpe_tunnel_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_adjacencies_get (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_lisp_adjacencies_get_t *mp; + f64 timeout = ~0; + u8 vni_set = 0; + u32 vni = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "vni %d", &vni)) + { + vni_set = 1; + } + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (!vni_set) + { + errmsg ("vni not set!"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%s %40s", "leid", "reid"); + } + + M (LISP_ADJACENCIES_GET, lisp_adjacencies_get); + mp->vni = clib_host_to_net_u32 (vni); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_server_dump (vat_main_t * vam) +{ + vl_api_lisp_map_server_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "Map server"); + } + + M (LISP_MAP_SERVER_DUMP, lisp_map_server_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_map_resolver_dump (vat_main_t * vam) +{ + vl_api_lisp_map_resolver_dump_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "Map resolver"); + } + + M (LISP_MAP_RESOLVER_DUMP, lisp_map_resolver_dump); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_show_lisp_status (vat_main_t * vam) +{ + vl_api_show_lisp_status_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%-20s%-16s", "lisp status", "locator-set"); + } + + M (SHOW_LISP_STATUS, show_lisp_status); + /* send it... */ + S; + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_lisp_get_map_request_itr_rlocs (vat_main_t * vam) +{ + vl_api_lisp_get_map_request_itr_rlocs_t *mp; + f64 timeout = ~0; + + if (!vam->json_output) + { + print (vam->ofp, "%=20s", "itr-rlocs:"); + } + + M (LISP_GET_MAP_REQUEST_ITR_RLOCS, lisp_get_map_request_itr_rlocs); + /* send it... */ + S; + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_af_packet_create (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_af_packet_create_t *mp; + f64 timeout; + u8 *host_if_name = 0; + u8 hw_addr[6]; + u8 random_hw_addr = 1; + + memset (hw_addr, 0, sizeof (hw_addr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &host_if_name)) + vec_add1 (host_if_name, 0); + else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr)) + random_hw_addr = 0; + else + break; + } + + if (!vec_len (host_if_name)) + { + errmsg ("host-interface name must be specified"); + return -99; + } + + if (vec_len (host_if_name) > 64) + { + errmsg ("host-interface name too long"); + return -99; + } + + M (AF_PACKET_CREATE, af_packet_create); + + clib_memcpy (mp->host_if_name, host_if_name, vec_len (host_if_name)); + clib_memcpy (mp->hw_addr, hw_addr, 6); + mp->use_random_hw_addr = random_hw_addr; + vec_free (host_if_name); + + S; + W2 (fprintf (vam->ofp, " new sw_if_index = %d ", vam->sw_if_index)); + /* NOTREACHED */ + return 0; +} + +static int +api_af_packet_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_af_packet_delete_t *mp; + f64 timeout; + u8 *host_if_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &host_if_name)) + vec_add1 (host_if_name, 0); + else + break; + } + + if (!vec_len (host_if_name)) + { + errmsg ("host-interface name must be specified"); + return -99; + } + + if (vec_len (host_if_name) > 64) + { + errmsg ("host-interface name too long"); + return -99; + } + + M (AF_PACKET_DELETE, af_packet_delete); + + clib_memcpy (mp->host_if_name, host_if_name, vec_len (host_if_name)); + vec_free (host_if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_add_del_t *mp; + f64 timeout; + u8 is_add = 1; + u8 *name = 0; + u32 cir = 0; + u32 eir = 0; + u64 cb = 0; + u64 eb = 0; + u8 rate_type = 0; + u8 round_type = 0; + u8 type = 0; + u8 color_aware = 0; + sse2_qos_pol_action_params_st conform_action, exceed_action, violate_action; + + conform_action.action_type = SSE2_QOS_ACTION_TRANSMIT; + conform_action.dscp = 0; + exceed_action.action_type = SSE2_QOS_ACTION_MARK_AND_TRANSMIT; + exceed_action.dscp = 0; + violate_action.action_type = SSE2_QOS_ACTION_DROP; + violate_action.dscp = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "name %s", &name)) + vec_add1 (name, 0); + else if (unformat (i, "cir %u", &cir)) + ; + else if (unformat (i, "eir %u", &eir)) + ; + else if (unformat (i, "cb %u", &cb)) + ; + else if (unformat (i, "eb %u", &eb)) + ; + else if (unformat (i, "rate_type %U", unformat_policer_rate_type, + &rate_type)) + ; + else if (unformat (i, "round_type %U", unformat_policer_round_type, + &round_type)) + ; + else if (unformat (i, "type %U", unformat_policer_type, &type)) + ; + else if (unformat (i, "conform_action %U", unformat_policer_action_type, + &conform_action)) + ; + else if (unformat (i, "exceed_action %U", unformat_policer_action_type, + &exceed_action)) + ; + else if (unformat (i, "violate_action %U", unformat_policer_action_type, + &violate_action)) + ; + else if (unformat (i, "color-aware")) + color_aware = 1; + else + break; + } + + if (!vec_len (name)) + { + errmsg ("policer name must be specified"); + return -99; + } + + if (vec_len (name) > 64) + { + errmsg ("policer name too long"); + return -99; + } + + M (POLICER_ADD_DEL, policer_add_del); + + clib_memcpy (mp->name, name, vec_len (name)); + vec_free (name); + mp->is_add = is_add; + mp->cir = cir; + mp->eir = eir; + mp->cb = cb; + mp->eb = eb; + mp->rate_type = rate_type; + mp->round_type = round_type; + mp->type = type; + mp->conform_action_type = conform_action.action_type; + mp->conform_dscp = conform_action.dscp; + mp->exceed_action_type = exceed_action.action_type; + mp->exceed_dscp = exceed_action.dscp; + mp->violate_action_type = violate_action.action_type; + mp->violate_dscp = violate_action.dscp; + mp->color_aware = color_aware; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_dump_t *mp; + f64 timeout = ~0; + u8 *match_name = 0; + u8 match_name_valid = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &match_name)) + { + vec_add1 (match_name, 0); + match_name_valid = 1; + } + else + break; + } + + M (POLICER_DUMP, policer_dump); + mp->match_name_valid = match_name_valid; + clib_memcpy (mp->match_name, match_name, vec_len (match_name)); + vec_free (match_name); + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_policer_classify_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_classify_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u32 l2_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else if (unformat (i, "l2-table %d", &l2_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (POLICER_CLASSIFY_SET_INTERFACE, policer_classify_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->l2_table_index = ntohl (l2_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_policer_classify_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_policer_classify_dump_t *mp; + f64 timeout = ~0; + u8 type = POLICER_CLASSIFY_N_TABLES; + + if (unformat (i, "type %U", unformat_policer_classify_table_type, &type)) + ; + else + { + errmsg ("classify table type must be specified"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%10s%20s", "Intfc idx", "Classify table"); + } + + M (POLICER_CLASSIFY_DUMP, policer_classify_dump); + mp->type = type; + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_netmap_create (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_netmap_create_t *mp; + f64 timeout; + u8 *if_name = 0; + u8 hw_addr[6]; + u8 random_hw_addr = 1; + u8 is_pipe = 0; + u8 is_master = 0; + + memset (hw_addr, 0, sizeof (hw_addr)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &if_name)) + vec_add1 (if_name, 0); + else if (unformat (i, "hw_addr %U", unformat_ethernet_address, hw_addr)) + random_hw_addr = 0; + else if (unformat (i, "pipe")) + is_pipe = 1; + else if (unformat (i, "master")) + is_master = 1; + else if (unformat (i, "slave")) + is_master = 0; + else + break; + } + + if (!vec_len (if_name)) + { + errmsg ("interface name must be specified"); + return -99; + } + + if (vec_len (if_name) > 64) + { + errmsg ("interface name too long"); + return -99; + } + + M (NETMAP_CREATE, netmap_create); + + clib_memcpy (mp->netmap_if_name, if_name, vec_len (if_name)); + clib_memcpy (mp->hw_addr, hw_addr, 6); + mp->use_random_hw_addr = random_hw_addr; + mp->is_pipe = is_pipe; + mp->is_master = is_master; + vec_free (if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_netmap_delete (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_netmap_delete_t *mp; + f64 timeout; + u8 *if_name = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "name %s", &if_name)) + vec_add1 (if_name, 0); + else + break; + } + + if (!vec_len (if_name)) + { + errmsg ("interface name must be specified"); + return -99; + } + + if (vec_len (if_name) > 64) + { + errmsg ("interface name too long"); + return -99; + } + + M (NETMAP_DELETE, netmap_delete); + + clib_memcpy (mp->netmap_if_name, if_name, vec_len (if_name)); + vec_free (if_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_mpls_tunnel_details_t_handler + (vl_api_mpls_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 len = mp->mt_next_hop_n_labels; + i32 i; + + print (vam->ofp, "[%d]: via %U %d labels ", + mp->tunnel_index, + format_ip4_address, mp->mt_next_hop, + ntohl (mp->mt_next_hop_sw_if_index)); + for (i = 0; i < len; i++) + { + print (vam->ofp, "%u ", ntohl (mp->mt_next_hop_out_labels[i])); + } + print (vam->ofp, ""); +} + +static void vl_api_mpls_tunnel_details_t_handler_json + (vl_api_mpls_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + i32 i; + i32 len = mp->mt_next_hop_n_labels; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "tunnel_index", ntohl (mp->tunnel_index)); + clib_memcpy (&ip4, &(mp->mt_next_hop), sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + vat_json_object_add_uint (node, "next_hop_sw_if_index", + ntohl (mp->mt_next_hop_sw_if_index)); + vat_json_object_add_uint (node, "l2_only", ntohl (mp->mt_l2_only)); + vat_json_object_add_uint (node, "label_count", len); + for (i = 0; i < len; i++) + { + vat_json_object_add_uint (node, "label", + ntohl (mp->mt_next_hop_out_labels[i])); + } +} + +static int +api_mpls_tunnel_dump (vat_main_t * vam) +{ + vl_api_mpls_tunnel_dump_t *mp; + f64 timeout; + i32 index = -1; + + /* Parse args required to build the message */ + while (unformat_check_input (vam->input) != UNFORMAT_END_OF_INPUT) + { + if (!unformat (vam->input, "tunnel_index %d", &index)) + { + index = -1; + break; + } + } + + print (vam->ofp, " tunnel_index %d", index); + + M (MPLS_TUNNEL_DUMP, mpls_tunnel_dump); + mp->tunnel_index = htonl (index); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_mpls_fib_details_t_endian vl_noop_handler +#define vl_api_mpls_fib_details_t_print vl_noop_handler + +static void +vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path2_t *fp; + int i; + + print (vam->ofp, + "table-id %d, label %u, ess_bit %u", + ntohl (mp->table_id), ntohl (mp->label), mp->eos_bit); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_mpls_fib_details_t_handler_json + (vl_api_mpls_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path2_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + vat_json_object_add_uint (node, "s_bit", mp->eos_bit); + vat_json_object_add_uint (node, "label", ntohl (mp->label)); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_mpls_fib_dump (vat_main_t * vam) +{ + vl_api_mpls_fib_dump_t *mp; + f64 timeout; + + M (MPLS_FIB_DUMP, mpls_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_ip_fib_details_t_endian vl_noop_handler +#define vl_api_ip_fib_details_t_print vl_noop_handler + +static void +vl_api_ip_fib_details_t_handler (vl_api_ip_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path_t *fp; + int i; + + print (vam->ofp, + "table-id %d, prefix %U/%d", + ntohl (mp->table_id), format_ip4_address, mp->address, + mp->address_length); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_ip_fib_details_t_handler_json + (vl_api_ip_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + clib_memcpy (&ip4, &mp->address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "prefix", ip4); + vat_json_object_add_uint (node, "mask_length", mp->address_length); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_ip_fib_dump (vat_main_t * vam) +{ + vl_api_ip_fib_dump_t *mp; + f64 timeout; + + M (IP_FIB_DUMP, ip_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void vl_api_ip_neighbor_details_t_handler + (vl_api_ip_neighbor_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%c %U %U", + (mp->is_static) ? 'S' : 'D', + format_ethernet_address, &mp->mac_address, + (mp->is_ipv6) ? format_ip6_address : format_ip4_address, + &mp->ip_address); +} + +static void vl_api_ip_neighbor_details_t_handler_json + (vl_api_ip_neighbor_details_t * mp) +{ + + vat_main_t *vam = &vat_main; + vat_json_node_t *node; + struct in_addr ip4; + struct in6_addr ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_string_copy (node, "flag", + (mp->is_static) ? (u8 *) "static" : (u8 *) + "dynamic"); + + vat_json_object_add_string_copy (node, "link_layer", + format (0, "%U", format_ethernet_address, + &mp->mac_address)); + + if (mp->is_ipv6) + { + clib_memcpy (&ip6, &mp->ip_address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "ip_address", ip6); + } + else + { + clib_memcpy (&ip4, &mp->ip_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "ip_address", ip4); + } +} + +static int +api_ip_neighbor_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ip_neighbor_dump_t *mp; + f64 timeout; + u8 is_ipv6 = 0; + u32 sw_if_index = ~0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "ip6")) + is_ipv6 = 1; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (IP_NEIGHBOR_DUMP, ip_neighbor_dump); + mp->is_ipv6 = (u8) is_ipv6; + mp->sw_if_index = ntohl (sw_if_index); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +#define vl_api_ip6_fib_details_t_endian vl_noop_handler +#define vl_api_ip6_fib_details_t_print vl_noop_handler + +static void +vl_api_ip6_fib_details_t_handler (vl_api_ip6_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vl_api_fib_path_t *fp; + int i; + + print (vam->ofp, + "table-id %d, prefix %U/%d", + ntohl (mp->table_id), format_ip6_address, mp->address, + mp->address_length); + fp = mp->path; + for (i = 0; i < count; i++) + { + if (fp->afi == IP46_TYPE_IP6) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip6_address, fp->next_hop); + else if (fp->afi == IP46_TYPE_IP4) + print (vam->ofp, + " weight %d, sw_if_index %d, is_local %d, is_drop %d, " + "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U", + ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local, + fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi, + format_ip4_address, fp->next_hop); + fp++; + } +} + +static void vl_api_ip6_fib_details_t_handler_json + (vl_api_ip6_fib_details_t * mp) +{ + vat_main_t *vam = &vat_main; + int count = ntohl (mp->count); + vat_json_node_t *node = NULL; + struct in_addr ip4; + struct in6_addr ip6; + vl_api_fib_path_t *fp; + int i; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "table", ntohl (mp->table_id)); + clib_memcpy (&ip6, &mp->address, sizeof (ip6)); + vat_json_object_add_ip6 (node, "prefix", ip6); + vat_json_object_add_uint (node, "mask_length", mp->address_length); + vat_json_object_add_uint (node, "path_count", count); + fp = mp->path; + for (i = 0; i < count; i++) + { + vat_json_object_add_uint (node, "weight", ntohl (fp->weight)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index)); + vat_json_object_add_uint (node, "is_local", fp->is_local); + vat_json_object_add_uint (node, "is_drop", fp->is_drop); + vat_json_object_add_uint (node, "is_unreach", fp->is_unreach); + vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit); + vat_json_object_add_uint (node, "next_hop_afi", fp->afi); + if (fp->afi == IP46_TYPE_IP4) + { + clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4)); + vat_json_object_add_ip4 (node, "next_hop", ip4); + } + else if (fp->afi == IP46_TYPE_IP6) + { + clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6)); + vat_json_object_add_ip6 (node, "next_hop", ip6); + } + } +} + +static int +api_ip6_fib_dump (vat_main_t * vam) +{ + vl_api_ip6_fib_dump_t *mp; + f64 timeout; + + M (IP6_FIB_DUMP, ip6_fib_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +int +api_classify_table_ids (vat_main_t * vam) +{ + vl_api_classify_table_ids_t *mp; + f64 timeout; + + /* Construct the API message */ + M (CLASSIFY_TABLE_IDS, classify_table_ids); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_table_by_interface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_table_by_interface_t *mp; + f64 timeout; + + u32 sw_if_index = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (input, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_TABLE_BY_INTERFACE, classify_table_by_interface); + mp->context = 0; + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_table_info (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_table_info_t *mp; + f64 timeout; + + u32 table_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "table_id %d", &table_id)) + ; + else + break; + } + if (table_id == ~0) + { + errmsg ("missing table id"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_TABLE_INFO, classify_table_info); + mp->context = 0; + mp->table_id = ntohl (table_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_classify_session_dump (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_classify_session_dump_t *mp; + f64 timeout; + + u32 table_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "table_id %d", &table_id)) + ; + else + break; + } + if (table_id == ~0) + { + errmsg ("missing table id"); + return -99; + } + + /* Construct the API message */ + M (CLASSIFY_SESSION_DUMP, classify_session_dump); + mp->context = 0; + mp->table_id = ntohl (table_id); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; + /* NOTREACHED */ + return 0; +} + +static void +vl_api_ipfix_exporter_details_t_handler (vl_api_ipfix_exporter_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "collector_address %U, collector_port %d, " + "src_address %U, vrf_id %d, path_mtu %u, " + "template_interval %u, udp_checksum %d", + format_ip4_address, mp->collector_address, + ntohs (mp->collector_port), + format_ip4_address, mp->src_address, + ntohl (mp->vrf_id), ntohl (mp->path_mtu), + ntohl (mp->template_interval), mp->udp_checksum); + + vam->retval = 0; + vam->result_ready = 1; +} + +static void + vl_api_ipfix_exporter_details_t_handler_json + (vl_api_ipfix_exporter_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + struct in_addr collector_address; + struct in_addr src_address; + + vat_json_init_object (&node); + clib_memcpy (&collector_address, &mp->collector_address, + sizeof (collector_address)); + vat_json_object_add_ip4 (&node, "collector_address", collector_address); + vat_json_object_add_uint (&node, "collector_port", + ntohs (mp->collector_port)); + clib_memcpy (&src_address, &mp->src_address, sizeof (src_address)); + vat_json_object_add_ip4 (&node, "src_address", src_address); + vat_json_object_add_int (&node, "vrf_id", ntohl (mp->vrf_id)); + vat_json_object_add_uint (&node, "path_mtu", ntohl (mp->path_mtu)); + vat_json_object_add_uint (&node, "template_interval", + ntohl (mp->template_interval)); + vat_json_object_add_int (&node, "udp_checksum", mp->udp_checksum); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = 0; + vam->result_ready = 1; +} + +int +api_ipfix_exporter_dump (vat_main_t * vam) +{ + vl_api_ipfix_exporter_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (IPFIX_EXPORTER_DUMP, ipfix_exporter_dump); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_ipfix_classify_stream_dump (vat_main_t * vam) +{ + vl_api_ipfix_classify_stream_dump_t *mp; + f64 timeout; + + /* Construct the API message */ + M (IPFIX_CLASSIFY_STREAM_DUMP, ipfix_classify_stream_dump); + mp->context = 0; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void + vl_api_ipfix_classify_stream_details_t_handler + (vl_api_ipfix_classify_stream_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, "domain_id %d, src_port %d", + ntohl (mp->domain_id), ntohs (mp->src_port)); + vam->retval = 0; + vam->result_ready = 1; +} + +static void + vl_api_ipfix_classify_stream_details_t_handler_json + (vl_api_ipfix_classify_stream_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_uint (&node, "domain_id", ntohl (mp->domain_id)); + vat_json_object_add_uint (&node, "src_port", ntohs (mp->src_port)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = 0; + vam->result_ready = 1; +} + +static int +api_ipfix_classify_table_dump (vat_main_t * vam) +{ + vl_api_ipfix_classify_table_dump_t *mp; + f64 timeout; + + if (!vam->json_output) + { + print (vam->ofp, "%15s%15s%20s", "table_id", "ip_version", + "transport_protocol"); + } + + /* Construct the API message */ + M (IPFIX_CLASSIFY_TABLE_DUMP, ipfix_classify_table_dump); + + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static void + vl_api_ipfix_classify_table_details_t_handler + (vl_api_ipfix_classify_table_details_t * mp) +{ + vat_main_t *vam = &vat_main; + print (vam->ofp, "%15d%15d%20d", ntohl (mp->table_id), mp->ip_version, + mp->transport_protocol); +} + +static void + vl_api_ipfix_classify_table_details_t_handler_json + (vl_api_ipfix_classify_table_details_t * mp) +{ + vat_json_node_t *node = NULL; + vat_main_t *vam = &vat_main; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + + node = vat_json_array_add (&vam->json_tree); + vat_json_init_object (node); + + vat_json_object_add_uint (node, "table_id", ntohl (mp->table_id)); + vat_json_object_add_uint (node, "ip_version", mp->ip_version); + vat_json_object_add_uint (node, "transport_protocol", + mp->transport_protocol); +} + +static int +api_sw_interface_span_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_span_enable_disable_t *mp; + f64 timeout; + u32 src_sw_if_index = ~0; + u32 dst_sw_if_index = ~0; + u8 state = 3; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (i, "src %U", api_unformat_sw_if_index, vam, &src_sw_if_index)) + ; + else if (unformat (i, "src_sw_if_index %d", &src_sw_if_index)) + ; + else + if (unformat + (i, "dst %U", api_unformat_sw_if_index, vam, &dst_sw_if_index)) + ; + else if (unformat (i, "dst_sw_if_index %d", &dst_sw_if_index)) + ; + else if (unformat (i, "disable")) + state = 0; + else if (unformat (i, "rx")) + state = 1; + else if (unformat (i, "tx")) + state = 2; + else if (unformat (i, "both")) + state = 3; + else + break; + } + + M (SW_INTERFACE_SPAN_ENABLE_DISABLE, sw_interface_span_enable_disable); + + mp->sw_if_index_from = htonl (src_sw_if_index); + mp->sw_if_index_to = htonl (dst_sw_if_index); + mp->state = state; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void +vl_api_sw_interface_span_details_t_handler (vl_api_sw_interface_span_details_t + * mp) +{ + vat_main_t *vam = &vat_main; + u8 *sw_if_from_name = 0; + u8 *sw_if_to_name = 0; + u32 sw_if_index_from = ntohl (mp->sw_if_index_from); + u32 sw_if_index_to = ntohl (mp->sw_if_index_to); + char *states[] = { "none", "rx", "tx", "both" }; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index_from) + { + sw_if_from_name = (u8 *)(p->key); + if (sw_if_to_name) + break; + } + if ((u32) p->value[0] == sw_if_index_to) + { + sw_if_to_name = (u8 *)(p->key); + if (sw_if_from_name) + break; + } + })); + /* *INDENT-ON* */ + print (vam->ofp, "%20s => %20s (%s)", + sw_if_from_name, sw_if_to_name, states[mp->state]); +} + +static void + vl_api_sw_interface_span_details_t_handler_json + (vl_api_sw_interface_span_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + u8 *sw_if_from_name = 0; + u8 *sw_if_to_name = 0; + u32 sw_if_index_from = ntohl (mp->sw_if_index_from); + u32 sw_if_index_to = ntohl (mp->sw_if_index_to); + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->sw_if_index_by_interface_name, + ({ + if ((u32) p->value[0] == sw_if_index_from) + { + sw_if_from_name = (u8 *)(p->key); + if (sw_if_to_name) + break; + } + if ((u32) p->value[0] == sw_if_index_to) + { + sw_if_to_name = (u8 *)(p->key); + if (sw_if_from_name) + break; + } + })); + /* *INDENT-ON* */ + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "src-if-index", sw_if_index_from); + vat_json_object_add_string_copy (node, "src-if-name", sw_if_from_name); + vat_json_object_add_uint (node, "dst-if-index", sw_if_index_to); + vat_json_object_add_string_copy (node, "dst-if-name", sw_if_to_name); + vat_json_object_add_uint (node, "state", mp->state); +} + +static int +api_sw_interface_span_dump (vat_main_t * vam) +{ + vl_api_sw_interface_span_dump_t *mp; + f64 timeout; + + M (SW_INTERFACE_SPAN_DUMP, sw_interface_span_dump); + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +int +api_pg_create_interface (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_create_interface_t *mp; + f64 timeout; + + u32 if_id = ~0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "if_id %d", &if_id)) + ; + else + break; + } + if (if_id == ~0) + { + errmsg ("missing pg interface index"); + return -99; + } + + /* Construct the API message */ + M (PG_CREATE_INTERFACE, pg_create_interface); + mp->context = 0; + mp->interface_id = ntohl (if_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_pg_capture (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_capture_t *mp; + f64 timeout; + + u32 if_id = ~0; + u8 enable = 1; + u32 count = 1; + u8 pcap_file_set = 0; + u8 *pcap_file = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "if_id %d", &if_id)) + ; + else if (unformat (input, "pcap %s", &pcap_file)) + pcap_file_set = 1; + else if (unformat (input, "count %d", &count)) + ; + else if (unformat (input, "disable")) + enable = 0; + else + break; + } + if (if_id == ~0) + { + errmsg ("missing pg interface index"); + return -99; + } + if (pcap_file_set > 0) + { + if (vec_len (pcap_file) > 255) + { + errmsg ("pcap file name is too long"); + return -99; + } + } + + u32 name_len = vec_len (pcap_file); + /* Construct the API message */ + M (PG_CAPTURE, pg_capture); + mp->context = 0; + mp->interface_id = ntohl (if_id); + mp->is_enabled = enable; + mp->count = ntohl (count); + mp->pcap_name_length = ntohl (name_len); + if (pcap_file_set != 0) + { + clib_memcpy (mp->pcap_file_name, pcap_file, name_len); + } + vec_free (pcap_file); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_pg_enable_disable (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_pg_enable_disable_t *mp; + f64 timeout; + + u8 enable = 1; + u8 stream_name_set = 0; + u8 *stream_name = 0; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "stream %s", &stream_name)) + stream_name_set = 1; + else if (unformat (input, "disable")) + enable = 0; + else + break; + } + + if (stream_name_set > 0) + { + if (vec_len (stream_name) > 255) + { + errmsg ("stream name too long"); + return -99; + } + } + + u32 name_len = vec_len (stream_name); + /* Construct the API message */ + M (PG_ENABLE_DISABLE, pg_enable_disable); + mp->context = 0; + mp->is_enabled = enable; + if (stream_name_set != 0) + { + mp->stream_name_length = ntohl (name_len); + clib_memcpy (mp->stream_name, stream_name, name_len); + } + vec_free (stream_name); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_ip_source_and_port_range_check_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ip_source_and_port_range_check_add_del_t *mp; + f64 timeout; + + u16 *low_ports = 0; + u16 *high_ports = 0; + u16 this_low; + u16 this_hi; + ip4_address_t ip4_addr; + ip6_address_t ip6_addr; + u32 length; + u32 tmp, tmp2; + u8 prefix_set = 0; + u32 vrf_id = ~0; + u8 is_add = 1; + u8 is_ipv6 = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U/%d", unformat_ip4_address, &ip4_addr, &length)) + { + prefix_set = 1; + } + else + if (unformat + (input, "%U/%d", unformat_ip6_address, &ip6_addr, &length)) + { + prefix_set = 1; + is_ipv6 = 1; + } + else if (unformat (input, "vrf %d", &vrf_id)) + ; + else if (unformat (input, "del")) + is_add = 0; + else if (unformat (input, "port %d", &tmp)) + { + if (tmp == 0 || tmp > 65535) + { + errmsg ("port %d out of range", tmp); + return -99; + } + this_low = tmp; + this_hi = this_low + 1; + vec_add1 (low_ports, this_low); + vec_add1 (high_ports, this_hi); + } + else if (unformat (input, "range %d - %d", &tmp, &tmp2)) + { + if ((tmp > tmp2) || (tmp == 0) || (tmp2 > 65535)) + { + errmsg ("incorrect range parameters"); + return -99; + } + this_low = tmp; + /* Note: in debug CLI +1 is added to high before + passing to real fn that does "the work" + (ip_source_and_port_range_check_add_del). + This fn is a wrapper around the binary API fn a + control plane will call, which expects this increment + to have occurred. Hence letting the binary API control + plane fn do the increment for consistency between VAT + and other control planes. + */ + this_hi = tmp2; + vec_add1 (low_ports, this_low); + vec_add1 (high_ports, this_hi); + } + else + break; + } + + if (prefix_set == 0) + { + errmsg ("
/ not specified"); + return -99; + } + + if (vrf_id == ~0) + { + errmsg ("VRF ID required, not specified"); + return -99; + } + + if (vrf_id == 0) + { + errmsg + ("VRF ID should not be default. Should be distinct VRF for this purpose."); + return -99; + } + + if (vec_len (low_ports) == 0) + { + errmsg ("At least one port or port range required"); + return -99; + } + + M (IP_SOURCE_AND_PORT_RANGE_CHECK_ADD_DEL, + ip_source_and_port_range_check_add_del); + + mp->is_add = is_add; + + if (is_ipv6) + { + mp->is_ipv6 = 1; + clib_memcpy (mp->address, &ip6_addr, sizeof (ip6_addr)); + } + else + { + mp->is_ipv6 = 0; + clib_memcpy (mp->address, &ip4_addr, sizeof (ip4_addr)); + } + + mp->mask_length = length; + mp->number_of_ranges = vec_len (low_ports); + + clib_memcpy (mp->low_ports, low_ports, vec_len (low_ports)); + vec_free (low_ports); + + clib_memcpy (mp->high_ports, high_ports, vec_len (high_ports)); + vec_free (high_ports); + + mp->vrf_id = ntohl (vrf_id); + + S; + W; + /* NOTREACHED */ + return 0; +} + +int +api_ip_source_and_port_range_check_interface_add_del (vat_main_t * vam) +{ + unformat_input_t *input = vam->input; + vl_api_ip_source_and_port_range_check_interface_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + int vrf_set = 0; + u32 tcp_out_vrf_id = ~0, udp_out_vrf_id = ~0; + u32 tcp_in_vrf_id = ~0, udp_in_vrf_id = ~0; + u8 is_add = 1; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (input, "tcp-out-vrf %d", &tcp_out_vrf_id)) + vrf_set = 1; + else if (unformat (input, "udp-out-vrf %d", &udp_out_vrf_id)) + vrf_set = 1; + else if (unformat (input, "tcp-in-vrf %d", &tcp_in_vrf_id)) + vrf_set = 1; + else if (unformat (input, "udp-in-vrf %d", &udp_in_vrf_id)) + vrf_set = 1; + else if (unformat (input, "del")) + is_add = 0; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("Interface required but not specified"); + return -99; + } + + if (vrf_set == 0) + { + errmsg ("VRF ID required but not specified"); + return -99; + } + + if (tcp_out_vrf_id == 0 + || udp_out_vrf_id == 0 || tcp_in_vrf_id == 0 || udp_in_vrf_id == 0) + { + errmsg + ("VRF ID should not be default. Should be distinct VRF for this purpose."); + return -99; + } + + /* Construct the API message */ + M (IP_SOURCE_AND_PORT_RANGE_CHECK_INTERFACE_ADD_DEL, + ip_source_and_port_range_check_interface_add_del); + + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = is_add; + mp->tcp_out_vrf_id = ntohl (tcp_out_vrf_id); + mp->udp_out_vrf_id = ntohl (udp_out_vrf_id); + mp->tcp_in_vrf_id = ntohl (tcp_in_vrf_id); + mp->udp_in_vrf_id = ntohl (udp_in_vrf_id); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; +} + +static int +api_ipsec_gre_add_del_tunnel (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_gre_add_del_tunnel_t *mp; + f64 timeout; + u32 local_sa_id = 0; + u32 remote_sa_id = 0; + ip4_address_t src_address; + ip4_address_t dst_address; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "local_sa %d", &local_sa_id)) + ; + else if (unformat (i, "remote_sa %d", &remote_sa_id)) + ; + else if (unformat (i, "src %U", unformat_ip4_address, &src_address)) + ; + else if (unformat (i, "dst %U", unformat_ip4_address, &dst_address)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (IPSEC_GRE_ADD_DEL_TUNNEL, ipsec_gre_add_del_tunnel); + + mp->local_sa_id = ntohl (local_sa_id); + mp->remote_sa_id = ntohl (remote_sa_id); + clib_memcpy (mp->src_address, &src_address, sizeof (src_address)); + clib_memcpy (mp->dst_address, &dst_address, sizeof (dst_address)); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_punt (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_punt_t *mp; + f64 timeout; + u32 ipv = ~0; + u32 protocol = ~0; + u32 port = ~0; + int is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "ip %d", &ipv)) + ; + else if (unformat (i, "protocol %d", &protocol)) + ; + else if (unformat (i, "port %d", &port)) + ; + else if (unformat (i, "del")) + is_add = 0; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (PUNT, punt); + + mp->is_add = (u8) is_add; + mp->ipv = (u8) ipv; + mp->l4_protocol = (u8) protocol; + mp->l4_port = htons ((u16) port); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static void vl_api_ipsec_gre_tunnel_details_t_handler + (vl_api_ipsec_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%11d%15U%15U%14d%14d", + ntohl (mp->sw_if_index), + format_ip4_address, &mp->src_address, + format_ip4_address, &mp->dst_address, + ntohl (mp->local_sa_id), ntohl (mp->remote_sa_id)); +} + +static void vl_api_ipsec_gre_tunnel_details_t_handler_json + (vl_api_ipsec_gre_tunnel_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr ip4; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + clib_memcpy (&ip4, &mp->src_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "src_address", ip4); + clib_memcpy (&ip4, &mp->dst_address, sizeof (ip4)); + vat_json_object_add_ip4 (node, "dst_address", ip4); + vat_json_object_add_uint (node, "local_sa_id", ntohl (mp->local_sa_id)); + vat_json_object_add_uint (node, "remote_sa_id", ntohl (mp->remote_sa_id)); +} + +static int +api_ipsec_gre_tunnel_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_gre_tunnel_dump_t *mp; + f64 timeout; + u32 sw_if_index; + u8 sw_if_index_set = 0; + + /* Parse args required to build the message */ + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else + break; + } + + if (sw_if_index_set == 0) + { + sw_if_index = ~0; + } + + if (!vam->json_output) + { + print (vam->ofp, "%11s%15s%15s%14s%14s", + "sw_if_index", "src_address", "dst_address", + "local_sa_id", "remote_sa_id"); + } + + /* Get list of gre-tunnel interfaces */ + M (IPSEC_GRE_TUNNEL_DUMP, ipsec_gre_tunnel_dump); + + mp->sw_if_index = htonl (sw_if_index); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_delete_subif (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_delete_subif_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (DELETE_SUBIF, delete_subif); + mp->sw_if_index = ntohl (sw_if_index); + + S; + W; +} + +#define foreach_pbb_vtr_op \ +_("disable", L2_VTR_DISABLED) \ +_("pop", L2_VTR_POP_2) \ +_("push", L2_VTR_PUSH_2) + +static int +api_l2_interface_pbb_tag_rewrite (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_l2_interface_pbb_tag_rewrite_t *mp; + f64 timeout; + u32 sw_if_index = ~0, vtr_op = ~0; + u16 outer_tag = ~0; + u8 dmac[6], smac[6]; + u8 dmac_set = 0, smac_set = 0; + u16 vlanid = 0; + u32 sid = ~0; + u32 tmp; + + /* Shut up coverity */ + memset (dmac, 0, sizeof (dmac)); + memset (smac, 0, sizeof (smac)); + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "vtr_op %d", &vtr_op)) + ; +#define _(n,v) else if (unformat(i, n)) {vtr_op = v;} + foreach_pbb_vtr_op +#undef _ + else if (unformat (i, "translate_pbb_stag")) + { + if (unformat (i, "%d", &tmp)) + { + vtr_op = L2_VTR_TRANSLATE_2_1; + outer_tag = tmp; + } + else + { + errmsg + ("translate_pbb_stag operation requires outer tag definition"); + return -99; + } + } + else if (unformat (i, "dmac %U", unformat_ethernet_address, dmac)) + dmac_set++; + else if (unformat (i, "smac %U", unformat_ethernet_address, smac)) + smac_set++; + else if (unformat (i, "sid %d", &sid)) + ; + else if (unformat (i, "vlanid %d", &tmp)) + vlanid = tmp; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if ((sw_if_index == ~0) || (vtr_op == ~0)) + { + errmsg ("missing sw_if_index or vtr operation"); + return -99; + } + if (((vtr_op == L2_VTR_PUSH_2) || (vtr_op == L2_VTR_TRANSLATE_2_2)) + && ((dmac_set == 0) || (smac_set == 0) || (sid == ~0))) + { + errmsg + ("push and translate_qinq operations require dmac, smac, sid and optionally vlanid"); + return -99; + } + + M (L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite); + mp->sw_if_index = ntohl (sw_if_index); + mp->vtr_op = ntohl (vtr_op); + mp->outer_tag = ntohs (outer_tag); + clib_memcpy (mp->b_dmac, dmac, sizeof (dmac)); + clib_memcpy (mp->b_smac, smac, sizeof (smac)); + mp->b_vlanid = ntohs (vlanid); + mp->i_sid = ntohl (sid); + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_flow_classify_set_interface (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_flow_classify_set_interface_t *mp; + f64 timeout; + u32 sw_if_index; + int sw_if_index_set; + u32 ip4_table_index = ~0; + u32 ip6_table_index = ~0; + u8 is_add = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + sw_if_index_set = 1; + else if (unformat (i, "del")) + is_add = 0; + else if (unformat (i, "ip4-table %d", &ip4_table_index)) + ; + else if (unformat (i, "ip6-table %d", &ip6_table_index)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sw_if_index_set == 0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + M (FLOW_CLASSIFY_SET_INTERFACE, flow_classify_set_interface); + + mp->sw_if_index = ntohl (sw_if_index); + mp->ip4_table_index = ntohl (ip4_table_index); + mp->ip6_table_index = ntohl (ip6_table_index); + mp->is_add = is_add; + + S; + W; + /* NOTREACHED */ + return 0; +} + +static int +api_flow_classify_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_flow_classify_dump_t *mp; + f64 timeout = ~0; + u8 type = FLOW_CLASSIFY_N_TABLES; + + if (unformat (i, "type %U", unformat_flow_classify_table_type, &type)) + ; + else + { + errmsg ("classify table type must be specified"); + return -99; + } + + if (!vam->json_output) + { + print (vam->ofp, "%10s%20s", "Intfc idx", "Classify table"); + } + + M (FLOW_CLASSIFY_DUMP, flow_classify_dump); + mp->type = type; + /* send it... */ + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + +static int +api_feature_enable_disable (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_feature_enable_disable_t *mp; + f64 timeout; + u8 *arc_name = 0; + u8 *feature_name = 0; + u32 sw_if_index = ~0; + u8 enable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "arc_name %s", &arc_name)) + ; + else if (unformat (i, "feature_name %s", &feature_name)) + ; + else + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "disable")) + enable = 0; + else + break; + } + + if (arc_name == 0) + { + errmsg ("missing arc name"); + return -99; + } + if (vec_len (arc_name) > 63) + { + errmsg ("arc name too long"); + } + + if (feature_name == 0) + { + errmsg ("missing feature name"); + return -99; + } + if (vec_len (feature_name) > 63) + { + errmsg ("feature name too long"); + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + /* Construct the API message */ + M (FEATURE_ENABLE_DISABLE, feature_enable_disable); + mp->sw_if_index = ntohl (sw_if_index); + mp->enable = enable; + clib_memcpy (mp->arc_name, arc_name, vec_len (arc_name)); + clib_memcpy (mp->feature_name, feature_name, vec_len (feature_name)); + vec_free (arc_name); + vec_free (feature_name); + + S; + W; +} + +static int +api_sw_interface_tag_add_del (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_tag_add_del_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u8 *tag = 0; + u8 enable = 1; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "tag %s", &tag)) + ; + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (i, "del")) + enable = 0; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (enable && (tag == 0)) + { + errmsg ("no tag specified"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del); + mp->sw_if_index = ntohl (sw_if_index); + mp->is_add = enable; + if (enable) + strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1); + vec_free (tag); + + S; + W; +} + +static void vl_api_l2_xconnect_details_t_handler + (vl_api_l2_xconnect_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "%15d%15d", + ntohl (mp->rx_sw_if_index), ntohl (mp->tx_sw_if_index)); +} + +static void vl_api_l2_xconnect_details_t_handler_json + (vl_api_l2_xconnect_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "rx_sw_if_index", + ntohl (mp->rx_sw_if_index)); + vat_json_object_add_uint (node, "tx_sw_if_index", + ntohl (mp->tx_sw_if_index)); +} + +static int +api_l2_xconnect_dump (vat_main_t * vam) +{ + vl_api_l2_xconnect_dump_t *mp; + f64 timeout; + + if (!vam->json_output) + { + print (vam->ofp, "%15s%15s", "rx_sw_if_index", "tx_sw_if_index"); + } + + M (L2_XCONNECT_DUMP, l2_xconnect_dump); + + S; + + /* Use a control ping for synchronization */ + { + vl_api_control_ping_t *mp; + M (CONTROL_PING, control_ping); + S; + } + W; +} + +static int +api_sw_interface_set_mtu (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_sw_interface_set_mtu_t *mp; + f64 timeout; + u32 sw_if_index = ~0; + u32 mtu = 0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "mtu %d", &mtu)) + ; + if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index)) + ; + else if (unformat (i, "sw_if_index %d", &sw_if_index)) + ; + else + break; + } + + if (sw_if_index == ~0) + { + errmsg ("missing interface name or sw_if_index"); + return -99; + } + + if (mtu == 0) + { + errmsg ("no mtu specified"); + return -99; + } + + /* Construct the API message */ + M (SW_INTERFACE_SET_MTU, sw_interface_set_mtu); + mp->sw_if_index = ntohl (sw_if_index); + mp->mtu = ntohs ((u16) mtu); + + S; + W; +} + + +static int +q_or_quit (vat_main_t * vam) +{ + longjmp (vam->jump_buf, 1); + return 0; /* not so much */ +} + +static int +q (vat_main_t * vam) +{ + return q_or_quit (vam); +} + +static int +quit (vat_main_t * vam) +{ + return q_or_quit (vam); +} + +static int +comment (vat_main_t * vam) +{ + return 0; +} + +static int +cmd_cmp (void *a1, void *a2) +{ + u8 **c1 = a1; + u8 **c2 = a2; + + return strcmp ((char *) (c1[0]), (char *) (c2[0])); +} + +static int +help (vat_main_t * vam) +{ + u8 **cmds = 0; + u8 *name = 0; + hash_pair_t *p; + unformat_input_t *i = vam->input; + int j; + + if (unformat (i, "%s", &name)) + { + uword *hs; + + vec_add1 (name, 0); + + hs = hash_get_mem (vam->help_by_name, name); + if (hs) + print (vam->ofp, "usage: %s %s", name, hs[0]); + else + print (vam->ofp, "No such msg / command '%s'", name); + vec_free (name); + return 0; + } + + print (vam->ofp, "Help is available for the following:"); + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->function_by_name, + ({ + vec_add1 (cmds, (u8 *)(p->key)); + })); + /* *INDENT-ON* */ + + vec_sort_with_function (cmds, cmd_cmp); + + for (j = 0; j < vec_len (cmds); j++) + print (vam->ofp, "%s", cmds[j]); + + vec_free (cmds); + return 0; +} + +static int +set (vat_main_t * vam) +{ + u8 *name = 0, *value = 0; + unformat_input_t *i = vam->input; + + if (unformat (i, "%s", &name)) + { + /* The input buffer is a vector, not a string. */ + value = vec_dup (i->buffer); + vec_delete (value, i->index, 0); + /* Almost certainly has a trailing newline */ + if (value[vec_len (value) - 1] == '\n') + value[vec_len (value) - 1] = 0; + /* Make sure it's a proper string, one way or the other */ + vec_add1 (value, 0); + (void) clib_macro_set_value (&vam->macro_main, + (char *) name, (char *) value); + } + else + errmsg ("usage: set "); + + vec_free (name); + vec_free (value); + return 0; +} + +static int +unset (vat_main_t * vam) +{ + u8 *name = 0; + + if (unformat (vam->input, "%s", &name)) + if (clib_macro_unset (&vam->macro_main, (char *) name) == 1) + errmsg ("unset: %s wasn't set", name); + vec_free (name); + return 0; +} + +typedef struct +{ + u8 *name; + u8 *value; +} macro_sort_t; + + +static int +macro_sort_cmp (void *a1, void *a2) +{ + macro_sort_t *s1 = a1; + macro_sort_t *s2 = a2; + + return strcmp ((char *) (s1->name), (char *) (s2->name)); +} + +static int +dump_macro_table (vat_main_t * vam) +{ + macro_sort_t *sort_me = 0, *sm; + int i; + hash_pair_t *p; + + /* *INDENT-OFF* */ + hash_foreach_pair (p, vam->macro_main.the_value_table_hash, + ({ + vec_add2 (sort_me, sm, 1); + sm->name = (u8 *)(p->key); + sm->value = (u8 *) (p->value[0]); + })); + /* *INDENT-ON* */ + + vec_sort_with_function (sort_me, macro_sort_cmp); + + if (vec_len (sort_me)) + print (vam->ofp, "%-15s%s", "Name", "Value"); + else + print (vam->ofp, "The macro table is empty..."); + + for (i = 0; i < vec_len (sort_me); i++) + print (vam->ofp, "%-15s%s", sort_me[i].name, sort_me[i].value); + return 0; +} + +static int +dump_node_table (vat_main_t * vam) +{ + int i, j; + vlib_node_t *node, *next_node; + + if (vec_len (vam->graph_nodes) == 0) + { + print (vam->ofp, "Node table empty, issue get_node_graph..."); + return 0; + } + + for (i = 0; i < vec_len (vam->graph_nodes); i++) + { + node = vam->graph_nodes[i]; + print (vam->ofp, "[%d] %s", i, node->name); + for (j = 0; j < vec_len (node->next_nodes); j++) + { + if (node->next_nodes[j] != ~0) + { + next_node = vam->graph_nodes[node->next_nodes[j]]; + print (vam->ofp, " [%d] %s", j, next_node->name); + } + } + } + return 0; +} + +static int +value_sort_cmp (void *a1, void *a2) +{ + name_sort_t *n1 = a1; + name_sort_t *n2 = a2; + + if (n1->value < n2->value) + return -1; + if (n1->value > n2->value) + return 1; + return 0; +} + + +static int +dump_msg_api_table (vat_main_t * vam) +{ + api_main_t *am = &api_main; + name_sort_t *nses = 0, *ns; + hash_pair_t *hp; + int i; + + /* *INDENT-OFF* */ + hash_foreach_pair (hp, am->msg_index_by_name_and_crc, + ({ + vec_add2 (nses, ns, 1); + ns->name = (u8 *)(hp->key); + ns->value = (u32) hp->value[0]; + })); + /* *INDENT-ON* */ + + vec_sort_with_function (nses, value_sort_cmp); + + for (i = 0; i < vec_len (nses); i++) + print (vam->ofp, " [%d]: %s", nses[i].value, nses[i].name); + vec_free (nses); + return 0; +} + +static int +get_msg_id (vat_main_t * vam) +{ + u8 *name_and_crc; + u32 message_index; + + if (unformat (vam->input, "%s", &name_and_crc)) + { + message_index = vl_api_get_msg_index (name_and_crc); + if (message_index == ~0) + { + print (vam->ofp, " '%s' not found", name_and_crc); + return 0; + } + print (vam->ofp, " '%s' has message index %d", + name_and_crc, message_index); + return 0; + } + errmsg ("name_and_crc required..."); + return 0; +} + +static int +search_node_table (vat_main_t * vam) +{ + unformat_input_t *line_input = vam->input; + u8 *node_to_find; + int j; + vlib_node_t *node, *next_node; + uword *p; + + if (vam->graph_node_index_by_name == 0) + { + print (vam->ofp, "Node table empty, issue get_node_graph..."); + return 0; + } + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%s", &node_to_find)) + { + vec_add1 (node_to_find, 0); + p = hash_get_mem (vam->graph_node_index_by_name, node_to_find); + if (p == 0) + { + print (vam->ofp, "%s not found...", node_to_find); + goto out; + } + node = vam->graph_nodes[p[0]]; + print (vam->ofp, "[%d] %s", p[0], node->name); + for (j = 0; j < vec_len (node->next_nodes); j++) + { + if (node->next_nodes[j] != ~0) + { + next_node = vam->graph_nodes[node->next_nodes[j]]; + print (vam->ofp, " [%d] %s", j, next_node->name); + } + } + } + + else + { + clib_warning ("parse error '%U'", format_unformat_error, + line_input); + return -99; + } + + out: + vec_free (node_to_find); + + } + + return 0; +} + + +static int +script (vat_main_t * vam) +{ +#if (VPP_API_TEST_BUILTIN==0) + u8 *s = 0; + char *save_current_file; + unformat_input_t save_input; + jmp_buf save_jump_buf; + u32 save_line_number; + + FILE *new_fp, *save_ifp; + + if (unformat (vam->input, "%s", &s)) + { + new_fp = fopen ((char *) s, "r"); + if (new_fp == 0) + { + errmsg ("Couldn't open script file %s", s); + vec_free (s); + return -99; + } + } + else + { + errmsg ("Missing script name"); + return -99; + } + + clib_memcpy (&save_input, &vam->input, sizeof (save_input)); + clib_memcpy (&save_jump_buf, &vam->jump_buf, sizeof (save_jump_buf)); + save_ifp = vam->ifp; + save_line_number = vam->input_line_number; + save_current_file = (char *) vam->current_file; + + vam->input_line_number = 0; + vam->ifp = new_fp; + vam->current_file = s; + do_one_file (vam); + + clib_memcpy (&vam->input, &save_input, sizeof (vam->input)); + clib_memcpy (&vam->jump_buf, &save_jump_buf, sizeof (save_jump_buf)); + vam->ifp = save_ifp; + vam->input_line_number = save_line_number; + vam->current_file = (u8 *) save_current_file; + vec_free (s); + + return 0; +#else + clib_warning ("use the exec command..."); + return -99; +#endif +} + +static int +echo (vat_main_t * vam) +{ + print (vam->ofp, "%v", vam->input->buffer); + return 0; +} + +/* List of API message constructors, CLI names map to api_xxx */ +#define foreach_vpe_api_msg \ +_(create_loopback,"[mac ]") \ +_(sw_interface_dump,"") \ +_(sw_interface_set_flags, \ + " | sw_if_index admin-up | admin-down link-up | link down") \ +_(sw_interface_add_del_address, \ + " | sw_if_index | [del] [del-all] ") \ +_(sw_interface_set_table, \ + " | sw_if_index vrf [ipv6]") \ +_(sw_interface_set_mpls_enable, \ + " | sw_if_index [disable | dis]") \ +_(sw_interface_set_vpath, \ + " | sw_if_index enable | disable") \ +_(sw_interface_set_vxlan_bypass, \ + " | sw_if_index [ip4 | ip6] enable | disable") \ +_(sw_interface_set_l2_xconnect, \ + "rx | rx_sw_if_index tx | tx_sw_if_index \n" \ + "enable | disable") \ +_(sw_interface_set_l2_bridge, \ + " | sw_if_index bd_id \n" \ + "[shg ] [bvi]\n" \ + "enable | disable") \ +_(sw_interface_set_dpdk_hqos_pipe, \ + "rx | sw_if_index subport pipe \n" \ + "profile \n") \ +_(sw_interface_set_dpdk_hqos_subport, \ + "rx | sw_if_index subport [rate ]\n" \ + "[bktsize ] [tc0 ] [tc1 ] [tc2 ] [tc3 ] [period ]\n") \ +_(sw_interface_set_dpdk_hqos_tctbl, \ + "rx | sw_if_index entry tc queue \n") \ +_(bridge_domain_add_del, \ + "bd_id [flood 1|0] [uu-flood 1|0] [forward 1|0] [learn 1|0] [arp-term 1|0] [del]\n") \ +_(bridge_domain_dump, "[bd_id ]\n") \ +_(l2fib_add_del, \ + "mac bd_id [del] | sw_if | sw_if_index [static] [filter] [bvi] [count ]\n") \ +_(l2_flags, \ + "sw_if | sw_if_index [learn] [forward] [uu-flood] [flood]\n") \ +_(bridge_flags, \ + "bd_id [learn] [forward] [uu-flood] [flood] [arp-term] [disable]\n") \ +_(tap_connect, \ + "tapname mac | random-mac [tag ]") \ +_(tap_modify, \ + " | sw_if_index tapname mac | random-mac") \ +_(tap_delete, \ + " | sw_if_index ") \ +_(sw_interface_tap_dump, "") \ +_(ip_add_del_route, \ + "/ via [table-id ]\n" \ + "[ | sw_if_index ] [resolve-attempts ]\n" \ + "[weight ] [drop] [local] [classify ] [del]\n" \ + "[multipath] [count ]") \ +_(mpls_route_add_del, \ + "