This is the first commit of the hicn project 53/16853/14 v19.01
authorLuca Muscariello <lumuscar+fdio@cisco.com>
Thu, 17 Jan 2019 12:47:57 +0000 (13:47 +0100)
committerLuca Muscariello <lumuscar+fdio@cisco.com>
Thu, 17 Jan 2019 15:32:51 +0000 (16:32 +0100)
Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
556 files changed:
.gitreview [new file with mode: 0644]
AUTHORS [new file with mode: 0755]
CMakeLists.txt [new file with mode: 0755]
LICENSE [new file with mode: 0755]
README.md [new file with mode: 0755]
apps/README.md [new file with mode: 0755]
cmake/Modules/BuildMacros.cmake [new file with mode: 0755]
cmake/Modules/FindAsio.cmake [new file with mode: 0755]
cmake/Modules/FindGFlags.cmake [new file with mode: 0755]
cmake/Modules/FindGlog.cmake [new file with mode: 0755]
cmake/Modules/FindHicnBinaryApi.cmake [new file with mode: 0755]
cmake/Modules/FindLibEvent.cmake [new file with mode: 0755]
cmake/Modules/FindLibhicn.cmake [new file with mode: 0755]
cmake/Modules/FindLibmemif.cmake [new file with mode: 0755]
cmake/Modules/FindLibparc.cmake [new file with mode: 0755]
cmake/Modules/FindLibtransport.cmake [new file with mode: 0755]
cmake/Modules/FindLongBow.cmake [new file with mode: 0755]
cmake/Modules/FindUncrustify.cmake [new file with mode: 0755]
cmake/Modules/FindVpp.cmake [new file with mode: 0755]
cmake/Modules/IosMacros.cmake [new file with mode: 0755]
cmake/Modules/Packager.cmake [new file with mode: 0755]
cmake/Modules/detectCacheSize.cmake [new file with mode: 0755]
hicn-light/CMakeLists.txt [new file with mode: 0755]
hicn-light/README.md [new file with mode: 0755]
hicn-light/config/hicn-light.service [new file with mode: 0755]
hicn-light/src/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/command_line/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/command_line/controller/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/command_line/controller/hicnLightControl_main.c [new file with mode: 0755]
hicn-light/src/command_line/daemon/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/command_line/daemon/hicnLightDaemon_main.c [new file with mode: 0755]
hicn-light/src/config.h.in [new file with mode: 0755]
hicn-light/src/config/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/config/commandOps.c [new file with mode: 0755]
hicn-light/src/config/commandOps.h [new file with mode: 0755]
hicn-light/src/config/commandParser.c [new file with mode: 0755]
hicn-light/src/config/commandParser.h [new file with mode: 0755]
hicn-light/src/config/commandReturn.h [new file with mode: 0755]
hicn-light/src/config/configuration.c [new file with mode: 0755]
hicn-light/src/config/configuration.h [new file with mode: 0755]
hicn-light/src/config/configurationFile.c [new file with mode: 0755]
hicn-light/src/config/configurationFile.h [new file with mode: 0755]
hicn-light/src/config/configurationListeners.c [new file with mode: 0755]
hicn-light/src/config/configurationListeners.h [new file with mode: 0755]
hicn-light/src/config/controlAdd.c [new file with mode: 0755]
hicn-light/src/config/controlAdd.h [new file with mode: 0755]
hicn-light/src/config/controlAddConnection.c [new file with mode: 0755]
hicn-light/src/config/controlAddConnection.h [new file with mode: 0755]
hicn-light/src/config/controlAddListener.c [new file with mode: 0755]
hicn-light/src/config/controlAddListener.h [new file with mode: 0755]
hicn-light/src/config/controlAddPunting.c [new file with mode: 0755]
hicn-light/src/config/controlAddPunting.h [new file with mode: 0755]
hicn-light/src/config/controlAddRoute.c [new file with mode: 0755]
hicn-light/src/config/controlAddRoute.h [new file with mode: 0755]
hicn-light/src/config/controlCache.c [new file with mode: 0755]
hicn-light/src/config/controlCache.h [new file with mode: 0755]
hicn-light/src/config/controlCacheClear.c [new file with mode: 0755]
hicn-light/src/config/controlCacheClear.h [new file with mode: 0755]
hicn-light/src/config/controlCacheServe.c [new file with mode: 0755]
hicn-light/src/config/controlCacheServe.h [new file with mode: 0755]
hicn-light/src/config/controlCacheStore.c [new file with mode: 0755]
hicn-light/src/config/controlCacheStore.h [new file with mode: 0755]
hicn-light/src/config/controlList.c [new file with mode: 0755]
hicn-light/src/config/controlList.h [new file with mode: 0755]
hicn-light/src/config/controlListConnections.c [new file with mode: 0755]
hicn-light/src/config/controlListConnections.h [new file with mode: 0755]
hicn-light/src/config/controlListInterfaces.c [new file with mode: 0755]
hicn-light/src/config/controlListInterfaces.h [new file with mode: 0755]
hicn-light/src/config/controlListListeners.c [new file with mode: 0755]
hicn-light/src/config/controlListListeners.h [new file with mode: 0755]
hicn-light/src/config/controlListRoutes.c [new file with mode: 0755]
hicn-light/src/config/controlListRoutes.h [new file with mode: 0755]
hicn-light/src/config/controlMapMe.c [new file with mode: 0755]
hicn-light/src/config/controlMapMe.h [new file with mode: 0755]
hicn-light/src/config/controlMapMeDiscovery.c [new file with mode: 0755]
hicn-light/src/config/controlMapMeDiscovery.h [new file with mode: 0755]
hicn-light/src/config/controlMapMeEnable.c [new file with mode: 0755]
hicn-light/src/config/controlMapMeEnable.h [new file with mode: 0755]
hicn-light/src/config/controlMapMeRetx.c [new file with mode: 0755]
hicn-light/src/config/controlMapMeRetx.h [new file with mode: 0755]
hicn-light/src/config/controlMapMeTimescale.c [new file with mode: 0755]
hicn-light/src/config/controlMapMeTimescale.h [new file with mode: 0755]
hicn-light/src/config/controlQuit.c [new file with mode: 0755]
hicn-light/src/config/controlQuit.h [new file with mode: 0755]
hicn-light/src/config/controlRemove.c [new file with mode: 0755]
hicn-light/src/config/controlRemove.h [new file with mode: 0755]
hicn-light/src/config/controlRemoveConnection.c [new file with mode: 0755]
hicn-light/src/config/controlRemoveConnection.h [new file with mode: 0755]
hicn-light/src/config/controlRemovePunting.c [new file with mode: 0755]
hicn-light/src/config/controlRemovePunting.h [new file with mode: 0755]
hicn-light/src/config/controlRemoveRoute.c [new file with mode: 0755]
hicn-light/src/config/controlRemoveRoute.h [new file with mode: 0755]
hicn-light/src/config/controlRoot.c [new file with mode: 0755]
hicn-light/src/config/controlRoot.h [new file with mode: 0755]
hicn-light/src/config/controlSet.c [new file with mode: 0755]
hicn-light/src/config/controlSet.h [new file with mode: 0755]
hicn-light/src/config/controlSetDebug.c [new file with mode: 0755]
hicn-light/src/config/controlSetDebug.h [new file with mode: 0755]
hicn-light/src/config/controlSetStrategy.c [new file with mode: 0755]
hicn-light/src/config/controlSetStrategy.h [new file with mode: 0755]
hicn-light/src/config/controlSetWldr.c [new file with mode: 0755]
hicn-light/src/config/controlSetWldr.h [new file with mode: 0755]
hicn-light/src/config/controlState.c [new file with mode: 0755]
hicn-light/src/config/controlState.h [new file with mode: 0755]
hicn-light/src/config/controlUnset.c [new file with mode: 0755]
hicn-light/src/config/controlUnset.h [new file with mode: 0755]
hicn-light/src/config/controlUnsetDebug.c [new file with mode: 0755]
hicn-light/src/config/controlUnsetDebug.h [new file with mode: 0755]
hicn-light/src/config/symbolicNameTable.c [new file with mode: 0755]
hicn-light/src/config/symbolicNameTable.h [new file with mode: 0755]
hicn-light/src/content_store/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/content_store/contentStoreEntry.c [new file with mode: 0755]
hicn-light/src/content_store/contentStoreEntry.h [new file with mode: 0755]
hicn-light/src/content_store/contentStoreInterface.c [new file with mode: 0755]
hicn-light/src/content_store/contentStoreInterface.h [new file with mode: 0755]
hicn-light/src/content_store/contentStoreLRU.c [new file with mode: 0755]
hicn-light/src/content_store/contentStoreLRU.h [new file with mode: 0755]
hicn-light/src/content_store/listLRU.c [new file with mode: 0755]
hicn-light/src/content_store/listLRU.h [new file with mode: 0755]
hicn-light/src/content_store/listTimeOrdered.c [new file with mode: 0755]
hicn-light/src/content_store/listTimeOrdered.h [new file with mode: 0755]
hicn-light/src/core/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/core/connection.c [new file with mode: 0755]
hicn-light/src/core/connection.h [new file with mode: 0755]
hicn-light/src/core/connectionList.c [new file with mode: 0755]
hicn-light/src/core/connectionList.h [new file with mode: 0755]
hicn-light/src/core/connectionManager.c [new file with mode: 0755]
hicn-light/src/core/connectionManager.h [new file with mode: 0755]
hicn-light/src/core/connectionTable.c [new file with mode: 0755]
hicn-light/src/core/connectionTable.h [new file with mode: 0755]
hicn-light/src/core/dispatcher.c [new file with mode: 0755]
hicn-light/src/core/dispatcher.h [new file with mode: 0755]
hicn-light/src/core/forwarder.c [new file with mode: 0755]
hicn-light/src/core/forwarder.h [new file with mode: 0755]
hicn-light/src/core/logger.c [new file with mode: 0755]
hicn-light/src/core/logger.h [new file with mode: 0755]
hicn-light/src/core/mapMe.c [new file with mode: 0755]
hicn-light/src/core/mapMe.h [new file with mode: 0755]
hicn-light/src/core/message.c [new file with mode: 0755]
hicn-light/src/core/message.h [new file with mode: 0755]
hicn-light/src/core/messageHandler.h [new file with mode: 0755]
hicn-light/src/core/messagePacketType.h [new file with mode: 0755]
hicn-light/src/core/name.c [new file with mode: 0755]
hicn-light/src/core/name.h [new file with mode: 0755]
hicn-light/src/core/nameBitvector.c [new file with mode: 0755]
hicn-light/src/core/nameBitvector.h [new file with mode: 0755]
hicn-light/src/core/numberSet.c [new file with mode: 0755]
hicn-light/src/core/numberSet.h [new file with mode: 0755]
hicn-light/src/core/streamBuffer.c [new file with mode: 0755]
hicn-light/src/core/streamBuffer.h [new file with mode: 0755]
hicn-light/src/core/system.h [new file with mode: 0755]
hicn-light/src/core/ticks.h [new file with mode: 0755]
hicn-light/src/core/wldr.c [new file with mode: 0755]
hicn-light/src/core/wldr.h [new file with mode: 0755]
hicn-light/src/io/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/io/addressPair.c [new file with mode: 0755]
hicn-light/src/io/addressPair.h [new file with mode: 0755]
hicn-light/src/io/hicnConnection.c [new file with mode: 0755]
hicn-light/src/io/hicnConnection.h [new file with mode: 0755]
hicn-light/src/io/hicnListener.c [new file with mode: 0755]
hicn-light/src/io/hicnListener.h [new file with mode: 0755]
hicn-light/src/io/hicnTunnel.c [new file with mode: 0755]
hicn-light/src/io/hicnTunnel.h [new file with mode: 0755]
hicn-light/src/io/ioOperations.c [new file with mode: 0755]
hicn-light/src/io/ioOperations.h [new file with mode: 0755]
hicn-light/src/io/listener.h [new file with mode: 0755]
hicn-light/src/io/listenerSet.c [new file with mode: 0755]
hicn-light/src/io/listenerSet.h [new file with mode: 0755]
hicn-light/src/io/streamConnection.c [new file with mode: 0755]
hicn-light/src/io/streamConnection.h [new file with mode: 0755]
hicn-light/src/io/tcpListener.c [new file with mode: 0755]
hicn-light/src/io/tcpListener.h [new file with mode: 0755]
hicn-light/src/io/tcpTunnel.c [new file with mode: 0755]
hicn-light/src/io/tcpTunnel.h [new file with mode: 0755]
hicn-light/src/io/udpConnection.c [new file with mode: 0755]
hicn-light/src/io/udpConnection.h [new file with mode: 0755]
hicn-light/src/io/udpListener.c [new file with mode: 0755]
hicn-light/src/io/udpListener.h [new file with mode: 0755]
hicn-light/src/io/udpTunnel.c [new file with mode: 0755]
hicn-light/src/io/udpTunnel.h [new file with mode: 0755]
hicn-light/src/messenger/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/messenger/messenger.c [new file with mode: 0755]
hicn-light/src/messenger/messenger.h [new file with mode: 0755]
hicn-light/src/messenger/messengerRecipient.c [new file with mode: 0755]
hicn-light/src/messenger/messengerRecipient.h [new file with mode: 0755]
hicn-light/src/messenger/missive.c [new file with mode: 0755]
hicn-light/src/messenger/missive.h [new file with mode: 0755]
hicn-light/src/messenger/missiveDeque.c [new file with mode: 0755]
hicn-light/src/messenger/missiveDeque.h [new file with mode: 0755]
hicn-light/src/messenger/missiveType.h [new file with mode: 0755]
hicn-light/src/platforms/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/platforms/README.txt [new file with mode: 0755]
hicn-light/src/platforms/android/system.c [new file with mode: 0755]
hicn-light/src/platforms/darwin/system.c [new file with mode: 0755]
hicn-light/src/platforms/linux/system.c [new file with mode: 0755]
hicn-light/src/processor/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/processor/fib.c [new file with mode: 0755]
hicn-light/src/processor/fib.h [new file with mode: 0755]
hicn-light/src/processor/fibEntry.c [new file with mode: 0755]
hicn-light/src/processor/fibEntry.h [new file with mode: 0755]
hicn-light/src/processor/fibEntryList.c [new file with mode: 0755]
hicn-light/src/processor/fibEntryList.h [new file with mode: 0755]
hicn-light/src/processor/hashTableFunction.c [new file with mode: 0755]
hicn-light/src/processor/hashTableFunction.h [new file with mode: 0755]
hicn-light/src/processor/matchingRulesTable.c [new file with mode: 0755]
hicn-light/src/processor/matchingRulesTable.h [new file with mode: 0755]
hicn-light/src/processor/messageProcessor.c [new file with mode: 0755]
hicn-light/src/processor/messageProcessor.h [new file with mode: 0755]
hicn-light/src/processor/pit.c [new file with mode: 0755]
hicn-light/src/processor/pit.h [new file with mode: 0755]
hicn-light/src/processor/pitEntry.c [new file with mode: 0755]
hicn-light/src/processor/pitEntry.h [new file with mode: 0755]
hicn-light/src/processor/pitStandard.c [new file with mode: 0755]
hicn-light/src/processor/pitStandard.h [new file with mode: 0755]
hicn-light/src/processor/pitVerdict.h [new file with mode: 0755]
hicn-light/src/socket/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/socket/api.c [new file with mode: 0755]
hicn-light/src/socket/api.h [new file with mode: 0755]
hicn-light/src/socket/error.c [new file with mode: 0755]
hicn-light/src/socket/error.h [new file with mode: 0755]
hicn-light/src/socket/ops.h [new file with mode: 0755]
hicn-light/src/socket/ops_linux.c [new file with mode: 0755]
hicn-light/src/strategies/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/strategies/loadBalancer.c [new file with mode: 0755]
hicn-light/src/strategies/loadBalancer.h [new file with mode: 0755]
hicn-light/src/strategies/loadBalancerWithPD.c [new file with mode: 0755]
hicn-light/src/strategies/loadBalancerWithPD.h [new file with mode: 0755]
hicn-light/src/strategies/nexthopState.c [new file with mode: 0755]
hicn-light/src/strategies/nexthopState.h [new file with mode: 0755]
hicn-light/src/strategies/nexthopStateWithPD.c [new file with mode: 0755]
hicn-light/src/strategies/nexthopStateWithPD.h [new file with mode: 0755]
hicn-light/src/strategies/rnd.c [new file with mode: 0755]
hicn-light/src/strategies/rnd.h [new file with mode: 0755]
hicn-light/src/strategies/rndSegment.c [new file with mode: 0755]
hicn-light/src/strategies/rndSegment.h [new file with mode: 0755]
hicn-light/src/strategies/strategyImpl.h [new file with mode: 0755]
hicn-light/src/utils/CMakeLists.txt [new file with mode: 0755]
hicn-light/src/utils/address.c [new file with mode: 0755]
hicn-light/src/utils/address.h [new file with mode: 0755]
hicn-light/src/utils/addressList.c [new file with mode: 0755]
hicn-light/src/utils/addressList.h [new file with mode: 0755]
hicn-light/src/utils/commands.h [new file with mode: 0755]
hicn-light/src/utils/interface.c [new file with mode: 0755]
hicn-light/src/utils/interface.h [new file with mode: 0755]
hicn-light/src/utils/interfaceSet.c [new file with mode: 0755]
hicn-light/src/utils/interfaceSet.h [new file with mode: 0755]
hicn-light/src/utils/punting.c [new file with mode: 0755]
hicn-light/src/utils/punting.h [new file with mode: 0755]
hicn-light/src/utils/utils.c [new file with mode: 0755]
hicn-light/src/utils/utils.h [new file with mode: 0755]
hicn-plugin/AUTHORS [new file with mode: 0755]
hicn-plugin/CMakeLists.txt [new file with mode: 0755]
hicn-plugin/README.md [new file with mode: 0755]
hicn-plugin/src/cache_policies/cs_lru.c [new file with mode: 0755]
hicn-plugin/src/cache_policies/cs_lru.h [new file with mode: 0755]
hicn-plugin/src/cache_policies/cs_policy.h [new file with mode: 0755]
hicn-plugin/src/cli.c [new file with mode: 0755]
hicn-plugin/src/data_fwd.h [new file with mode: 0755]
hicn-plugin/src/data_fwd_node.c [new file with mode: 0755]
hicn-plugin/src/data_pcslookup.h [new file with mode: 0755]
hicn-plugin/src/data_pcslookup_node.c [new file with mode: 0755]
hicn-plugin/src/data_push_node.c [new file with mode: 0755]
hicn-plugin/src/error.c [new file with mode: 0755]
hicn-plugin/src/error.h [new file with mode: 0755]
hicn-plugin/src/face_db.h [new file with mode: 0755]
hicn-plugin/src/faces/app/address_mgr.c [new file with mode: 0755]
hicn-plugin/src/faces/app/address_mgr.h [new file with mode: 0755]
hicn-plugin/src/faces/app/face_app_cli.c [new file with mode: 0755]
hicn-plugin/src/faces/app/face_cons.c [new file with mode: 0755]
hicn-plugin/src/faces/app/face_cons.h [new file with mode: 0755]
hicn-plugin/src/faces/app/face_prod.c [new file with mode: 0755]
hicn-plugin/src/faces/app/face_prod.h [new file with mode: 0755]
hicn-plugin/src/faces/app/face_prod_node.c [new file with mode: 0755]
hicn-plugin/src/faces/face.c [new file with mode: 0755]
hicn-plugin/src/faces/face.h [new file with mode: 0755]
hicn-plugin/src/faces/face_cli.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/dpo_ip.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/dpo_ip.h [new file with mode: 0755]
hicn-plugin/src/faces/ip/face_ip.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/face_ip.h [new file with mode: 0755]
hicn-plugin/src/faces/ip/face_ip_cli.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/face_ip_node.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/face_ip_node.h [new file with mode: 0755]
hicn-plugin/src/faces/ip/iface_ip_node.c [new file with mode: 0755]
hicn-plugin/src/faces/ip/iface_ip_node.h [new file with mode: 0755]
hicn-plugin/src/faces/udp/dpo_udp.c [new file with mode: 0755]
hicn-plugin/src/faces/udp/dpo_udp.h [new file with mode: 0755]
hicn-plugin/src/faces/udp/face_udp.c [new file with mode: 0755]
hicn-plugin/src/faces/udp/face_udp.h [new file with mode: 0755]
hicn-plugin/src/faces/udp/face_udp_cli.c [new file with mode: 0755]
hicn-plugin/src/faces/udp/face_udp_node.c [new file with mode: 0755]
hicn-plugin/src/faces/udp/face_udp_node.h [new file with mode: 0755]
hicn-plugin/src/faces/udp/iface_udp_node.c [new file with mode: 0755]
hicn-plugin/src/faces/udp/iface_udp_node.h [new file with mode: 0755]
hicn-plugin/src/hashtb.c [new file with mode: 0755]
hicn-plugin/src/hashtb.h [new file with mode: 0755]
hicn-plugin/src/hicn.api [new file with mode: 0755]
hicn-plugin/src/hicn.c [new file with mode: 0755]
hicn-plugin/src/hicn.h [new file with mode: 0755]
hicn-plugin/src/hicn_all_api_h.h [new file with mode: 0755]
hicn-plugin/src/hicn_api.c [new file with mode: 0755]
hicn-plugin/src/hicn_api.h [new file with mode: 0755]
hicn-plugin/src/hicn_api_test.c [new file with mode: 0755]
hicn-plugin/src/hicn_msg_enum.h [new file with mode: 0755]
hicn-plugin/src/infra.h [new file with mode: 0755]
hicn-plugin/src/interest_hitcs.h [new file with mode: 0755]
hicn-plugin/src/interest_hitcs_node.c [new file with mode: 0755]
hicn-plugin/src/interest_hitpit.h [new file with mode: 0755]
hicn-plugin/src/interest_hitpit_node.c [new file with mode: 0755]
hicn-plugin/src/interest_pcslookup.h [new file with mode: 0755]
hicn-plugin/src/interest_pcslookup_node.c [new file with mode: 0755]
hicn-plugin/src/mapme.h [new file with mode: 0755]
hicn-plugin/src/mapme_ack.h [new file with mode: 0755]
hicn-plugin/src/mapme_ack_node.c [new file with mode: 0755]
hicn-plugin/src/mapme_ctrl.h [new file with mode: 0755]
hicn-plugin/src/mapme_ctrl_node.c [new file with mode: 0755]
hicn-plugin/src/mapme_eventmgr.c [new file with mode: 0755]
hicn-plugin/src/mapme_eventmgr.h [new file with mode: 0755]
hicn-plugin/src/mgmt.c [new file with mode: 0755]
hicn-plugin/src/mgmt.h [new file with mode: 0755]
hicn-plugin/src/params.h [new file with mode: 0755]
hicn-plugin/src/parser.h [new file with mode: 0755]
hicn-plugin/src/pcs.c [new file with mode: 0755]
hicn-plugin/src/pcs.h [new file with mode: 0755]
hicn-plugin/src/pg.c [new file with mode: 0755]
hicn-plugin/src/pg.h [new file with mode: 0755]
hicn-plugin/src/punt.c [new file with mode: 0755]
hicn-plugin/src/punt.h [new file with mode: 0755]
hicn-plugin/src/route.c [new file with mode: 0755]
hicn-plugin/src/route.h [new file with mode: 0755]
hicn-plugin/src/state.h [new file with mode: 0755]
hicn-plugin/src/strategies/dpo_mw.c [new file with mode: 0755]
hicn-plugin/src/strategies/dpo_mw.h [new file with mode: 0755]
hicn-plugin/src/strategies/strategy_mw.c [new file with mode: 0755]
hicn-plugin/src/strategies/strategy_mw.h [new file with mode: 0755]
hicn-plugin/src/strategies/strategy_mw_cli.c [new file with mode: 0755]
hicn-plugin/src/strategy.c [new file with mode: 0755]
hicn-plugin/src/strategy.h [new file with mode: 0755]
hicn-plugin/src/strategy_dpo_ctx.h [new file with mode: 0755]
hicn-plugin/src/strategy_dpo_manager.c [new file with mode: 0755]
hicn-plugin/src/strategy_dpo_manager.h [new file with mode: 0755]
hicn-plugin/src/utils.h [new file with mode: 0755]
hicn-plugin/src/vface_db.h [new file with mode: 0755]
lib/CMakeLists.txt [new file with mode: 0755]
lib/README.md [new file with mode: 0755]
lib/doc/CMakeLists.txt [new file with mode: 0755]
lib/doc/Doxyfile.in [new file with mode: 0755]
lib/src/CMakeLists.txt [new file with mode: 0755]
lib/src/base.h [new file with mode: 0755]
lib/src/common.c [new file with mode: 0755]
lib/src/common.h [new file with mode: 0755]
lib/src/compat.c [new file with mode: 0755]
lib/src/compat.h [new file with mode: 0755]
lib/src/error.c [new file with mode: 0755]
lib/src/error.h [new file with mode: 0755]
lib/src/header.h [new file with mode: 0755]
lib/src/hicn.h [new file with mode: 0755]
lib/src/mapme.c [new file with mode: 0755]
lib/src/mapme.h [new file with mode: 0755]
lib/src/name.c [new file with mode: 0755]
lib/src/name.h [new file with mode: 0755]
lib/src/ops.c [new file with mode: 0755]
lib/src/ops.h [new file with mode: 0755]
lib/src/protocol.h [new file with mode: 0755]
lib/src/protocol/ah.c [new file with mode: 0755]
lib/src/protocol/ah.h [new file with mode: 0755]
lib/src/protocol/icmp.c [new file with mode: 0755]
lib/src/protocol/icmp.h [new file with mode: 0755]
lib/src/protocol/icmprd.h [new file with mode: 0755]
lib/src/protocol/ipv4.c [new file with mode: 0755]
lib/src/protocol/ipv4.h [new file with mode: 0755]
lib/src/protocol/ipv6.c [new file with mode: 0755]
lib/src/protocol/ipv6.h [new file with mode: 0755]
lib/src/protocol/tcp.c [new file with mode: 0755]
lib/src/protocol/tcp.h [new file with mode: 0755]
lib/src/protocol/udp.h [new file with mode: 0755]
libtransport/AUTHORS [new file with mode: 0755]
libtransport/CMakeLists.txt [new file with mode: 0755]
libtransport/README.md [new file with mode: 0755]
libtransport/cmake/Modules/Android.cmake [new file with mode: 0755]
libtransport/cmake/Modules/DefaultConfiguration.cmake [new file with mode: 0755]
libtransport/cmake/Modules/Ios.cmake [new file with mode: 0755]
libtransport/cmake/Modules/Packager.cmake [new file with mode: 0755]
libtransport/cmake/Modules/TestMacros.cmake [new file with mode: 0755]
libtransport/src/hicn/transport/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/config.h.in [new file with mode: 0755]
libtransport/src/hicn/transport/core/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/core/connector.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/connector.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/content_object.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/content_object.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/facade.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/forwarder_interface.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/hicn_binary_api.c [new file with mode: 0755]
libtransport/src/hicn/transport/core/hicn_binary_api.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/hicn_forwarder_interface.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/hicn_memif_api.c [new file with mode: 0755]
libtransport/src/hicn/transport/core/interest.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/interest.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/key_locator.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/key_locator.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/key_locator_type.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_fixed.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_fixed.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/manifest_inline.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/memif_binary_api.c [new file with mode: 0755]
libtransport/src/hicn/transport/core/memif_binary_api.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/memif_connector.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/memif_connector.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/name.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/name.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/packet.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/packet.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/payload_type.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/pending_interest.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/pending_interest.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/portal.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/prefix.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/prefix.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/raw_socket_connector.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/raw_socket_connector.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/raw_socket_interface.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/raw_socket_interface.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/socket_connector.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/socket_connector.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/test/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/core/test/test_core_manifest.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/vpp_binary_api.c [new file with mode: 0755]
libtransport/src/hicn/transport/core/vpp_binary_api.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/vpp_binary_api_internal.h [new file with mode: 0755]
libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc [new file with mode: 0755]
libtransport/src/hicn/transport/core/vpp_forwarder_interface.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/errors/errors.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/malformed_name_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/malformed_packet_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/not_implemented_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/null_pointer_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/runtime_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/errors/tokenizer_exception.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/http/callbacks.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/client_connection.cc [new file with mode: 0755]
libtransport/src/hicn/transport/http/client_connection.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/default_values.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/facade.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/message.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/request.cc [new file with mode: 0755]
libtransport/src/hicn/transport/http/request.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/response.cc [new file with mode: 0755]
libtransport/src/hicn/transport/http/response.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/server_acceptor.cc [new file with mode: 0755]
libtransport/src/hicn/transport/http/server_acceptor.h [new file with mode: 0755]
libtransport/src/hicn/transport/http/server_publisher.cc [new file with mode: 0755]
libtransport/src/hicn/transport/http/server_publisher.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/async_transport.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/full_duplex_socket.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/publication_options.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_consumer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_consumer.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_options_default_values.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_options_keys.h [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_producer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/interfaces/socket_producer.h [new file with mode: 0755]
libtransport/src/hicn/transport/portability/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/portability/c_portability.h [new file with mode: 0755]
libtransport/src/hicn/transport/portability/portability.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/cbr.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/cbr.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/consumer.conf [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/download_observer.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/protocol.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/protocol.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/raaqm.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/raaqm.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/raaqm_data_path.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/raaqm_data_path.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rate_estimation.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rate_estimation.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rtc.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rtc.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rtc_data_path.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/rtc_data_path.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/test/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/vegas.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/vegas.h [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc [new file with mode: 0755]
libtransport/src/hicn/transport/protocols/vegas_rto_estimator.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/CMakeLists.txt [new file with mode: 0755]
libtransport/src/hicn/transport/utils/array.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/branch_prediction.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/content_store.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/content_store.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/conversions.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/crypto_hash.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/crypto_hash_type.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/crypto_hasher.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/crypto_suite.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/daemonizator.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/daemonizator.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/deadline_timer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/endianess.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/epoll_event_reactor.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/epoll_event_reactor.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/event_reactor.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/event_thread.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/fd_deadline_timer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/hash.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/identity.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/identity.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/key_id.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/linux.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/literals.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/log.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/log.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/membuf.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/membuf.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/min_filter.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/object_pool.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/ring_buffer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/sharable_vector.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/signer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/signer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/socket.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/spinlock.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/stream_buffer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/string_tokenizer.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/string_tokenizer.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/test.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/uri.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/uri.h [new file with mode: 0755]
libtransport/src/hicn/transport/utils/verifier.cc [new file with mode: 0755]
libtransport/src/hicn/transport/utils/verifier.h [new file with mode: 0755]
utils/CMakeLists.txt [new file with mode: 0755]
utils/src/hiperf.cc [new file with mode: 0755]
utils/src/ping_client.cc [new file with mode: 0755]
utils/src/ping_server.cc [new file with mode: 0755]

diff --git a/.gitreview b/.gitreview
new file mode 100644 (file)
index 0000000..2579a4a
--- /dev/null
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.fd.io
+port=29418
+project=hicn
diff --git a/AUTHORS b/AUTHORS
new file mode 100755 (executable)
index 0000000..ab60dbd
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,6 @@
+Jordan Augé <jordan.auge@cisco.com>
+Alberto Compagno <acompagn@cisco.com>
+Giovanni Conte <gconte@cisco.com>
+Luca Muscariello <lumuscar@cisco.com>
+Michele Papalini <mpapal@cisco.com>
+Mauro Sardara <msardara@cisco.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..c47f8e6
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+project(hicn-fdio)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+set(HICN_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/lib)
+
+## Target names
+set(LIBHICN hicn)
+set(LIBHICN_SHARED hicn.shared)
+set(LIBHICN_LIGHT hicn-light)
+set(HICN_LIGHT_CONTROL hicnLightControl)
+set(HICN_LIGHT_DAEMON hicnLightDaemon)
+set(LIBTRANSPORT transport)
+set(LIBTRANSPORT_SHARED transport.shared)
+
+## HEADER FILES
+set(LIBHICN_HEADER_FILES)
+set(LIBHICN_LIGHT_HEADER_FILES)
+set(LIBTRANSPORT_HEADER_FILES)
+
+set(SUBDIRS lib hicn-light libtransport utils)
+
+if (BUILD_VPP_PLUGIN AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" )
+list(APPEND SUBDIRS
+  hicn-plugin
+)
+list(APPEND HICN_BINARY_API_INCLUDE_DIRS
+  ${PROJECT_BINARY_DIR}/hicn-plugin
+  ${PROJECT_BINARY_DIR}/hicn-plugin/vpp_plugins)
+endif()
+
+foreach(dir ${SUBDIRS})
+  add_subdirectory(${dir})
+endforeach()
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100755 (executable)
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
new file mode 100755 (executable)
index 0000000..c43dbb4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,33 @@
+Hybrid Information-Centric Networking (hICN)
+========================
+
+## Introduction
+hicn is an open source implementation of Cisco's hICN. It includes a network
+stack, that implements ICN forwarding path in IPv6, and a transport stack
+that implements two main transport protocols and a socket API.
+The transport protocols provide one reliable transport service implementaton
+and a real-time transport service for audio/video media.
+
+## Directory layout
+
+| Directory name         | Description                                    |
+| ---------------------- | ---------------------------------------------- |
+|      lib               | Core support library                           |
+|      hicn-plugin       | VPP plugin                                     |
+|      hicn-light        | Lightweight packet forwarder                   |
+|      libtransport      | Support library with transport layer and API   |
+|      utils             | Tools for testing                              |
+|      apps              | Application examples using hicn stack          |
+
+
+## Supported platforms
+
+- Ubuntu 16.04 LTS (x86_64)
+- Ubuntu 18.04 LTS (x86_64)
+- Debian Stable/Testing
+- Red Hat Enterprise Linux 7
+- CentOS 7
+- Android 8
+- iOS 12
+- macOS 10.12
+- Windows 10
diff --git a/apps/README.md b/apps/README.md
new file mode 100755 (executable)
index 0000000..3d763f0
--- /dev/null
@@ -0,0 +1,2 @@
+Application examples using hicn stack
+==================
diff --git a/cmake/Modules/BuildMacros.cmake b/cmake/Modules/BuildMacros.cmake
new file mode 100755 (executable)
index 0000000..14a82fa
--- /dev/null
@@ -0,0 +1,146 @@
+# Copyright (c) 2017-2019 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.
+
+##############################
+# Utils for building libraries and executables
+#
+
+macro(build_executable exec)
+  cmake_parse_arguments(ARG
+    "NO_INSTALL"
+    "COMPONENT"
+    "SOURCES;LINK_LIBRARIES;DEPENDS;DEFINITIONS"
+    ${ARGN}
+  )
+
+  add_executable(${exec} ${ARG_SOURCES})
+  if(ARG_LINK_LIBRARIES)
+    target_link_libraries(${exec} ${ARG_LINK_LIBRARIES})
+  endif()
+
+  if(ARG_DEPENDS)
+    add_dependencies(${exec} ${ARG_DEPENDS})
+  endif()
+
+  if(ARG_DEFINITIONS)
+    target_compile_definitions(${exec} PRIVATE ${ARG_DEFINITIONS})
+  endif()
+
+  if(NOT ARG_NO_INSTALL)
+    install(TARGETS ${exec} DESTINATION bin COMPONENT ${ARG_COMPONENT})
+  endif()
+endmacro()
+
+macro(build_library lib)
+  cmake_parse_arguments(ARG
+    "SHARED;STATIC"
+    "COMPONENT"
+    "SOURCES;LINK_LIBRARIES;INSTALL_HEADERS;DEPENDS;INCLUDE_DIRS;DEFINITIONS;INSTALL_ROOT_DIR"
+    ${ARGN}
+  )
+
+  if (ARG_SHARED)
+    list(APPEND TARGET_LIBS
+      ${lib}.shared
+    )
+    add_library(${lib}.shared SHARED ${ARG_SOURCES})
+  endif()
+
+  if(ARG_STATIC)
+    list(APPEND TARGET_LIBS
+      ${lib}
+    )
+    add_library(${lib} STATIC ${ARG_SOURCES})
+  endif()
+
+  foreach(library ${TARGET_LIBS})
+    target_compile_options(${library} PRIVATE -Wall)
+
+    if(HICN_VERSION)
+      set_target_properties(${library}
+        PROPERTIES
+        SOVERSION ${HICN_VERSION}
+      )
+    endif()
+
+    set_target_properties(${library}
+      PROPERTIES
+      OUTPUT_NAME ${lib}
+    )
+
+    # library deps
+    if(ARG_LINK_LIBRARIES)
+      target_link_libraries(${library} ${ARG_LINK_LIBRARIES})
+    endif()
+
+    if(ARG_DEFINITIONS)
+      target_compile_definitions(${library} PRIVATE ${ARG_DEFINITIONS})
+    endif()
+
+    if(ARG_INCLUDE_DIRS)
+      target_include_directories(${library} BEFORE PUBLIC
+        ${ARG_INCLUDE_DIRS}
+        ${PROJECT_BINARY_DIR}
+      )
+    endif()
+
+    # install .so
+    if(NOT ARG_COMPONENT)
+      set(ARG_COMPONENT hicn)
+    endif()
+    install(
+      TARGETS ${library}
+      DESTINATION lib
+      COMPONENT ${ARG_COMPONENT}
+    )
+
+    if(ARG_DEPENDS)
+      add_dependencies(${library} ${ARG_DEPENDS})
+    endif()
+  endforeach()
+
+  # install headers
+  if(ARG_INSTALL_HEADERS)
+
+    if (NOT ARG_INSTALL_ROOT_DIR)
+      set(ARG_INSTALL_ROOT_DIR "hicn")
+    endif()
+
+    foreach(file ${ARG_INSTALL_HEADERS})
+      get_filename_component(_dir ${file} DIRECTORY)
+      get_filename_component(dir ${_dir} NAME)
+      if (${dir} STREQUAL src)
+        set(dir "")
+      endif()
+      install(
+        FILES ${file}
+        DESTINATION include/${ARG_INSTALL_ROOT_DIR}/${dir}
+        COMPONENT ${ARG_COMPONENT}-dev
+      )
+    endforeach()
+  endif()
+endmacro()
+
+add_custom_target(${PROJECT_NAME}_cleanup_profiling_data
+  "find" "." "-name" "*.gcda" "-delete"
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+  COMMENT "Cleanup previous profiling data."
+)
+
+macro(AddTest testFile)
+  add_executable(${ARGV0} ${ARGV0}.cc)
+  target_link_libraries(${ARGV0} ${TARGET_TRANSPORT_STATIC} ${GTEST_LIBRARIES})
+  add_test(${ARGV0} ${ARGV0})
+  set_target_properties(${ARGV0} PROPERTIES FOLDER Test)
+  add_dependencies(${ARGV0} ${PROJECT_NAME}_cleanup_profiling_data)
+endmacro(AddTest)
\ No newline at end of file
diff --git a/cmake/Modules/FindAsio.cmake b/cmake/Modules/FindAsio.cmake
new file mode 100755 (executable)
index 0000000..73888e5
--- /dev/null
@@ -0,0 +1,41 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the hcin libraries and includes
+# This module sets:
+#  ASIO_FOUND: True if asio was found
+#  ASIO_INCLUDE_DIR:  The asio include dir
+#
+
+set(ASIO_SEARCH_PATH_LIST
+  ${ASIO_HOME}
+  $ENV{ASIO_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(ASIO_INCLUDE_DIR asio.hpp
+  HINTS ${ASIO_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the asio includes"
+)
+
+set(ASIO_INCLUDE_DIRS ${ASIO_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Asio
+  REQUIRED_VARS ASIO_INCLUDE_DIRS
+)
\ No newline at end of file
diff --git a/cmake/Modules/FindGFlags.cmake b/cmake/Modules/FindGFlags.cmake
new file mode 100755 (executable)
index 0000000..804bfeb
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017-2019 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.
+
+#
+# Find libgflags
+#
+#  LIBGFLAGS_INCLUDE_DIR - where to find gflags/gflags.h, etc.
+#  LIBGFLAGS_LIBRARY     - List of libraries when using libgflags.
+#  LIBGFLAGS_FOUND       - True if libgflags found.
+
+
+IF (LIBGFLAGS_INCLUDE_DIR)
+    # Already in cache, be silent
+    SET(LIBGFLAGS_FIND_QUIETLY TRUE)
+ENDIF ()
+
+FIND_PATH(LIBGFLAGS_INCLUDE_DIR gflags/gflags.h)
+
+FIND_LIBRARY(LIBGFLAGS_LIBRARY NAMES gflags gflags_static)
+
+# handle the QUIETLY and REQUIRED arguments and set LIBGFLAGS_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBGFLAGS DEFAULT_MSG LIBGFLAGS_LIBRARY LIBGFLAGS_INCLUDE_DIR)
+
+MARK_AS_ADVANCED(LIBGFLAGS_LIBRARY LIBGFLAGS_INCLUDE_DIR)
\ No newline at end of file
diff --git a/cmake/Modules/FindGlog.cmake b/cmake/Modules/FindGlog.cmake
new file mode 100755 (executable)
index 0000000..10023a1
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017-2019 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.
+
+#
+# Find libglog
+#
+#  LIBGLOG_INCLUDE_DIR - where to find glog/logging.h, etc.
+#  LIBGLOG_LIBRARY     - List of libraries when using libglog.
+#  LIBGLOG_FOUND       - True if libglog found.
+
+
+IF (LIBGLOG_INCLUDE_DIR)
+    # Already in cache, be silent
+    SET(LIBGLOG_FIND_QUIETLY TRUE)
+ENDIF ()
+
+FIND_PATH(LIBGLOG_INCLUDE_DIR glog/logging.h)
+
+FIND_LIBRARY(LIBGLOG_LIBRARY glog)
+
+# handle the QUIETLY and REQUIRED arguments and set LIBGLOG_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBGLOG DEFAULT_MSG LIBGLOG_LIBRARY LIBGLOG_INCLUDE_DIR)
+
+MARK_AS_ADVANCED(LIBGLOG_LIBRARY LIBGLOG_INCLUDE_DIR)
\ No newline at end of file
diff --git a/cmake/Modules/FindHicnBinaryApi.cmake b/cmake/Modules/FindHicnBinaryApi.cmake
new file mode 100755 (executable)
index 0000000..86a96ea
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2017-2019 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.
+
+set(HICN_BINARY_API_SEARCH_PATH_LIST
+  ${HICN_BINARY_API_HOME}
+  $ENV{HICN_BINARY_API_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(HICN_BINARY_API_INCLUDE_DIR vpp_plugins/hicn/hicn_api.h
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the VPP includes"
+)
+
+set(HICN_BINARY_API_INCLUDE_DIRS ${VPP_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(HicnBinaryApi DEFAULT_MSG VPP_LIBRARIES VPP_INCLUDE_DIRS)
\ No newline at end of file
diff --git a/cmake/Modules/FindLibEvent.cmake b/cmake/Modules/FindLibEvent.cmake
new file mode 100755 (executable)
index 0000000..5e41137
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the LibEvent libraries and includes
+# This module sets:
+#  LIBEVENT_FOUND: True if LibEvent was found
+#  LIBEVENT_LIBRARY:  The LibEvent library
+#  LIBEVENT_LIBRARIES:  The LibEvent library and dependencies
+#  LIBEVENT_INCLUDE_DIR:  The LibEvent include dir
+#
+# This module will look for the libraries in various locations
+# See the LIBEVENT_SEARCH_PATH_LIST for a full list.
+#
+# The caller can hint at locations using the following variables:
+#
+# LIBEVENT_HOME (passed as -D to cmake)
+# LIBEVENT_HOME (in environment)
+#
+
+set(LIBEVENT_SEARCH_PATH_LIST
+  ${LIBEVENT_HOME}
+  $ENV{DEPENDENCIES}
+  $ENV{LIBEVENT_HOME}
+  /usr/local
+  /opt
+  /usr
+  )
+
+find_path(LIBEVENT_INCLUDE_DIR event2/event.h
+  HINTS ${LIBEVENT_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the LibEvent includes" )
+
+find_library(LIBEVENT_LIBRARY NAMES event
+  HINTS ${LIBEVENT_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the LibEvent libraries" )
+
+set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARY})
+set(LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LibEvent  DEFAULT_MSG LIBEVENT_LIBRARY LIBEVENT_INCLUDE_DIR)
diff --git a/cmake/Modules/FindLibhicn.cmake b/cmake/Modules/FindLibhicn.cmake
new file mode 100755 (executable)
index 0000000..7cfaaa5
--- /dev/null
@@ -0,0 +1,49 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the hcin libraries and includes
+# This module sets:
+#  HICN_FOUND: True if hicn was found
+#  HICN_LIBRARY:  The hicn library
+#  HICN_LIBRARIES:  The hicn library and dependencies
+#  HCIN_INCLUDE_DIR:  The hicn include dir
+#
+
+set(HICN_SEARCH_PATH_LIST
+  ${HICN_HOME}
+  $ENV{HICN_HOME}
+  $ENV{FOUNDATION_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(HICN_INCLUDE_DIR hicn/hicn.h
+  HINTS ${HICN_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the hicn includes"
+)
+
+find_library(HICN_LIBRARY NAMES hicn
+  HINTS ${HICN_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the hicn libraries"
+)
+
+set(HICN_LIBRARIES ${HICN_LIBRARY})
+set(HICN_INCLUDE_DIRS ${HICN_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(hicn  DEFAULT_MSG HICN_LIBRARY HICN_INCLUDE_DIR)
diff --git a/cmake/Modules/FindLibmemif.cmake b/cmake/Modules/FindLibmemif.cmake
new file mode 100755 (executable)
index 0000000..48460ee
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the hcin libraries and includes
+# This module sets:
+#  LIBMEMIF_FOUND: True if core was found
+#  LIBMEMIF_LIBRARY:  The core library
+#  LIBMEMIF_INCLUDE_DIR:  The core include dir
+#
+
+set(LIBMEMIF_SEARCH_PATH_LIST
+  ${LIBMEMIF_HOME}
+  $ENV{LIBMEMIF_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(LIBMEMIF_INCLUDE_DIR memif/libmemif.h
+  HINTS ${LIBMEMIF_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the libmemif includes"
+)
+
+find_library(LIBMEMIF_LIBRARY NAMES memif
+  HINTS ${LIBMEMIF_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the libmemif libraries"
+)
+
+set(LIBMEMIF_LIBRARIES ${LIBMEMIF_LIBRARY})
+set(LIBMEMIF_INCLUDE_DIRS ${LIBMEMIF_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libmemif DEFAULT_MSG LIBMEMIF_LIBRARY LIBMEMIF_INCLUDE_DIR)
diff --git a/cmake/Modules/FindLibparc.cmake b/cmake/Modules/FindLibparc.cmake
new file mode 100755 (executable)
index 0000000..c5c99af
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the Libparc libraries and includes
+# This module sets:
+#  LIBPARC_FOUND: True if Libparc was found
+#  LIBPARC_LIBRARY:  The Libparc library
+#  LIBPARC_LIBRARIES:  The Libparc library and dependencies
+#  LIBPARC_INCLUDE_DIR:  The Libparc include dir
+#
+
+set(LIBPARC_SEARCH_PATH_LIST
+  ${LIBPARC_HOME}
+  $ENV{LIBPARC_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(LIBPARC_INCLUDE_DIR parc/libparc_About.h
+  HINTS ${LIBPARC_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the Libparc includes"
+)
+
+find_library(LIBPARC_LIBRARY NAMES parc
+  HINTS ${LIBPARC_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the Libparc libraries"
+)
+
+set(LIBPARC_LIBRARIES ${LIBPARC_LIBRARY})
+set(LIBPARC_INCLUDE_DIRS ${LIBPARC_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libparc DEFAULT_MSG LIBPARC_LIBRARY LIBPARC_INCLUDE_DIR)
+
+mark_as_advanced(LIBPARC_LIBRARY LIBPARC_INCLUDE_DIR)
diff --git a/cmake/Modules/FindLibtransport.cmake b/cmake/Modules/FindLibtransport.cmake
new file mode 100755 (executable)
index 0000000..5910a64
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the LibTRANSPORT libraries and includes
+# This module sets:
+#  LIBTRANSPORT_FOUND: True if Libconsumer-producer was found
+#  LIBTRANSPORTR_LIBRARY:  The Libconsumer-producer library
+#  LIBTRANSPORT_LIBRARIES:  The Libconsumer-producer library and dependencies
+#  LIBTRANSPORT_INCLUDE_DIR:  The Libconsumer-producer include dir
+#
+
+set(LIBTRANSPORT_SEARCH_PATH_LIST
+  ${LIBTRANSPORT_HOME}
+  $ENV{LIBTRANSPORTHOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(LIBTRANSPORT_INCLUDE_DIR hicn/transport/config.h
+  HINTS ${LIBTRANSPORT_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the libtransport includes"
+)
+
+find_library(LIBTRANSPORT_LIBRARY NAMES transport
+  HINTS ${LIBTRANSPORT_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the libtransport libraries"
+)
+
+set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT_LIBRARY})
+set(LIBTRANSPORT_INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libtransport DEFAULT_MSG LIBTRANSPORT_LIBRARIES LIBTRANSPORT_INCLUDE_DIRS)
\ No newline at end of file
diff --git a/cmake/Modules/FindLongBow.cmake b/cmake/Modules/FindLongBow.cmake
new file mode 100755 (executable)
index 0000000..4a05d7f
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (c) 2017-2019 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.
+
+########################################
+#
+# Find the LongBow libraries and includes
+# This module sets:
+#  LONGBOW_FOUND: True if LongBow was found
+#  LONGBOW_LIBRARY:  The LongBow library
+#  LONGBOW_LIBRARIES:  The LongBow library and dependencies
+#  LONGBOW_INCLUDE_DIR:  The LongBow include dir
+#
+
+set(LONGBOW_SEARCH_PATH_LIST
+  ${LONGBOW_HOME}
+  $ENV{LONGBOW_HOME}
+  $ENV{PARC_HOME}
+  $ENV{FOUNDATION_HOME}
+  /usr/local/parc
+  /usr/local/ccn
+  /usr/local
+  /opt
+  /usr
+  )
+
+find_path(LONGBOW_INCLUDE_DIR LongBow/longBow_About.h
+  HINTS ${LONGBOW_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the LongBow includes" )
+
+find_library(LONGBOW_LIBRARY NAMES longbow
+  HINTS ${LONGBOW_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the LongBow libraries" )
+
+find_library(LONGBOW_REPORT_LIBRARY NAMES longbow-textplain longbow-ansiterm
+  HINTS ${LONGBOW_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib
+  DOC "Find the LongBow report libraries" )
+
+set(LONGBOW_LIBRARIES ${LONGBOW_LIBRARY} ${LONGBOW_REPORT_LIBRARY})
+set(LONGBOW_INCLUDE_DIRS ${LONGBOW_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LongBow  DEFAULT_MSG LONGBOW_LIBRARY LONGBOW_INCLUDE_DIR)
diff --git a/cmake/Modules/FindUncrustify.cmake b/cmake/Modules/FindUncrustify.cmake
new file mode 100755 (executable)
index 0000000..f8f6b00
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2017-2019 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.
+
+# Find uncrustify program
+#
+find_program( UNCRUSTIFY_BIN uncrustify
+                PATHS
+                               $ENV{UNCRUSTIFY_HOME}
+                               )
+
+message( "-- UNCRUSTIFY found in ${UNCRUSTIFY_BIN}" )
diff --git a/cmake/Modules/FindVpp.cmake b/cmake/Modules/FindVpp.cmake
new file mode 100755 (executable)
index 0000000..ae11c80
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright (c) 2017-2019 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.
+
+set(VPP_SEARCH_PATH_LIST
+  ${VPP_HOME}
+  $ENV{VPP_HOME}
+  /usr/local
+  /opt
+  /usr
+)
+
+find_path(VPP_INCLUDE_DIR vnet/vnet.h
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES include
+  DOC "Find the VPP includes"
+)
+
+find_library(VPP_LIBRARY_MEMORYCLIENT
+  NAMES vlibmemoryclient
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib lib64
+  DOC "Find the Vpp Memoryclient library"
+)
+
+find_library(VPP_LIBRARY_SVM
+  NAMES svm
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib lib64
+  DOC "Find the Vpp svm library"
+)
+
+find_library(VPP_LIBRARY_INFRA
+  NAMES vppinfra
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib lib64
+  DOC "Find the Vpp infra library"
+)
+
+find_library(VPP_LIBRARY_VATPLUGIN
+  NAMES vatplugin
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib lib64
+  DOC "Find the Vpp vatplugin library"
+)
+
+find_library(VPP_LIBRARY_VLIB
+  NAMES vlib
+  HINTS ${VPP_SEARCH_PATH_LIST}
+  PATH_SUFFIXES lib lib64
+  DOC "Find the Vpp vlib library"
+)
+
+set(VPP_LIBRARIES ${VPP_LIBRARY_MEMORYCLIENT} ${VPP_LIBRARY_SVM} ${VPP_LIBRARY_INFRA} ${VPP_LIBRARY_VATPLUGIN} ${VPP_LIBRARY_VLIB})
+set(VPP_INCLUDE_DIRS ${VPP_INCLUDE_DIR} ${VPP_INCLUDE_DIR}/vpp_plugins)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Vpp DEFAULT_MSG VPP_LIBRARIES VPP_INCLUDE_DIRS)
\ No newline at end of file
diff --git a/cmake/Modules/IosMacros.cmake b/cmake/Modules/IosMacros.cmake
new file mode 100755 (executable)
index 0000000..b1e5cc4
--- /dev/null
@@ -0,0 +1,24 @@
+# Copyright (c) 2017-2019 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.
+
+if(COMPILE_FOR_IOS)
+  include_directories(iOS)
+endif()
+
+macro(find_package_wrapper)
+  if(COMPILE_FOR_IOS)
+    find_host_package(${ARGN})
+  else()
+    find_package(${ARGN})
+  endif()
+endmacro()
\ No newline at end of file
diff --git a/cmake/Modules/Packager.cmake b/cmake/Modules/Packager.cmake
new file mode 100755 (executable)
index 0000000..58530fa
--- /dev/null
@@ -0,0 +1,105 @@
+# Copyright (c) 2017-2019 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.
+
+#############
+# RPM/DEB/TGZ Packaging utils
+#
+
+set(CONTACT "hicn-dev@lists.fd.io" CACHE STRING "Contact")
+set(PACKAGE_MAINTAINER "ICN Team" CACHE STRING "Maintainer")
+set(PACKAGE_VENDOR "fd.io" CACHE STRING "Vendor")
+
+macro(add_package name)
+  cmake_parse_arguments(ARG
+    ""
+    "NAME;DESCRIPION;DEPENDENCIES"
+    ""
+    ${ARGN}
+  )
+
+  if (0)
+    # parse /etc/os-release
+    file(READ "/etc/os-release" os_version)
+    string(REPLACE "\n" ";" os_version ${os_version})
+    foreach(_ver ${os_version})
+      string(REPLACE "=" ";" _ver ${_ver})
+      list(GET _ver 0 _name)
+      list(GET _ver 1 _value)
+      set(OS_${_name} ${_value})
+    endforeach()
+
+    # extract version from git
+    execute_process(
+      COMMAND git describe --long --match v*
+      OUTPUT_VARIABLE VER
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+
+    if (NOT VER)
+      set(VER 1.0)
+    endif()
+
+    string(REGEX REPLACE "v(.*)-([0-9]+)-(g[0-9a-f]+)" "\\1;\\2;\\3" VER ${VER})
+    list(GET VER 0 tag)
+    string(REPLACE "-" "~" tag ${tag})
+    list(GET VER 1 commit_num)
+    list(GET VER 2 commit_name)
+
+    #define DEB and RPM version numbers
+    if(${commit_num} EQUAL 0)
+      set(deb_ver "${tag}")
+      set(rpm_ver "${tag}")
+    else()
+      set(deb_ver "${tag}~${commit_num}~${commit_name}")
+      set(rpm_ver "${tag}~${commit_num}_${commit_name}")
+    endif()
+
+    get_cmake_property(components COMPONENTS)
+
+    if(OS_ID_LIKE MATCHES "debian")
+      set(CPACK_GENERATOR "DEB")
+      set(type "DEBIAN")
+      set(CPACK_PACKAGE_VERSION "${deb_ver}")
+      set(CPACK_DEBIAN_PACKAGE_MAINTAINER "VPP Team")
+      set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
+      foreach(lc ${components})
+        string(TOUPPER ${lc} uc)
+        set(CPACK_DEBIAN_${uc}_PACKAGE_NAME "${lc}")
+      endforeach()
+    elseif(OS_ID_LIKE MATCHES "rhel")
+      set(CPACK_GENERATOR "RPM")
+      set(type "RPM")
+      set(CPACK_PACKAGE_VERSION "${rpm_ver}")
+      set(CPACK_RPM_FILE_NAME RPM-DEFAULT)
+      foreach(lc ${components})
+        string(TOUPPER ${lc} uc)
+        if(${lc} MATCHES ".*-dev")
+          set(CPACK_RPM_${uc}_DEBUGINFO_PACKAGE ON)
+          set(lc ${lc}el)
+        endif()
+        set(CPACK_RPM_${uc}_PACKAGE_NAME "${lc}")
+      endforeach()
+    endif()
+
+    if(CPACK_GENERATOR)
+      set(CPACK_PACKAGE_NAME ${ARG_NAME})
+      set(CPACK_STRIP_FILES OFF)
+      set(CPACK_PACKAGE_VENDOR "${ARG_VENDOR}")
+      set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+      set(CPACK_${CPACK_GENERATOR}_COMPONENT_INSTALL ON)
+      set(CPACK_${type}_PACKAGE_DESCRIPTION "${ARG_DESCRIPTION}")
+      set(CPACK_${type}_PACKAGE_RELEASE 1)
+      include(CPack)
+    endif()
+  endif()
+endmacro()
\ No newline at end of file
diff --git a/cmake/Modules/detectCacheSize.cmake b/cmake/Modules/detectCacheSize.cmake
new file mode 100755 (executable)
index 0000000..a8209bb
--- /dev/null
@@ -0,0 +1,21 @@
+# Detect the cache size
+#
+# XXX: TODO: This is a bug when cross compiling. We are detecting the local
+# Cache Line size and not the target cache line size.  We should provide some
+# way to define this
+
+set(LEVEL1_DCACHE_LINESIZE 32)
+
+if( APPLE )
+  execute_process(COMMAND sysctl -n hw.cachelinesize
+       OUTPUT_VARIABLE LEVEL1_DCACHE_LINESIZE
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif( APPLE )
+
+if( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
+  execute_process(COMMAND getconf LEVEL1_DCACHE_LINESIZE
+       OUTPUT_VARIABLE LEVEL1_DCACHE_LINESIZE
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif()
+
+message(STATUS "Cache line size: ${LEVEL1_DCACHE_LINESIZE}")
diff --git a/hicn-light/CMakeLists.txt b/hicn-light/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..289e07e
--- /dev/null
@@ -0,0 +1,74 @@
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+project(hicn-light)
+
+if (NOT CMAKE_BUILD_TYPE)
+    message(STATUS "No build type selected, default to Release")
+    set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+
+include( CTest )
+include( detectCacheSize )
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+if(ANDROID_API)
+  message("############ Detected cross compile for $ENV{CMAKE_SYSTEM_NAME}")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}")
+  endif()
+
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DLIBRTA_DISABLE_VALIDATION -DPARCLibrary_DISABLE_VALIDATION")
+
+include(IosMacros)
+
+find_package_wrapper(Libparc REQUIRED)
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+  find_package_wrapper(Libhicn REQUIRED)
+  set(LIBHICN_LIGHT hicn-light)
+  set(HICN_LIGHT_CONTROL hicnLightControl)
+  set(HICN_LIGHT_DAEMON hicnLightDaemon)
+else()
+  set(HICN_LIBRARIES ${LIBHICN_SHARED})
+  set(DEPENDENCIES
+    ${LIBHICN}
+    ${LIBHICN_SHARED}
+  )
+endif()
+
+find_package(Threads REQUIRED)
+
+set(HICN_LIGHT_LINK_LIBRARIES
+  hicn-light
+  ${HICN_LIBRARIES}
+  ${LIBPARC_LIBRARIES}
+  ${CMAKE_THREAD_LIBS_INIT}
+)
+
+# Include dirs -- Order does matter!
+list(APPEND HICN_LIGHT_INCLUDE_DIRS
+  ${HICN_INCLUDE_DIRS}
+  ${LIBPARC_INCLUDE_DIRS}
+)
+
+if (UNIX)
+  list(APPEND HICN_LIGHT_LINK_LIBRARIES
+    m
+  )
+endif()
+
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
+  set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS} -undefined dynamic_lookup")
+       message(STATUS "Set \"-undefined dynamic_lookup\" for shared libraries")
+endif()
+
+add_subdirectory(src)
\ No newline at end of file
diff --git a/hicn-light/README.md b/hicn-light/README.md
new file mode 100755 (executable)
index 0000000..ba7ed77
--- /dev/null
@@ -0,0 +1,302 @@
+hicn-light
+=======
+
+## Introduction ##
+
+hicn-light is a socket based forwarder
+
+## Using hicn-light ##
+
+### Platforms ###
+
+hicn-light has been tested in:
+
+- Ubuntu 16.04 (x86_64)
+- Debian Testing
+- MacOSX 10.12
+
+Other platforms and architectures may work.
+
+### Dependencies ###
+
+Build dependencies:
+
+- c99 ( clang / gcc )
+- CMake 3.4
+
+Basic dependencies:
+
+- OpenSSL
+- pthreads
+- Libevent
+- Libparc
+
+## hicn-light Executables ##
+
+hicn-light is a set of binary executables that are used to run a forwarder instance. 
+The forwarder can be run and configured using the commands
+
+- `hicnLightDaemon`
+- `hicnLightControl`
+
+Use the `-h` option to display the help messages
+
+### hicn-light Daemon ###
+
+The command `hicnLightDaemon` runs the hicn-light forwarder. The forwarder can be executed 
+with the following options:
+
+```
+hicnLightDaemon [--port port] [--daemon] [--capacity objectStoreSize] [--log facility=level] 
+                [--log-file filename] [--config file]
+
+Options:
+
+--port            = tcp port for local in-bound connections
+--daemon          = start as daemon process
+--capacity        = maximum number of content objects to cache. To disable the cache 
+                    objectStoreSize must be 0.
+                    Default vaule for objectStoreSize is 100000
+--log             = sets a facility to a given log level. You can have multiple of these.
+                    facilities: all, config, core, io, message, processor
+                    levels: debug, info, notice, warning, error, critical, alert, off
+                    example: hicnLightDaemon --log io=debug --log core=off
+--log-file        = file to write log messages to (required in daemon mode)
+--config          = configuration filename
+```
+
+The configuration file contains configuration lines as per hicnLightControl (see below for all
+the available commands). If logging level or content store capacity is set in the configuration
+file, it overrides the command_line. When a configuration file is specified, no default listeners
+are setup.  Only 'add listener' lines in the configuration file matter.
+
+If no configuration file is specified, hicnLightDaemon will listen on TCP and UDP ports specified
+by the --port flag (or default port).  It will listen on both IPv4 and IPv6 if available. The
+default port for hicn-light is 9695. Commands are expected on port 2001.
+
+### hicn-light Control ###
+
+`hicnLightControl` can be used to send command to the hicn-light forwarder and configure it.
+The command can be executed in the following way:
+
+```
+hicnLightControl [commands]
+
+Options:
+    -h              = This help screen
+    commands        = configuration line to send to hicn-light (use 'help' for list)
+```
+
+#### Available Commands in hicn-light Control ####
+
+This is the full list of available commands in `hicnLightControl`. This commands can be used
+from the command line running `hicnLightControl` as explained before, or listing them in a
+configuration file.
+
+Information about the commands are also available in the `hicnLightControl` help message.
+
+`add listener`: creates a TCP or UDP listener with the specified options on the local forwarder.
+For local connections (application to hicn-light) we expect a TCP listener. The default port for
+the local listener is 9695.
+
+```
+add listener <protocol> <symbolic> <local_adress> <local_port>
+
+  <symbolic>        :User defined name for listener, must start with alpha and bealphanum
+  <protocol>        :tcp | udp
+  <localAddress>    :IPv4 or IPv6 address
+  <local_port>      :TCP/UDP port
+
+```
+
+`add listener hicn`: creates a hicn listener with the specified options on the local forwarder.
+
+```
+add listener hicn <symbolic> <local_adress>
+
+  <symbolic>        :User defined name for listener, must start with alpha and be alphanum
+  <localAddress>    :IPv4 or IPv6 address
+
+```
+
+`add connection`: creates a TCP or UDP connection on the local forwarder with the specified options.
+
+```
+add connection <protocol> <symbolic> <remote_ip> <remote_port> <local_ip> <local_port>
+
+  <protocol>              : tcp | udp
+  <symbolic>              : symbolic name, e.g. 'conn1' (must be unique, start with alpha)
+  <remote_ip>             : the IPv4 or IPv6 of the remote system
+  <remote_port>           : the remote TCP/UDP port
+  <local_ip>              : local IP address to bind to
+  <local_port>            : local TCP/UDP port
+
+```
+`add connection hicn`: creates an hicn connection on the local forwarder with the specified options.
+
+```
+add connection hicn <symbolic> <remote_ip> <local_ip>
+
+  <symbolic>            : symbolic name, e.g. 'conn1' (must be unique, start with alpha)
+  <remote_ip>           : the IPv4 or IPv6 of the remote system
+  <local_ip>            : local IP address to bind to
+
+```
+`list`: lists the connections, routes or listeners available on the local hicn-light forwarder
+```
+list <connections | routes | listeners>
+
+```
+`add route`: adds a route to the specified connection
+
+```
+add route <symbolic | connid> <prefix> <cost>
+
+  <symbolic>   :The symbolic name for an exgress (must be unique, start with alpha)
+  <connid>:    :The egress connection id (see 'help list connections')
+  <prefix>:    :ipAddress/netmask
+  <cost>:      :positive integer representing cost
+```
+
+`remove connection`: removes the specified connection. At the moment, this commands is available
+only for UDP connections, TCP is ignored.
+
+```
+remove connection <protocol> <symbolic | connid>
+
+  <protocol>   : tcp | upd. This is the protocol used to create the connection.
+  <symbolic>   :The symbolic name for an exgress (must be unique, start with alpha)
+  <connid>:    :The egress connection id (see 'help list connections')
+
+```
+
+`remove route`: remove the specified prefix for a local connection
+
+```
+remove route <symbolic | connid> <prefix>
+
+  <connid>    : the alphanumeric name of a local connection
+  <prefix>    : the prefix (ipAddress/netmask) to remove
+```
+
+`cache serve`: enables/disables replies from local content store (if available)
+
+```
+cache serve <on|off>
+```
+`cache store`:  enables/disables the storage of incoming data packets in the local content store
+(if available)
+
+```
+cache store <on|off>
+
+```
+`cache clear`: removes all the cached data form the local content store (if available)
+
+```
+cache clear
+
+```
+`set strategy`: sets the forwarding strategy for a give prefix. There are 4 different strategies
+implemented in hicn-light:
+
+- random: each interest is forwarded randomly to one of the available output connections
+- random_per_dash_segment: the output connection is selected randomly for each DASH segment.
+  This can be used only for DASH video streams.
+- loadbalancer: each interest is forwarded toward the output connection with the lowest number
+  of pending interests. The pending interest are the interest sent on a certain connection but
+  not yet satisfied. More information are available in: 
+  G. Carofiglio, M. Gallo, L. Muscariello, M. Papalini, S. Wang, 
+  "Optimal multipath congestion control and request forwarding in information-centric networks", 
+  ICNP 2013.
+- loadbalancer_with_delay: implements the same strategy as loadbalancer but it takes into account
+  also the propagation delay behind each connections.
+
+```
+set strategy <prefix> <strategy>
+
+  <preifx>    : the prefix to which apply the forwarding strategy
+  <strategy>  : random | random_per_dash_segment | loadbalancer | loadbalancer_with_delay
+```
+`set wldr`: turns on/off WLDR on the specified connection. WLDR (Wireless Loss Detiection and
+ Recovery) is a protocol that can be used to recover losses generated by unreliable wireless 
+ connections, such as WIFI. More information on WLDR are available in: 
+ G. Carofiglio, L. Muscariello, M. Papalini, N. Rozhnova, X. Zeng, 
+ "Leveraging ICN In-network Control for Loss Detection and Recovery in Wireless Mobile networks", 
+ ICN 2016. Notice that WLDR is currently available only for UDP connections. In order to work
+ properly, WLDR needs to be activated on both side of the connection.
+
+```
+set wldr <on|off> <symbolic | connid>
+
+  <symbolic>   :The symbolic name for an exgress (must be unique, start with alpha)
+  <connid>:    :The egress connection id (see 'help list connections')
+
+```
+`add punting`: Add punting rules to the forwarders.
+
+```
+add punting <symbolic> <prefix>
+
+ <symbolic> : listener symbolic name
+ <address>  : prefix to add as a punting rule. (example 1234::0/64)
+```
+`mapme enable`: enables/disables mapme
+
+```
+mapme enable <on|off>
+```
+`mapme discovery`: enables/disables mapme discovery
+
+```
+mapme discovery <on|off>
+```
+
+`mapme timescale`: set the timescale value expressed in millisencods
+
+```
+mapme timescale <milliseconds>
+```
+`mapme retx`: set the retrasmission time value expressed in millisecond
+
+```
+mapme retx <milliseconds>
+```
+`quit`: Exits the interactive shell
+
+### hicn-light Configuration File Example ###
+
+This is an example of a simple configuration file for hicn-light. It can be loaded by running
+the command `hicnLightDaemon --config configFile.cfg`, assuming the file name is configFile.cfg
+
+```
+#create a local listener on port 9199. This will be used by the applications to talk
+with the forwarder
+add listener udp local0 127.0.0.1 9199
+
+#create a connection with a remote node
+add connection udp conn0 192.168.0.20 12345 127.0.0.1 9199
+
+#add a route toward the remote node
+add route conn0 192.168.0.20/24 1
+```
+
+
+## License ##
+
+This software is distributed under the following license:
+
+```
+Copyright (c) 2017-2019 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.
+```
diff --git a/hicn-light/config/hicn-light.service b/hicn-light/config/hicn-light.service
new file mode 100755 (executable)
index 0000000..0f976fc
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2017-2019 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.
+
+[Unit]
+Description=hicn-light is the cisco hicn socket based forwarder.
+#Documentation=man:hicn-light-forwarder
+
+[Service]
+Environment=PORT=9695
+Environment=LOG_FILE=/tmp/hicn_light.log
+Environment=CS_SIZE=1000
+Environment=CONFIG=/etc/hicn/hicn_light.conf
+# This will overrride the default environment
+EnvironmentFile=-/etc/default/source
+ExecStart=/usr/bin/hicnLightDaemon --port ${PORT} --log-file ${LOG_FILE} --capacity ${CS_SIZE} --config ${CONFIG}
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/hicn-light/src/CMakeLists.txt b/hicn-light/src/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..939f38a
--- /dev/null
@@ -0,0 +1,45 @@
+# Define a few configuration variables that we want accessible in the software
+
+include(BuildMacros)
+configure_file(config.h.in config.h @ONLY)
+
+if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS)
+       add_subdirectory(command_line)
+endif ()
+
+add_subdirectory(config)
+add_subdirectory(content_store)
+add_subdirectory(core)
+add_subdirectory(io)
+add_subdirectory(messenger)
+add_subdirectory(platforms)
+add_subdirectory(processor)
+add_subdirectory(socket)
+add_subdirectory(strategies)
+add_subdirectory(utils)
+
+list(APPEND HEADER_FILES
+       ${CMAKE_CURRENT_BINARY_DIR}/config.h
+)
+
+set(COMPILER_DEFINITIONS "-DWITH_MAPME -DWITH_MAPME_FIXES")
+
+list(APPEND HICN_LIGHT_INCLUDE_DIRS
+       ${CMAKE_CURRENT_SOURCE_DIR}/..
+)
+
+if (INSTALL_HEADER)
+       set(TO_INSTALL_HEADERS ${HEADER_FILES})
+endif()
+
+build_library(${LIBHICN_LIGHT}
+       STATIC
+       SOURCES ${SOURCE_FILES}
+       INSTALL_HEADERS ${TO_INSTALL_HEADERS}
+       LINK_LIBRARIES ${LIBRARIES}
+       DEPENDS ${DEPENDENCIES}
+       COMPONENT hicn-light
+       INCLUDE_DIRS ${HICN_LIGHT_INCLUDE_DIRS}
+       INSTALL_ROOT_DIR hicn/hicn-light
+       DEFINITIONS ${COMPILER_DEFINITIONS}
+)
diff --git a/hicn-light/src/command_line/CMakeLists.txt b/hicn-light/src/command_line/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..16c23dc
--- /dev/null
@@ -0,0 +1,2 @@
+add_subdirectory(controller)
+add_subdirectory(daemon)
diff --git a/hicn-light/src/command_line/controller/CMakeLists.txt b/hicn-light/src/command_line/controller/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b53e610
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2017-2019 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.
+
+list(APPEND CONTROLLER_SRC
+  hicnLightControl_main.c
+)
+
+build_executable(${HICN_LIGHT_CONTROL}
+  SOURCES ${CONTROLLER_SRC}
+  LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES}
+  DEPENDS hicn-light
+  COMPONENT hicn-light
+)
diff --git a/hicn-light/src/command_line/controller/hicnLightControl_main.c b/hicn-light/src/command_line/controller/hicnLightControl_main.c
new file mode 100755 (executable)
index 0000000..4641bdd
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <errno.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+#include <src/utils/commands.h>
+
+size_t commandOutputLen = 0;  // preserve the number of structs composing
+                              // payload in case on not interactive call.
+
+// REMINDER: when a new_command is added, the following array has to be updated
+// with the sizeof(new_command). It allows to allocate the buffer for receiving
+// the payload of the DAEMON RESPONSE after the header has beed read. Each
+// command identifier (typedef enum command_id) corresponds to a position in the
+// following array.
+static int payloadLengthController[LAST_COMMAND_VALUE] = {
+    sizeof(add_listener_command),
+    sizeof(add_connection_command),
+    sizeof(list_connections_command),  // needed when get response from FWD
+    sizeof(add_route_command),
+    sizeof(list_routes_command),  // needed when get response from FWD
+    sizeof(remove_connection_command),
+    sizeof(remove_route_command),
+    sizeof(cache_store_command),
+    sizeof(cache_serve_command),
+    0,  // cache clear
+    sizeof(set_strategy_command),
+    sizeof(set_wldr_command),
+    sizeof(add_punting_command),
+    sizeof(list_listeners_command),  // needed when get response from FWD
+    sizeof(mapme_activator_command),
+    sizeof(mapme_activator_command),
+    sizeof(mapme_timing_command),
+    sizeof(mapme_timing_command)};
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+typedef struct controller_main_state {
+  ControlState *controlState;
+} ControlMainState;
+
+static void _displayForwarderLogo(void){
+  const char cli_banner [] =
+  "\033[0;31m   ____ ___      _       \033[0m  __    _               __ _        __   __\n"
+  "\033[0;31m  / __// _ \\    (_)___  \033[0m  / /   (_)____ ___ ____/ /(_)___ _ / /  / /_\n"
+  "\033[0;31m / _/ / // /_  / // _ \\ \033[0m / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"
+  "\033[0;31m/_/  /____/(_)/_/ \\___/ \033[0m/_//_//_/ \\__//_//_/  /_//_/ \\_, //_//_/\\__/\n"
+  "                                                    /___/            \n";
+  printf("%s", cli_banner);
+  printf("\n");
+}
+
+static void _displayUsage(char *programName) {
+  printf("Usage: %s -h\n", programName);
+  printf(
+      "hicn-light is the 1.0 source, which runs on each end system and as a "
+      "software source\n");
+  printf(
+      "on intermediate systems.  controller is the program to configure the "
+      "source, daemon.\n");
+  printf("\n");
+  printf("Options:\n");
+  printf("-h              = This help screen\n");
+  printf(
+      "commands        = configuration line to send to hicn-light (use 'help' "
+      "for list)\n");
+  printf("\n");
+}
+
+static int _parseArgs(int argc, char *argv[], char **keystorePath,
+                      char **keystorePassword, PARCList *commandList) {
+  static struct option longFormOptions[] = {
+      {"help", no_argument, 0, 'h'},
+      {"keystore", required_argument, 0, 'k'},
+      {"password", required_argument, 0, 'p'},
+      {0, 0, 0, 0}};
+
+  int c;
+
+  while (1) {
+    // getopt_long stores the option index here.
+    int optionIndex = 0;
+
+    c = getopt_long(argc, argv, "hk:p:", longFormOptions, &optionIndex);
+
+    // Detect the end of the options.
+    if (c == -1) {
+      break;
+    }
+
+    switch (c) {
+      case 'k':
+        *keystorePath = optarg;
+        break;
+
+      case 'p':
+        *keystorePassword = optarg;
+        break;
+
+      case 'h':
+      default:
+        _displayUsage(argv[0]);
+        return 0;
+    }
+  }
+
+  // Any remaining parameters get put in the command list.
+  if (optind < argc) {
+    while (optind < argc) {
+      parcList_Add(commandList, argv[optind]);
+      optind++;
+    }
+  }
+
+  return 1;
+}
+
+struct iovec *_writeAndReadMessage(ControlState *state, struct iovec *msg) {
+  parcAssertNotNull(msg, "Parameter msg must be non-null");
+  int sockfd = controlState_GetSockfd(state);
+
+  // check if request has a payload
+  if (((header_control_message *)msg[0].iov_base)->length >
+      0) {  // command with payload
+    // write header + payload (compatibility issue: two write needed instead of
+    // the writev)
+    if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0 ||
+        write(sockfd, msg[1].iov_base, msg[1].iov_len) < 0) {
+      printf("\nError while sending the Message: cannot write on socket \n");
+      exit(EXIT_FAILURE);
+    }
+    parcMemory_Deallocate(&msg[1].iov_base);
+  } else {  // command without payload, e.g. 'list'
+    // write header only
+    if (write(sockfd, msg[0].iov_base, msg[0].iov_len) < 0) {
+      printf("\nError while sending the Message: cannot write on socket \n");
+      exit(EXIT_FAILURE);
+    }
+  }
+  parcMemory_Deallocate(&msg[0].iov_base);
+
+  // ======= RECEIVE =======
+
+  header_control_message *headerResponse =
+      (header_control_message *)parcMemory_AllocateAndClear(
+          sizeof(header_control_message));
+  if (recv(sockfd, headerResponse, sizeof(header_control_message), 0) < 0) {
+    printf("\nError in Receiving the Message \n");
+    exit(EXIT_FAILURE);
+  }
+
+  if (headerResponse->messageType < RESPONSE_LIGHT ||
+      headerResponse->messageType >= LAST_MSG_TYPE_VALUE) {
+    char *checkFinMsg = parcMemory_Reallocate(headerResponse, 32);
+    if (recv(sockfd, checkFinMsg, sizeof(checkFinMsg),
+             MSG_PEEK | MSG_DONTWAIT) == 0) {
+      // if recv returns zero, that means the connection has been closed:
+      close(sockfd);
+      printf("\nConnection terminated by the Daemon. Exiting... \n");
+      exit(EXIT_SUCCESS);
+    } else {
+      printf("\nError: Unrecognized message type received \n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  void *payloadResponse = NULL;
+
+  if ((commandOutputLen = headerResponse->length) > 0) {
+    payloadResponse = parcMemory_AllocateAndClear(
+        payloadLengthController[headerResponse->commandID] *
+        headerResponse->length);
+
+    if (recv(sockfd, payloadResponse,
+             payloadLengthController[headerResponse->commandID] *
+                 headerResponse->length,
+             0) < 0) {
+      printf("\nError in Receiving the Message \n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  response[0].iov_base = headerResponse;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payloadResponse;
+  response[1].iov_len = payloadLengthController[headerResponse->commandID] *
+                        headerResponse->length;
+
+  return response;
+}
+
+int main(int argc, char *argv[]) {
+  _displayForwarderLogo();
+
+  if (argc == 2 && strcmp("-h", argv[1]) == 0) {
+    _displayUsage(argv[0]);
+    exit(EXIT_SUCCESS);
+  }
+
+  PARCList *commands =
+      parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+  if (!_parseArgs(argc, argv, NULL, NULL, commands)) {
+    parcList_Release(&commands);
+    exit(EXIT_FAILURE);
+  }
+
+  ControlMainState mainState;
+  mainState.controlState =
+      controlState_Create(&mainState, _writeAndReadMessage, true);
+
+  controlState_RegisterCommand(mainState.controlState,
+                               controlRoot_HelpCreate(mainState.controlState));
+  controlState_RegisterCommand(mainState.controlState,
+                               controlRoot_Create(mainState.controlState));
+
+  if (parcList_Size(commands) > 0) {
+    controlState_SetInteractiveFlag(mainState.controlState, false);
+    controlState_DispatchCommand(mainState.controlState, commands);
+    char **commandOutputMain =
+        controlState_GetCommandOutput(mainState.controlState);
+    if (commandOutputMain != NULL && commandOutputLen > 0) {
+      for (size_t j = 0; j < commandOutputLen; j++) {
+        printf("Output %zu: %s \n", j, commandOutputMain[j]);
+      }
+      controlState_ReleaseCommandOutput(mainState.controlState,
+                                        commandOutputMain, commandOutputLen);
+    }
+    // release
+
+  } else {
+    controlState_Interactive(mainState.controlState);
+  }
+
+  parcList_Release(&commands);
+
+  controlState_Destroy(&mainState.controlState);
+
+  return EXIT_SUCCESS;
+}
diff --git a/hicn-light/src/command_line/daemon/CMakeLists.txt b/hicn-light/src/command_line/daemon/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..fd6cc93
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2017-2019 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.
+
+list(APPEND DAEMON_SRC
+  hicnLightDaemon_main.c
+)
+
+build_executable(${HICN_LIGHT_DAEMON}
+  SOURCES ${DAEMON_SRC}
+  LINK_LIBRARIES ${HICN_LIGHT_LINK_LIBRARIES}
+  DEPENDS hicn-light
+  COMPONENT hicn-light
+)
\ No newline at end of file
diff --git a/hicn-light/src/command_line/daemon/hicnLightDaemon_main.c b/hicn-light/src/command_line/daemon/hicnLightDaemon_main.c
new file mode 100755 (executable)
index 0000000..f6d5217
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static void _displayForwarderLogo(void){
+  const char cli_banner [] =
+  "\033[0;31m   ____ ___      _       \033[0m  __    _               __ _        __   __\n"
+  "\033[0;31m  / __// _ \\    (_)___  \033[0m  / /   (_)____ ___ ____/ /(_)___ _ / /  / /_\n"
+  "\033[0;31m / _/ / // /_  / // _ \\ \033[0m / _ \\ / // __// _ \\___/ // // _ `// _ \\/ __/\n"
+  "\033[0;31m/_/  /____/(_)/_/ \\___/ \033[0m/_//_//_/ \\__//_//_/  /_//_/ \\_, //_//_/\\__/\n"
+  "                                                    /___/            \n";
+  printf("%s", cli_banner);
+  printf("\n");
+}
+
+static void _usage(int exitCode) {
+  printf(
+      "Usage: daemon [--port port] [--daemon] [--capacity objectStoreSize] "
+      "[--log facility=level] [--log-file filename] [--config file]\n");
+  printf("\n");
+  printf(
+      "hicn-light run as a daemon is the program to launch the forwarder, "
+      "either as a console program\n");
+  printf(
+      "or a background daemon (detatched from console).  Once running, use the "
+      "program controller to\n");
+  printf("configure hicn-light.\n");
+  printf("\n");
+  printf(
+      "The configuration file contains configuration lines as per "
+      "controller\n");
+  printf(
+      "If logging level or content store capacity is set in the configuraiton "
+      "file, it overrides the command_line\n");
+  printf(
+      "When a configuration file is specified, no default listeners on 'port' "
+      "are setup.  Only 'add listener' lines\n");
+  printf("in the configuration file matter.\n");
+  printf("\n");
+  printf(
+      "If no configuration file is specified, daemon will listen on TCP and "
+      "UDP ports specified by\n");
+  printf(
+      "the --port flag (or default port).  It will listen on both IPv4 and "
+      "IPv6 if available.\n");
+  printf("\n");
+  printf("Options:\n");
+  printf("--port            = tcp port for in-bound connections\n");
+  printf("--daemon          = start as daemon process\n");
+  printf("--objectStoreSize = maximum number of content objects to cache\n");
+  printf(
+      "--log             = sets a facility to a given log level.  You can have "
+      "multiple of these.\n");
+  printf(
+      "                    facilities: all, config, core, io, message, "
+      "processor\n");
+  printf(
+      "                    levels: debug, info, notice, warning, error, "
+      "critical, alert, off\n");
+  printf("                    example: daemon --log io=debug --log core=off\n");
+  printf(
+      "--log-file        = file to write log messages to (required in daemon "
+      "mode)\n");
+  printf("--config           = configuration filename\n");
+  printf("\n");
+  exit(exitCode);
+}
+
+static void _setLogLevelToLevel(int logLevelArray[LoggerFacility_END],
+                                LoggerFacility facility,
+                                const char *levelString) {
+  PARCLogLevel level = parcLogLevel_FromString(levelString);
+
+  if (level < PARCLogLevel_All) {
+    // we have a good facility and level
+    logLevelArray[facility] = level;
+  } else {
+    printf("Invalid log level string %s\n", levelString);
+    _usage(EXIT_FAILURE);
+  }
+}
+
+/**
+ * string: "facility=level"
+ * Set the right thing in the logger
+ */
+static void _setLogLevel(int logLevelArray[LoggerFacility_END],
+                         const char *string) {
+  char *tofree = parcMemory_StringDuplicate(string, strlen(string));
+  char *p = tofree;
+
+  char *facilityString = strsep(&p, "=");
+  if (facilityString) {
+    char *levelString = p;
+
+    if (strcasecmp(facilityString, "all") == 0) {
+      for (LoggerFacility facility = 0; facility < LoggerFacility_END;
+           facility++) {
+        _setLogLevelToLevel(logLevelArray, facility, levelString);
+      }
+    } else {
+      LoggerFacility facility;
+      for (facility = 0; facility < LoggerFacility_END; facility++) {
+        if (strcasecmp(facilityString, logger_FacilityString(facility)) == 0) {
+          break;
+        }
+      }
+
+      if (facility < LoggerFacility_END) {
+        _setLogLevelToLevel(logLevelArray, facility, levelString);
+      } else {
+        printf("Invalid facility string %s\n", facilityString);
+        _usage(EXIT_FAILURE);
+      }
+    }
+  }
+
+  parcMemory_Deallocate((void **)&tofree);
+}
+
+static void _daemonize(void) {
+  if (getppid() == 1) {
+    // already a daemon
+    return;
+  }
+
+  int forkReturn = fork();
+  parcTrapUnexpectedStateIf(forkReturn < 0, "Fork error");
+
+  if (forkReturn > 0) {
+    // parent exits
+    exit(EXIT_SUCCESS);
+  }
+
+  // Child daemon detaches
+  printf("child continuing, pid = %u\n", getpid());
+
+  // get a new process group independent from old parent
+  setsid();
+
+  /* close all descriptors */
+  for (int i = getdtablesize(); i >= 0; --i) {
+    close(i);
+  }
+
+  // reset errno because it might be seg to EBADF from the close calls above
+  errno = 0;
+
+  // Redirect stdin and stdout and stderr to /dev/null
+  const char *devnull = "/dev/null";
+  int nullfile = open(devnull, O_RDWR);
+  parcAssertTrue(nullfile >= 0, "Error opening file '%s': (%d) %s", devnull,
+                 errno, strerror(errno));
+
+  int ret;
+  ret = dup(nullfile);
+  parcAssertTrue(ret == 1, "Error duping fd 1 got %d file: (%d) %s", ret, errno,
+                 strerror(errno));
+  ret = dup(nullfile);
+  parcAssertTrue(ret == 2, "Error duping fd 2, got %d file: (%d) %s", ret,
+                 errno, strerror(errno));
+
+  // forwarder will capture signals
+}
+
+static Logger *_createLogfile(const char *logfile) {
+  int logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
+  if (logfd < 0) {
+    fprintf(stderr, "Error opening %s for writing: (%d) %s\n", logfile, errno,
+            strerror(errno));
+    exit(EXIT_FAILURE);
+  }
+
+  chmod(logfile, S_IRWXU);
+
+  PARCFileOutputStream *fos = parcFileOutputStream_Create(logfd);
+  PARCOutputStream *pos = parcFileOutputStream_AsOutputStream(fos);
+  PARCLogReporter *reporter = parcLogReporterFile_Create(pos);
+
+  Logger *logger = logger_Create(reporter, parcClock_Wallclock());
+
+  parcOutputStream_Release(&pos);
+  parcLogReporter_Release(&reporter);
+
+  return logger;
+}
+
+int main(int argc, const char *argv[]) {
+  _displayForwarderLogo();
+
+  uint16_t port = PORT_NUMBER;
+  uint16_t configurationPort = 2001;
+  bool daemon = false;
+  int capacity = -1;
+  const char *configFileName = NULL;
+
+  char *logfile = NULL;
+
+  if (argc == 2 && strcasecmp(argv[1], "-h") == 0) {
+    _usage(EXIT_SUCCESS);
+  }
+
+  int logLevelArray[LoggerFacility_END];
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    logLevelArray[i] = -1;
+  }
+
+  for (int i = 0; i < argc; i++) {
+    if (argv[i][0] == '-') {
+      if (strcmp(argv[i], "--config") == 0) {
+        configFileName = argv[i + 1];
+        i++;
+      } else if (strcmp(argv[i], "--port") == 0) {
+        port = atoi(argv[i + 1]);
+        i++;
+      } else if (strcmp(argv[i], "--daemon") == 0) {
+        daemon = true;
+      } else if (strcmp(argv[i], "--capacity") == 0 ||
+                 strcmp(argv[i], "-c") == 0) {
+        capacity = atoi(argv[i + 1]);
+        i++;
+      } else if (strcmp(argv[i], "--log") == 0) {
+        _setLogLevel(logLevelArray, argv[i + 1]);
+        i++;
+      } else if (strcmp(argv[i], "--log-file") == 0) {
+        if (logfile) {
+          // error cannot repeat
+          fprintf(stderr, "Cannot specify --log-file more than once\n");
+          _usage(EXIT_FAILURE);
+        }
+
+        logfile = parcMemory_StringDuplicate(argv[i + 1], strlen(argv[i + 1]));
+        i++;
+      } else {
+        _usage(EXIT_FAILURE);
+      }
+    }
+  }
+
+  // set restrictive umask, in case we create any files
+  umask(027);
+
+  if (daemon && (logfile == NULL)) {
+    fprintf(stderr, "Must specify a logfile when running in daemon mode\n");
+    _usage(EXIT_FAILURE);
+  }
+
+  if (daemon) {
+    // inside this call, parent will EXIT_SUCCESS and child will continue
+    _daemonize();
+  }
+
+  Logger *logger = NULL;
+  if (logfile) {
+    logger = _createLogfile(logfile);
+    parcMemory_Deallocate((void **)&logfile);
+  } else {
+    PARCLogReporter *stdoutReporter = parcLogReporterTextStdout_Create();
+    logger = logger_Create(stdoutReporter, parcClock_Wallclock());
+    parcLogReporter_Release(&stdoutReporter);
+  }
+
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    if (logLevelArray[i] > -1) {
+      logger_SetLogLevel(logger, i, logLevelArray[i]);
+    }
+  }
+
+  // this will update the clock to the tick clock
+  Forwarder *forwarder = forwarder_Create(logger);
+
+  Configuration *configuration = forwarder_GetConfiguration(forwarder);
+
+  if (capacity > -1) {
+    configuration_SetObjectStoreSize(configuration, capacity);
+  }
+
+  if (configFileName) {
+    forwarder_SetupAllListeners(forwarder, port, NULL);
+    forwarder_SetupFromConfigFile(forwarder, configFileName);
+  } else {
+    // NULL to not setup AF_UNIX
+    forwarder_SetupAllListeners(forwarder, port, NULL);
+  }
+
+  Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder);
+
+  logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon",
+             "hicn-light running port %d configuration-port %d", port,
+             configurationPort);
+
+  dispatcher_Run(dispatcher);
+
+  logger_Log(logger, LoggerFacility_Core, PARCLogLevel_Alert, "daemon",
+             "hicn-light exiting port %d", port);
+
+  forwarder_Destroy(&forwarder);
+
+  sleep(2);
+
+  logger_Release(&logger);
+  return 0;
+}
diff --git a/hicn-light/src/config.h.in b/hicn-light/src/config.h.in
new file mode 100755 (executable)
index 0000000..16ec1ab
--- /dev/null
@@ -0,0 +1,5 @@
+/* CPU Cache line size */
+#define LEVEL1_DCACHE_LINESIZE @LEVEL1_DCACHE_LINESIZE@
+
+#define _GNU_SOURCE
+
diff --git a/hicn-light/src/config/CMakeLists.txt b/hicn-light/src/config/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5ce680b
--- /dev/null
@@ -0,0 +1,97 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/configuration.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/commandReturn.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlState.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlList.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/commandOps.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/commandParser.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/configuration.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/configurationFile.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/configurationListeners.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlState.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/symbolicNameTable.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAdd.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddConnection.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddRoute.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddListener.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlList.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListConnections.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListListeners.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlListRoutes.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlQuit.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemove.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveConnection.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemoveRoute.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRoot.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSet.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetDebug.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlUnset.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlUnsetDebug.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMe.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeEnable.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeDiscovery.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeTimescale.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlMapMeRetx.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheServe.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheStore.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCacheClear.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlCache.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetStrategy.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlSetWldr.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlAddPunting.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/controlRemovePunting.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/config/commandOps.c b/hicn-light/src/config/commandOps.c
new file mode 100755 (executable)
index 0000000..027c86e
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#ifndef __ANDROID__
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+#endif
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/commandOps.h>
+#include <src/config/commandParser.h>
+
+CommandOps *commandOps_Create(void *closure, const char *command,
+                              void (*init)(CommandParser *parser,
+                                           CommandOps *ops),
+                              CommandReturn (*execute)(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args),
+                              void (*destroyer)(CommandOps **opsPtr)) {
+  parcAssertNotNull(command, "Parameter command must be non-null");
+  parcAssertNotNull(execute, "Parameter execute must be non-null");
+  CommandOps *ops = parcMemory_AllocateAndClear(sizeof(CommandOps));
+  parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(CommandOps));
+
+  ops->closure = closure;
+  ops->command = parcMemory_StringDuplicate(command, strlen(command) + 1);
+  ops->init = init;
+  ops->execute = execute;
+  ops->destroyer = destroyer;
+  return ops;
+}
+
+void commandOps_Destroy(CommandOps **opsPtr) {
+  parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null");
+  parcAssertNotNull(*opsPtr,
+                    "Parameter opsPtr must dereference to non-null pointer");
+
+  CommandOps *ops = *opsPtr;
+  parcMemory_Deallocate((void **)&(ops->command));
+  // DO NOT call ops->destroyer, we are one!
+  parcMemory_Deallocate((void **)&ops);
+
+  *opsPtr = NULL;
+}
diff --git a/hicn-light/src/config/commandOps.h b/hicn-light/src/config/commandOps.h
new file mode 100755 (executable)
index 0000000..6428a3e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file command_Ops.h
+ * @brief The function structure defining a CLI command
+ *
+ * The function structure that defines a CLI command.  Each command will return
+ * one of these which defines how to run the command.
+ *
+ */
+
+#ifndef command_Ops_h
+#define command_Ops_h
+
+#include <parc/algol/parc_List.h>
+
+#include <src/config/commandReturn.h>
+
+// forward reference
+struct command_parser;
+
+struct command_ops;
+typedef struct command_ops CommandOps;
+
+/**
+ * @typedef CommandOps
+ * @abstract Each command implements a CommandOps
+ * @constant closure is a user-specified pointer for any state the user needs
+ * @constant command The text string of the command, must be the spelled out
+ * string, e.g. "help list routes"
+ * @constant init A function to call to initialize the command at program
+ * startup
+ * @constant execute A function to call to execute the command
+ * @constant destroyer A function to call to release the command
+ * @discussion
+ *     Typically, the root of the thee has an Init function that then initilizes
+ * the rest of the tree.  For example:
+ *
+ * @code
+ *    const CommandOps control_Root = {
+ *      .closure = NULL,
+ *      .command = "", // empty string for root
+ *      .init    = control_Root_Init,
+ *      .execute = control_Root_Execute
+ *      .destroyer = NULL
+ *    };
+ * @endcode
+ *
+ * The control_Root_Init function will then begin adding the subtree under root.
+ * For example:
+ *
+ * @code
+ *  const CommandOps control_Add = {
+ *      .closure = NULL,
+ *      .command = "add",
+ *      .init    = control_Add_Init,
+ *      .execute = control_Add_Execute,
+ *      .destroyer = NULL
+ *  };
+ *
+ *  static void
+ *  control_Root_Init(ControlState *state, CommandOps *ops)
+ *  {
+ *      controlState_RegisterCommand(state, &control_Add);
+ *  }
+ * @endcode
+ */
+struct command_ops {
+  void *closure;
+  char *command;
+  void (*init)(struct command_parser *parser, CommandOps *ops);
+  CommandReturn (*execute)(struct command_parser *parser, CommandOps *ops,
+                           PARCList *args);
+  void (*destroyer)(CommandOps **opsPtr);
+};
+
+/**
+ * A helper function to create the pubically defined CommandOps.
+ *
+ * Retruns allocated memory of the command
+ *
+ * @param [in] command The string is copied
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandOps *commandOps_Create(
+    void *closure, const char *command,
+    void (*init)(struct command_parser *parser, CommandOps *ops),
+    CommandReturn (*execute)(struct command_parser *parser, CommandOps *ops,
+                             PARCList *args),
+    void (*destroyer)(CommandOps **opsPtr));
+
+/**
+ * De-allocates the memory of the CommandOps and the copied command string
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandOps_Destroy(CommandOps **opsPtr);
+#endif  // command_Ops_h
diff --git a/hicn-light/src/config/commandParser.c b/hicn-light/src/config/commandParser.c
new file mode 100755 (executable)
index 0000000..84d273c
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <src/config/commandParser.h>
+
+#ifndef __ANDROID__
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#else
+extern int errno;
+#endif
+#endif
+
+struct command_parser {
+  // key = command, value = CommandOps
+  PARCTreeRedBlack *commandTree;
+  bool debugFlag;
+};
+
+static int _stringCompare(const void *key1, const void *key2) {
+  return strcasecmp((const char *)key1, (const char *)key2);
+}
+
+CommandParser *commandParser_Create(void) {
+  CommandParser *state = parcMemory_AllocateAndClear(sizeof(CommandParser));
+  parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(CommandParser));
+
+  state->commandTree = parcTreeRedBlack_Create(_stringCompare,  // key compare
+                                               NULL,            // key free
+                                               NULL,            // key copy
+                                               NULL,            // value equals
+                                               NULL,            // value free
+                                               NULL             // value copy
+  );
+  state->debugFlag = false;
+  return state;
+}
+
+void commandParser_Destroy(CommandParser **parserPtr) {
+  CommandParser *parser = *parserPtr;
+
+  // destroy every element if it has a destroyer
+  PARCArrayList *values = parcTreeRedBlack_Values(parser->commandTree);
+  if (values) {
+    for (int i = 0; i < parcArrayList_Size(values); i++) {
+      CommandOps *ops = parcArrayList_Get(values, i);
+      parcTreeRedBlack_Remove(parser->commandTree, ops->command);
+      if (ops->destroyer) {
+        ops->destroyer(&ops);
+      }
+    }
+    parcArrayList_Destroy(&values);
+  }
+
+  parcTreeRedBlack_Destroy(&parser->commandTree);
+
+  parcMemory_Deallocate((void **)&parser);
+  *parserPtr = NULL;
+}
+
+void commandParser_SetDebug(CommandParser *state, bool debugFlag) {
+  state->debugFlag = debugFlag;
+}
+
+bool commandParser_GetDebug(CommandParser *state) { return state->debugFlag; }
+
+void commandParser_RegisterCommand(CommandParser *state, CommandOps *ops) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  parcAssertNotNull(ops->command, "Operation command string must be non-null");
+
+  void *exists = parcTreeRedBlack_Get(state->commandTree, ops->command);
+  parcAssertNull(exists, "Command '%s' already exists in the tree %p\n",
+                 ops->command, (void *)exists);
+
+  parcTreeRedBlack_Insert(state->commandTree, (void *)ops->command,
+                          (void *)ops);
+
+  // if the command being registered asked for an init function to be called,
+  // call it
+  if (ops->init != NULL) {
+    ops->init(state, ops);
+  }
+}
+
+static PARCList *parseStringIntoTokens(const char *originalString) {
+  PARCList *list =
+      parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction),
+               PARCArrayListAsPARCList);
+
+  char *token;
+
+  char *tofree =
+      parcMemory_StringDuplicate(originalString, strlen(originalString) + 1);
+  char *string = tofree;
+
+  while ((token = strsep(&string, " \t\n")) != NULL) {
+    if (strlen(token) > 0) {
+      parcList_Add(list, strdup(token));
+    }
+  }
+
+  parcMemory_Deallocate((void **)&tofree);
+
+  return list;
+}
+
+/**
+ * Matches the user arguments to available commands, returning the command or
+ * NULL if not found
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static CommandOps *commandParser_MatchCommand(CommandParser *state,
+                                              PARCList *args) {
+  // Find the longest matching prefix command.
+  // Pretty wildly inefficient
+
+  size_t longest_token_count = 0;
+  char *longest_command = NULL;
+
+  PARCArrayList *commands = parcTreeRedBlack_Keys(state->commandTree);
+  for (int i = 0; i < parcArrayList_Size(commands); i++) {
+    char *command = parcArrayList_Get(commands, i);
+    PARCList *command_tokens = parseStringIntoTokens(command);
+
+    // is it a prefix match?
+    if (parcList_Size(args) >= parcList_Size(command_tokens)) {
+      bool possible_match = true;
+      for (int i = 0; i < parcList_Size(command_tokens) && possible_match;
+           i++) {
+        const char *a = parcList_GetAtIndex(command_tokens, i);
+        const char *b = parcList_GetAtIndex(args, i);
+        if (strncasecmp(a, b, strlen(a) + 1) != 0) {
+          possible_match = false;
+        }
+      }
+
+      if (possible_match &&
+          parcList_Size(command_tokens) > longest_token_count) {
+        longest_token_count = parcList_Size(command_tokens);
+        longest_command = command;
+      }
+    }
+
+    parcList_Release(&command_tokens);
+  }
+
+  parcArrayList_Destroy(&commands);
+
+  if (longest_token_count == 0) {
+    return NULL;
+  } else {
+    CommandOps *ops = parcTreeRedBlack_Get(state->commandTree, longest_command);
+    parcAssertNotNull(ops, "Got null operations for command '%s'\n",
+                      longest_command);
+    return ops;
+  }
+}
+
+CommandReturn commandParser_DispatchCommand(CommandParser *state,
+                                            PARCList *args) {
+  CommandOps *ops = commandParser_MatchCommand(state, args);
+
+  if (ops == NULL) {
+    printf("Command not found.\n");
+    return CommandReturn_Failure;
+  } else {
+    return ops->execute(state, ops, args);
+  }
+}
+
+bool commandParser_ContainsCommand(CommandParser *parser, const char *command) {
+  CommandOps *ops = parcTreeRedBlack_Get(parser->commandTree, command);
+  return (ops != NULL);
+}
diff --git a/hicn-light/src/config/commandParser.h b/hicn-light/src/config/commandParser.h
new file mode 100755 (executable)
index 0000000..78e19e6
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file command_Parser.h
+ * @brief Creates a dictionary of commands and parses a command_line to match
+ * against them
+ *
+ * A user creates individual CommandParserEntry that map a command_line to a
+ * function to execute.  The CommandParser then does a longest-matching prefix
+ * match of a command_line to the dictionary of commands and executes the
+ * appropriate command.
+ *
+ */
+
+#ifndef command_parser_h
+#define command_parser_h
+
+#include <src/config/commandOps.h>
+#include <src/config/commandReturn.h>
+
+struct command_parser;
+typedef struct command_parser CommandParser;
+
+/**
+ * controlState_Create
+ *
+ * Creates the global state for the Control program
+ *
+ * @return non-null A command parser
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandParser *commandParser_Create(void);
+
+/**
+ * Destroys the control state, closing all network connections
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandParser_Destroy(CommandParser **statePtr);
+
+/**
+ * Registers a CommandOps with the system.
+ *
+ * Each command has its complete command prefix in the "command" field.
+ * RegisterCommand will put these command prefixes in to a tree and then match
+ * what a user types against the longest-matching prefix in the tree.  If
+ * there's a match, it will call the "execute" function.
+ *
+ * When the parser is destroyed, each command's destroyer function will be
+ * called.
+ *
+ * @param [in] state An allocated ControlState
+ * @param [in] command The command to register with the system
+ *
+ * Example:
+ * @code
+ *      static ControlReturn
+ *      control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ *      {
+ *          printf("Root Command\n");
+ *          return CommandReturn_Success;
+ *      }
+ *
+ *      static ControlReturn
+ *      control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ *      {
+ *          printf("Foo Bar Command\n");
+ *          return CommandReturn_Success;
+ *      }
+ *
+ *      const CommandOps control_Root = {
+ *      .closure = NULL,
+ *      .command = "", // empty string for root
+ *      .init    = NULL,
+ *      .execute = control_Root_Execute
+ *      };
+ *
+ *      const CommandOps control_FooBar = {
+ *      .closure = NULL,
+ *      .command = "foo bar", // empty string for root
+ *      .init    = NULL,
+ *      .execute = control_FooBar_Execute
+ *      };
+ *
+ *   void startup(void)
+ *   {
+ *      ControlState *state = controlState_Create("happy", "day");
+ *      controlState_RegisterCommand(state, control_FooBar);
+ *      controlState_RegisterCommand(state, control_Root);
+ *
+ *      // this executes "root"
+ *      controlState_DispatchCommand(state, "foo");
+ *      controlState_Destroy(&state);
+ *  }
+ * @endcode
+ */
+void commandParser_RegisterCommand(CommandParser *state, CommandOps *command);
+
+/**
+ * Performs a longest-matching prefix of the args to the command tree
+ *
+ * The command tree is created with controlState_RegisterCommand.
+ *
+ * @param [in] state The allocated ControlState
+ * @param [in] args  Each command_line word parsed to the ordered list
+ *
+ * @return CommandReturn_Success the command was successful
+ * @return CommandReturn_Failure the command failed or was not found
+ * @return CommandReturn_Exit the command indicates that the interactive mode
+ * should exit
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandReturn commandParser_DispatchCommand(CommandParser *state,
+                                            PARCList *args);
+
+/**
+ * Sets the Debug mode, which will print out much more information.
+ *
+ * Prints out much more diagnostic information about what hicn-light controller
+ * is doing. yes, you would make a CommandOps to set and unset this :)
+ *
+ * @param [in] debugFlag true means to print debug info, false means to turn it
+ * off
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void commandParser_SetDebug(CommandParser *state, bool debugFlag);
+
+/**
+ * Returns the debug state of ControlState
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool commandParser_GetDebug(CommandParser *state);
+
+/**
+ * Checks if the command is registered
+ *
+ * Checks if the exact command given is registered.  This is not a prefix match.
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return true The command is registered
+ * @return false The command is not registered
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool commandParser_ContainsCommand(CommandParser *parser, const char *command);
+#endif  // command_parser_h
diff --git a/hicn-light/src/config/commandReturn.h b/hicn-light/src/config/commandReturn.h
new file mode 100755 (executable)
index 0000000..16ee93d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file command_Return.h
+ * @brief The return code used by CLI commands
+ *
+ * This return code is used throughout the command parser and command
+ * implementations to indicate success, failure, or if the program should exit.
+ *
+ */
+
+#ifndef command_return_h
+#define command_return_h
+
+/**
+ * @typedef ControlReturn
+ * @abstract A command returns one of (SUCCESS, FAILURE, EXIT)
+ * @constant SUCCESS means the command succeeded
+ * @constant FAILURE indicates failure
+ * @constant EXIT means the command indicated that hicn-light controller should
+ * exit.
+ * @discussion <#Discussion#>
+ */
+typedef enum command_return {
+  CommandReturn_Success,  // command returned success
+  CommandReturn_Failure,  // command failure
+  CommandReturn_Exit      // command indicates program should exit
+} CommandReturn;
+
+#endif  // command_return_h
diff --git a/hicn-light/src/config/configuration.c b/hicn-light/src/config/configuration.c
new file mode 100755 (executable)
index 0000000..cccd606
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_String.h>
+
+#include <src/config/configurationListeners.h>
+#include <src/config/symbolicNameTable.h>
+
+#include <src/core/connection.h>
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#include <src/core/system.h>
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+
+#include <src/io/streamConnection.h>
+
+#include <src/io/hicnTunnel.h>
+#include <src/io/tcpTunnel.h>
+#include <src/io/udpTunnel.h>
+
+#include <parc/algol/parc_Unsigned.h>
+#include <src/io/listener.h>     //the listener list
+#include <src/io/listenerSet.h>  //   needed to print
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+#include <src/utils/address.h>
+
+#define ETHERTYPE 0x0801
+
+struct configuration {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  size_t maximumContentObjectStoreSize;
+
+  // map from prefix (parcString) to strategy (parcString)
+  PARCHashMap *strategy_map;
+
+  // translates between a symblic name and a connection id
+  SymbolicNameTable *symbolicNameTable;
+};
+
+// ========================================================================================
+
+Configuration *configuration_Create(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null");
+  Configuration *config = parcMemory_AllocateAndClear(sizeof(Configuration));
+  parcAssertNotNull(config, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Configuration));
+  config->forwarder = forwarder;
+  config->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  config->maximumContentObjectStoreSize = 100000;
+  config->strategy_map = parcHashMap_Create();
+  config->symbolicNameTable = symbolicNameTable_Create();
+
+  return config;
+}
+
+void configuration_Destroy(Configuration **configPtr) {
+  parcAssertNotNull(configPtr, "Parameter must be non-null double poitner");
+  parcAssertNotNull(*configPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  Configuration *config = *configPtr;
+  logger_Release(&config->logger);
+  parcHashMap_Release(&(config->strategy_map));
+  symbolicNameTable_Destroy(&config->symbolicNameTable);
+  parcMemory_Deallocate((void **)&config);
+  *configPtr = NULL;
+}
+
+struct iovec *configuration_ProcessRegisterHIcnPrefix(Configuration *config,
+                                                      struct iovec *request,
+                                                      unsigned ingressId) {
+  header_control_message *header = request[0].iov_base;
+  add_route_command *control = request[1].iov_base;
+
+  bool success = false;
+
+  const char *symbolicOrConnid = control->symbolicOrConnid;
+
+  if (strcmp(symbolicOrConnid, "SELF_ROUTE") == 0) {
+    success = forwarder_AddOrUpdateRoute(config->forwarder, control, ingressId);
+  } else if (utils_IsNumber(symbolicOrConnid)) {
+    // case for connid as input
+    unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+    ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+    // check if iconnID present in the fwd table
+    if (connectionTable_FindById(table, connid)) {
+      success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid);
+    } else {
+      logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "ConnID not found, check list connections");
+      // failure
+    }
+
+  } else {
+    // case for symbolic as input: check if symbolic name can be resolved
+    unsigned connid =
+        symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+    // connid = UINT_MAX when symbolicName is not found
+    if (connid != UINT32_MAX) {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Debug)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+                   __func__, "Add route resolve name '%s' to connid %u",
+                   symbolicOrConnid, connid);
+      }
+
+      success = forwarder_AddOrUpdateRoute(config->forwarder, control, connid);
+
+    } else {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Warning)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning,
+                   __func__,
+                   "Add route symbolic name '%s' could not be resolved",
+                   symbolicOrConnid);
+      }
+      // failure
+    }
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(add_route_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(add_route_command));
+  }
+
+  return response;
+}
+
+struct iovec *configuration_ProcessUnregisterHIcnPrefix(Configuration *config,
+                                                        struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  remove_route_command *control = request[1].iov_base;
+
+  bool success = false;
+
+  const char *symbolicOrConnid = control->symbolicOrConnid;
+
+  if (utils_IsNumber(symbolicOrConnid)) {
+    // case for connid as input
+    unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+    ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+    // check if interface index present in the fwd table
+    if (connectionTable_FindById(table, connid)) {
+      success = forwarder_RemoveRoute(config->forwarder, control, connid);
+    } else {
+      logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "ConnID not found, check list connections");
+      // failure
+    }
+
+  } else {
+    // case for symbolic as input: chech if symbolic name can be resolved
+    unsigned connid =
+        symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+    // connid = UINT_MAX when symbolicName is not found
+    if (connid != UINT32_MAX) {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Debug)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+                   __func__, "Remove route resolve name '%s' to connid %u",
+                   symbolicOrConnid, connid);
+      }
+      success = forwarder_RemoveRoute(config->forwarder, control, connid);
+    } else {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Warning)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Warning,
+                   __func__,
+                   "Remove route symbolic name '%s' could not be resolved",
+                   symbolicOrConnid);
+      }
+      // failure
+    }
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(remove_route_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(remove_route_command));
+  }
+
+  return response;
+}
+
+struct iovec *configuration_ProcessRegistrationList(Configuration *config,
+                                                    struct iovec *request) {
+  FibEntryList *fibList = forwarder_GetFibEntries(config->forwarder);
+
+  size_t payloadSize = fibEntryList_Length(fibList);
+  size_t pointerLocation = 0;
+  struct sockaddr_in tmpAddr;
+  struct sockaddr_in6 tmpAddr6;
+
+  // allocate payload, cast from void* to uint8_t* = bytes granularity
+  uint8_t *payloadResponse =
+      parcMemory_AllocateAndClear(sizeof(list_routes_command) * payloadSize);
+
+  for (size_t i = 0; i < fibEntryList_Length(fibList); i++) {
+    FibEntry *entry = (FibEntry *)fibEntryList_Get(fibList, i);
+    NameBitvector *prefix = name_GetContentName(fibEntry_GetPrefix(entry));
+    const NumberSet *nexthops = fibEntry_GetNexthops(entry);
+
+    if (numberSet_Length(nexthops) > 1) {
+      // payload extended, need reallocate, further entries via nexthops
+      payloadSize = payloadSize + numberSet_Length(nexthops) - 1;
+      payloadResponse = (uint8_t *)parcMemory_Reallocate(
+          payloadResponse, sizeof(list_routes_command) * payloadSize);
+    }
+
+    for (size_t j = 0; j < numberSet_Length(nexthops); j++) {
+      list_routes_command *listRouteCommand =
+          (list_routes_command *)(payloadResponse +
+                                  (pointerLocation *
+                                   sizeof(list_routes_command)));
+
+      Address *addressEntry = nameBitvector_ToAddress(prefix);
+      if (addressGetType(addressEntry) == ADDR_INET) {
+        addressGetInet(addressEntry, &tmpAddr);
+        listRouteCommand->addressType = ADDR_INET;
+        listRouteCommand->address.ipv4 = tmpAddr.sin_addr.s_addr;
+      } else if (addressGetType(addressEntry) == ADDR_INET6) {
+        addressGetInet6(addressEntry, &tmpAddr6);
+        listRouteCommand->addressType = ADDR_INET6;
+        listRouteCommand->address.ipv6 = tmpAddr6.sin6_addr;
+      }
+      listRouteCommand->connid = numberSet_GetItem(nexthops, j);
+      listRouteCommand->len = nameBitvector_GetLength(prefix);
+      listRouteCommand->cost = 1;  // cost
+
+      pointerLocation++;
+      addressDestroy(&addressEntry);
+    }
+  }
+
+  // send response
+  header_control_message *header = request[0].iov_base;
+  header->messageType = RESPONSE_LIGHT;
+  header->length = payloadSize;
+
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  response[0].iov_base = header;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payloadResponse;
+  response[1].iov_len = sizeof(list_routes_command) * payloadSize;
+
+  return response;
+}
+
+static void configuration_SendResponse(Configuration *config, struct iovec *msg,
+                                       unsigned egressId) {
+  ConnectionTable *connectionTable =
+      forwarder_GetConnectionTable(config->forwarder);
+  const Connection *conn = connectionTable_FindById(connectionTable, egressId);
+  parcAssertNotNull(conn,
+                    "Got null connection for control message we just received");
+
+  IoOperations *ops = connection_GetIoOperations(conn);
+  streamState_SendCommandResponse(ops, msg);
+}
+
+struct iovec *configuration_ProcessCreateTunnel(Configuration *config,
+                                                struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  add_connection_command *control = request[1].iov_base;
+
+  bool success = false;
+  bool exists = true;
+
+  const char *symbolicName = control->symbolic;
+
+  Address *source = NULL;
+  Address *destination = NULL;
+
+  if (!symbolicNameTable_Exists(config->symbolicNameTable, symbolicName)) {
+    if (control->ipType == ADDR_INET) {
+      source =
+          utils_AddressFromInet(&control->localIp.ipv4, &control->localPort);
+      destination =
+          utils_AddressFromInet(&control->remoteIp.ipv4, &control->remotePort);
+    } else if (control->ipType == ADDR_INET6) {
+      source =
+          utils_AddressFromInet6(&control->localIp.ipv6, &control->localPort);
+      destination =
+          utils_AddressFromInet6(&control->remoteIp.ipv6, &control->remotePort);
+    } else {
+      printf("Invalid IP type.\n");  // will generate a Nack
+    }
+
+    AddressPair *pair = addressPair_Create(source, destination);
+    const Connection *conn = connectionTable_FindByAddressPair(
+        forwarder_GetConnectionTable(config->forwarder), pair);
+
+    addressPair_Release(&pair);
+
+    if (conn == NULL) {
+      // the connection does not exists (even without a name)
+      exists = false;
+    }
+  }
+
+  if (!exists) {
+    IoOperations *ops = NULL;
+    switch (control->connectionType) {
+      case TCP_CONN:
+        // logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+        // __func__,
+        //                  "Unsupported tunnel protocol: TCP");
+        ops = tcpTunnel_Create(config->forwarder, source, destination);
+        break;
+      case UDP_CONN:
+        ops = udpTunnel_Create(config->forwarder, source, destination);
+        break;
+      case GRE_CONN:
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+                   __func__, "Unsupported tunnel protocol: GRE");
+        break;
+#ifndef __APPLE__
+      case HICN_CONN:
+        ops = hicnTunnel_Create(config->forwarder, source, destination);
+        break;
+#endif /* __APPLE__ */
+      default:
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+                   __func__, "Unsupported tunnel protocol: %d",
+                   control->connectionType);
+        break;
+    }
+
+    if (ops != NULL) {
+      Connection *conn = connection_Create(ops);
+
+      connectionTable_Add(forwarder_GetConnectionTable(config->forwarder),
+                          conn);
+      symbolicNameTable_Add(config->symbolicNameTable, symbolicName,
+                            connection_GetConnectionId(conn));
+
+      success = true;
+
+    } else {
+      printf("failed, could not create IoOperations");
+    }
+
+  } else {
+    printf("failed, symbolic name or connextion already exist\n");
+  }
+
+  addressDestroy(&source);
+  addressDestroy(&destination);
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(add_connection_command));
+  } else {  // NACK
+    response =
+        utils_CreateNack(header, control, sizeof(add_connection_command));
+  }
+
+  return response;
+}
+
+/**
+ * Add an IP-based tunnel.
+ *
+ * The call cal fail if the symbolic name is a duplicate.  It could also fail if
+ * there's an problem creating the local side of the tunnel (i.e. the local
+ * socket address is not usable).
+ *
+ * @return true Tunnel added
+ * @return false Tunnel not added (an error)
+ */
+
+struct iovec *configuration_ProcessRemoveTunnel(Configuration *config,
+                                                struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  remove_connection_command *control = request[1].iov_base;
+
+  bool success = false;
+
+  const char *symbolicOrConnid = control->symbolicOrConnid;
+  ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+
+  if (utils_IsNumber(symbolicOrConnid)) {
+    // case for connid as input
+    unsigned connid = (unsigned)strtold(symbolicOrConnid, NULL);
+
+    // check if interface index present in the fwd table
+    //(it was missing and therefore caused a program crash)
+    if (connectionTable_FindById(table, connid)) {
+      // remove connection from the FIB
+      forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
+      // remove connection
+      connectionTable_RemoveById(table, connid);
+
+      success = true;
+    } else {
+      logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "ConnID not found, check list connections");
+      // failure
+    }
+
+  } else {
+    // case for symbolic as input
+    // chech if symbolic name can be resolved
+    unsigned connid =
+        symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+    // connid = UINT_MAX when symbolicName is not found
+    if (connid != UINT32_MAX) {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Debug)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+                   __func__, "Remove connection resolve name '%s' to connid %u",
+                   symbolicOrConnid, connid);
+      }
+
+      // remove connection from the FIB
+      forwarder_RemoveConnectionIdFromRoutes(config->forwarder, connid);
+      // remove connection
+      connectionTable_RemoveById(table, connid);
+      // remove connection from symbolicNameTable since we have symbolic input
+      symbolicNameTable_Remove(config->symbolicNameTable, symbolicOrConnid);
+      success = true;  // to write
+    } else {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Warning)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+                   __func__,
+                   "Remove connection symbolic name '%s' could not be resolved",
+                   symbolicOrConnid);
+      }
+      // failure
+    }
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {  // ACK
+    response =
+        utils_CreateAck(header, control, sizeof(remove_connection_command));
+  } else {  // NACK
+    response =
+        utils_CreateNack(header, control, sizeof(remove_connection_command));
+  }
+
+  return response;
+}
+
+struct iovec *configuration_ProcessConnectionList(Configuration *config,
+                                                  struct iovec *request) {
+  ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+  ConnectionList *connList = connectionTable_GetEntries(table);
+  struct sockaddr_in tmpAddr;
+  struct sockaddr_in6 tmpAddr6;
+
+  // allocate payload, cast from void* to uint8_t* fot bytes granularity
+  uint8_t *payloadResponse = parcMemory_AllocateAndClear(
+      sizeof(list_connections_command) * connectionList_Length(connList));
+
+  for (size_t i = 0; i < connectionList_Length(connList); i++) {
+    // Don't release original, it is not stored
+    Connection *original = connectionList_Get(connList, i);
+
+    const AddressPair *addressPair = connection_GetAddressPair(original);
+    Address *localAddress = addressCopy(addressPair_GetLocal(addressPair));
+    Address *remoteAddress = addressCopy(addressPair_GetRemote(addressPair));
+
+    // Fill payload by shifting and casting at each 'i' step.
+    list_connections_command *listConnectionsCommand =
+        (list_connections_command *)(payloadResponse +
+                                     (i * sizeof(list_connections_command)));
+
+    // set structure fields
+    listConnectionsCommand->connid = connection_GetConnectionId(original);
+    listConnectionsCommand->state =
+        connection_IsUp(original) ? IFACE_UP : IFACE_DOWN;
+    listConnectionsCommand->connectionData.connectionType =
+        ioOperations_GetConnectionType(connection_GetIoOperations(original));
+
+    if (addressGetType(localAddress) == ADDR_INET &&
+        addressGetType(remoteAddress) == ADDR_INET) {
+      listConnectionsCommand->connectionData.ipType = ADDR_INET;
+
+      // get local port/address
+      addressGetInet(localAddress, &tmpAddr);
+      listConnectionsCommand->connectionData.localPort = tmpAddr.sin_port;
+      listConnectionsCommand->connectionData.localIp.ipv4 =
+          tmpAddr.sin_addr.s_addr;
+      memset(&tmpAddr, 0, sizeof(tmpAddr));
+      // get remote port/address
+      addressGetInet(remoteAddress, &tmpAddr);
+      listConnectionsCommand->connectionData.remotePort = tmpAddr.sin_port;
+      listConnectionsCommand->connectionData.remoteIp.ipv4 =
+          tmpAddr.sin_addr.s_addr;
+
+    } else if (addressGetType(localAddress) == ADDR_INET6 &&
+               addressGetType(remoteAddress) == ADDR_INET6) {
+      listConnectionsCommand->connectionData.ipType = ADDR_INET6;
+
+      // get local port/address
+      addressGetInet6(localAddress, &tmpAddr6);
+      listConnectionsCommand->connectionData.localPort = tmpAddr6.sin6_port;
+      listConnectionsCommand->connectionData.localIp.ipv6 = tmpAddr6.sin6_addr;
+      memset(&tmpAddr6, 0, sizeof(tmpAddr6));
+      // get remote port/address
+      addressGetInet6(remoteAddress, &tmpAddr6);
+      listConnectionsCommand->connectionData.remotePort = tmpAddr6.sin6_port;
+      listConnectionsCommand->connectionData.remoteIp.ipv6 = tmpAddr6.sin6_addr;
+
+    }  // no need further else, control on the addressed already done at the
+       // time of insertion in the connection table
+    addressDestroy(&localAddress);
+    addressDestroy(&remoteAddress);
+  }
+
+  // send response
+  header_control_message *header = request[0].iov_base;
+  header->messageType = RESPONSE_LIGHT;
+  header->length = (uint16_t)connectionList_Length(connList);
+
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  response[0].iov_base = header;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payloadResponse;
+  response[1].iov_len =
+      sizeof(list_connections_command) * connectionList_Length(connList);
+
+  return response;
+}
+
+struct iovec *configuration_ProcessListenersList(Configuration *config,
+                                                 struct iovec *request) {
+  ListenerSet *listenerList = forwarder_GetListenerSet(config->forwarder);
+  struct sockaddr_in tmpAddr;
+  struct sockaddr_in6 tmpAddr6;
+
+  // allocate payload, cast from void* to uint8_t* fot bytes granularity
+  uint8_t *payloadResponse = parcMemory_AllocateAndClear(
+      sizeof(list_listeners_command) * listenerSet_Length(listenerList));
+
+  for (size_t i = 0; i < listenerSet_Length(listenerList); i++) {
+    ListenerOps *listenerEntry = listenerSet_Get(listenerList, i);
+
+    // Fill payload by shifting and casting at each 'i' step.
+    list_listeners_command *listListenersCommand =
+        (list_listeners_command *)(payloadResponse +
+                                   (i * sizeof(list_listeners_command)));
+
+    listListenersCommand->connid =
+        (uint32_t)listenerEntry->getInterfaceIndex(listenerEntry);
+    listListenersCommand->encapType =
+        (uint8_t)listenerEntry->getEncapType(listenerEntry);
+    if (addressGetType((const Address *)listenerEntry->getListenAddress(
+            listenerEntry)) == ADDR_INET) {
+      addressGetInet(
+          (const Address *)listenerEntry->getListenAddress(listenerEntry),
+          &tmpAddr);
+      listListenersCommand->addressType = ADDR_INET;
+      listListenersCommand->address.ipv4 = tmpAddr.sin_addr.s_addr;
+      listListenersCommand->port = tmpAddr.sin_port;
+    } else if (addressGetType((const Address *)listenerEntry->getListenAddress(
+                   listenerEntry)) == ADDR_INET6) {
+      addressGetInet6(
+          (const Address *)listenerEntry->getListenAddress(listenerEntry),
+          &tmpAddr6);
+      listListenersCommand->addressType = ADDR_INET6;
+      listListenersCommand->address.ipv6 = tmpAddr6.sin6_addr;
+      listListenersCommand->port = tmpAddr6.sin6_port;
+    }
+  }
+
+  // send response
+  header_control_message *header = request[0].iov_base;
+  header->messageType = RESPONSE_LIGHT;
+  header->length = (uint16_t)listenerSet_Length(listenerList);
+
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  response[0].iov_base = header;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payloadResponse;
+  response[1].iov_len =
+      sizeof(list_listeners_command) * listenerSet_Length(listenerList);
+
+  return response;
+}
+
+struct iovec *configuration_ProcessCacheStore(Configuration *config,
+                                              struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  ;
+  cache_store_command *control = request[1].iov_base;
+  ;
+
+  bool success = false;
+
+  switch (control->activate) {
+    case ACTIVATE_ON:
+      forwarder_SetChacheStoreFlag(config->forwarder, true);
+      if (forwarder_GetChacheStoreFlag(config->forwarder)) {
+        success = true;
+      }
+      break;
+
+    case ACTIVATE_OFF:
+      forwarder_SetChacheStoreFlag(config->forwarder, false);
+      if (!forwarder_GetChacheStoreFlag(config->forwarder)) {
+        success = true;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  struct iovec *response;
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(cache_store_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(cache_store_command));
+  }
+
+  return response;
+}
+
+struct iovec *configuration_ProcessCacheServe(Configuration *config,
+                                              struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  cache_serve_command *control = request[1].iov_base;
+
+  bool success = false;
+
+  switch (control->activate) {
+    case ACTIVATE_ON:
+      forwarder_SetChacheServeFlag(config->forwarder, true);
+      if (forwarder_GetChacheServeFlag(config->forwarder)) {
+        success = true;
+      }
+      break;
+
+    case ACTIVATE_OFF:
+      forwarder_SetChacheServeFlag(config->forwarder, false);
+      if (!forwarder_GetChacheServeFlag(config->forwarder)) {
+        success = true;
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  struct iovec *response;
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(cache_store_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(cache_store_command));
+  }
+
+  return response;
+}
+
+struct iovec *configuration_ProcessCacheClear(Configuration *config,
+                                              struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+
+  forwarder_ClearCache(config->forwarder);
+
+  struct iovec *response = utils_CreateAck(header, NULL, 0);
+  return response;
+}
+
+size_t configuration_GetObjectStoreSize(Configuration *config) {
+  return config->maximumContentObjectStoreSize;
+}
+
+void _configuration_StoreFwdStrategy(Configuration *config, const char *prefix,
+                                     strategy_type strategy) {
+  PARCString *prefixStr = parcString_Create(prefix);
+  PARCUnsigned *strategyValue = parcUnsigned_Create((unsigned)strategy);
+  parcHashMap_Put(config->strategy_map, prefixStr, strategyValue);
+  parcUnsigned_Release(&strategyValue);
+  parcString_Release(&prefixStr);
+}
+
+struct iovec *configuration_SetWldr(Configuration *config,
+                                    struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  set_wldr_command *control = request[1].iov_base;
+  ConnectionTable *table = forwarder_GetConnectionTable(config->forwarder);
+  Connection *conn = NULL;
+  bool success = false;
+
+  const char *symbolicOrConnid = control->symbolicOrConnid;
+
+  if (utils_IsNumber(symbolicOrConnid)) {
+    // case for connid as input: check if connID present in the fwd table
+    conn = (Connection *)connectionTable_FindById(
+        table, (unsigned)strtold(symbolicOrConnid, NULL));
+    if (conn) {
+      success = true;
+    } else {
+      logger_Log(forwarder_GetLogger(config->forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "ConnID not found, check list connections");  // failure
+    }
+  } else {
+    // case for symbolic as input: check if symbolic name can be resolved
+    unsigned connid =
+        symbolicNameTable_Get(config->symbolicNameTable, symbolicOrConnid);
+    if (connid != UINT32_MAX) {
+      conn = (Connection *)connectionTable_FindById(table, connid);
+      if (conn) {
+        if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                              PARCLogLevel_Debug)) {
+          logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Debug,
+                     __func__, "Set wldr resolve name '%s' to connid %u",
+                     symbolicOrConnid, connid);
+        }
+        success = true;
+      }
+    } else {
+      if (logger_IsLoggable(config->logger, LoggerFacility_Config,
+                            PARCLogLevel_Warning)) {
+        logger_Log(config->logger, LoggerFacility_Config, PARCLogLevel_Error,
+                   __func__, "Symbolic name '%s' could not be resolved",
+                   symbolicOrConnid);
+      }  // failure
+    }
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {
+    switch (control->activate) {
+      case ACTIVATE_ON:
+        connection_EnableWldr(conn);
+        response = utils_CreateAck(header, control, sizeof(set_wldr_command));
+        break;
+
+      case ACTIVATE_OFF:
+        connection_DisableWldr(conn);
+        response = utils_CreateAck(header, control, sizeof(set_wldr_command));
+        break;
+
+      default:  // received wrong value
+        response = utils_CreateNack(header, control, sizeof(set_wldr_command));
+        break;
+    }
+  } else {
+    response = utils_CreateNack(header, control, sizeof(set_wldr_command));
+  }
+
+  return response;
+}
+
+strategy_type configuration_GetForwardingStrategy(Configuration *config,
+                                                  const char *prefix) {
+  PARCString *prefixStr = parcString_Create(prefix);
+  const unsigned *val = parcHashMap_Get(config->strategy_map, prefixStr);
+  parcString_Release(&prefixStr);
+
+  if (val == NULL) {
+    return LAST_STRATEGY_VALUE;
+  } else {
+    return (strategy_type)*val;
+  }
+}
+
+struct iovec *configuration_SetForwardingStrategy(Configuration *config,
+                                                  struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  set_strategy_command *control = request[1].iov_base;
+
+  const char *prefix = utils_PrefixLenToString(
+      control->addressType, &control->address, &control->len);
+  strategy_type strategy = control->strategyType;
+  strategy_type existingFwdStrategy =
+      configuration_GetForwardingStrategy(config, prefix);
+
+  if (existingFwdStrategy == LAST_STRATEGY_VALUE ||
+      strategy != existingFwdStrategy) {
+    // means such a new strategy is not present in the hash table or has to be
+    // updated
+    _configuration_StoreFwdStrategy(config, prefix, strategy);
+    Name *hicnPrefix = name_CreateFromAddress(control->addressType,
+                                              control->address, control->len);
+    forwarder_SetStrategy(config->forwarder, hicnPrefix, strategy);
+    name_Release(&hicnPrefix);
+  }
+
+  struct iovec *response =
+      utils_CreateAck(header, control, sizeof(set_strategy_command));
+
+  return response;
+}
+
+void configuration_SetObjectStoreSize(Configuration *config,
+                                      size_t maximumObjectCount) {
+  config->maximumContentObjectStoreSize = maximumObjectCount;
+
+  forwarder_SetContentObjectStoreSize(config->forwarder,
+                                      config->maximumContentObjectStoreSize);
+}
+
+Forwarder *configuration_GetForwarder(const Configuration *config) {
+  return config->forwarder;
+}
+
+Logger *configuration_GetLogger(const Configuration *config) {
+  return config->logger;
+}
+
+struct iovec *configuration_MapMeEnable(Configuration *config,
+                                        struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  mapme_activator_command *control = request[1].iov_base;
+  const char *stateString[2] = {"on", "off"};
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  parcBufferComposer_Format(composer,
+                            "The mapme enable setting received is: %s",
+                            stateString[control->activate]);
+
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  puts(result);
+  parcMemory_Deallocate((void **)&result);
+  parcBufferComposer_Release(&composer);
+
+  struct iovec *response =
+      utils_CreateAck(header, control, sizeof(mapme_activator_command));
+
+  return response;
+}
+
+struct iovec *configuration_MapMeDiscovery(Configuration *config,
+                                           struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  mapme_activator_command *control = request[1].iov_base;
+  const char *stateString[2] = {"on", "off"};
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  parcBufferComposer_Format(composer,
+                            "The mapme discovery setting received is: %s",
+                            stateString[control->activate]);
+
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  puts(result);
+  parcMemory_Deallocate((void **)&result);
+  parcBufferComposer_Release(&composer);
+
+  struct iovec *response =
+      utils_CreateAck(header, control, sizeof(mapme_activator_command));
+
+  return response;
+}
+
+struct iovec *configuration_MapMeTimescale(Configuration *config,
+                                           struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  mapme_timing_command *control = request[1].iov_base;
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  parcBufferComposer_Format(composer,
+                            "The mapme timescale value received is: %u",
+                            control->timePeriod);
+
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  puts(result);
+  parcMemory_Deallocate((void **)&result);
+  parcBufferComposer_Release(&composer);
+
+  struct iovec *response =
+      utils_CreateAck(header, control, sizeof(mapme_timing_command));
+
+  return response;
+}
+
+struct iovec *configuration_MapMeRetx(Configuration *config,
+                                      struct iovec *request) {
+  header_control_message *header = request[0].iov_base;
+  mapme_timing_command *control = request[1].iov_base;
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  parcBufferComposer_Format(
+      composer, "The mapme retransmission time value received is: %u",
+      control->timePeriod);
+
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  puts(result);
+  parcMemory_Deallocate((void **)&result);
+  parcBufferComposer_Release(&composer);
+
+  struct iovec *response =
+      utils_CreateAck(header, control, sizeof(mapme_timing_command));
+
+  return response;
+}
+
+// ===========================
+// Main functions that deal with receiving commands, executing them, and sending
+// ACK/NACK
+
+struct iovec *configuration_DispatchCommand(Configuration *config,
+                                            command_id command,
+                                            struct iovec *control,
+                                            unsigned ingressId) {
+  struct iovec *response = NULL;
+
+  switch (command) {
+    case ADD_LISTENER:
+      response = configurationListeners_Add(config, control, ingressId);
+      break;
+
+    case ADD_CONNECTION:
+      response = configuration_ProcessCreateTunnel(config, control);
+      break;
+
+    case LIST_CONNECTIONS:
+      response = configuration_ProcessConnectionList(config, control);
+      break;
+
+    case ADD_ROUTE:
+      response =
+          configuration_ProcessRegisterHIcnPrefix(config, control, ingressId);
+      break;
+
+    case LIST_ROUTES:
+      response = configuration_ProcessRegistrationList(config, control);
+      break;
+
+    case REMOVE_CONNECTION:
+      response = configuration_ProcessRemoveTunnel(config, control);
+      break;
+
+    case REMOVE_ROUTE:
+      response = configuration_ProcessUnregisterHIcnPrefix(config, control);
+      break;
+
+    case CACHE_STORE:
+      response = configuration_ProcessCacheStore(config, control);
+      break;
+
+    case CACHE_SERVE:
+      response = configuration_ProcessCacheServe(config, control);
+      break;
+
+    case CACHE_CLEAR:
+      response = configuration_ProcessCacheClear(config, control);
+      break;
+
+    case SET_STRATEGY:
+      response = configuration_SetForwardingStrategy(config, control);
+      break;
+
+    case SET_WLDR:
+      response = configuration_SetWldr(config, control);
+      break;
+
+    case ADD_PUNTING:
+      response = configurationListeners_AddPunting(config, control, ingressId);
+      break;
+
+    case LIST_LISTENERS:
+      response = configuration_ProcessListenersList(config, control);
+      break;
+
+    case MAPME_ENABLE:
+      response = configuration_MapMeEnable(config, control);
+      break;
+
+    case MAPME_DISCOVERY:
+      response = configuration_MapMeDiscovery(config, control);
+      break;
+
+    case MAPME_TIMESCALE:
+      response = configuration_MapMeTimescale(config, control);
+      break;
+
+    case MAPME_RETX:
+      response = configuration_MapMeRetx(config, control);
+      break;
+
+    default:
+      break;
+  }
+
+  return response;
+}
+
+void configuration_ReceiveCommand(Configuration *config, command_id command,
+                                  struct iovec *request, unsigned ingressId) {
+  parcAssertNotNull(config, "Parameter config must be non-null");
+  parcAssertNotNull(request, "Parameter request must be non-null");
+  struct iovec *response =
+      configuration_DispatchCommand(config, command, request, ingressId);
+  configuration_SendResponse(config, response, ingressId);
+
+  switch (command) {
+    case LIST_CONNECTIONS:
+    case LIST_ROUTES:  // case LIST_INTERFACES: case ETC...:
+      parcMemory_Deallocate(
+          &response[1]
+               .iov_base);  // deallocate payload only if generated at fwd side
+      break;
+    default:
+      break;
+  }
+
+  // deallocate received request. It coincides with response[0].iov_base memory
+  // parcMemory_Deallocate(&request);    //deallocate header and payload (if
+  // same sent by controller)
+  parcMemory_Deallocate(&response);  // deallocate iovec pointer
+}
diff --git a/hicn-light/src/config/configuration.h b/hicn-light/src/config/configuration.h
new file mode 100755 (executable)
index 0000000..2bf66c0
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file configuration.h
+ * @brief hicn-light configuration, such as in-band commands or CLI
+ *
+ * Manages all user configuration of the system, such as from the CLI or web
+ * interface It remembers the user commands and will be able to write out a
+ * config file.
+ *
+ */
+
+#ifndef configuration_h
+#define configuration_h
+
+#include <src/utils/commands.h>
+#include <src/core/logger.h>
+
+struct configuration;
+typedef struct configuration Configuration;
+
+struct forwarder;
+typedef struct forwarder Forwarder;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Configuration *configuration_Create(Forwarder *forwarder);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configuration_Destroy(Configuration **configPtr);
+
+void configuration_SetupAllListeners(Configuration *config, uint16_t port,
+                                     const char *localPath);
+
+void configuration_ReceiveCommand(Configuration *config, command_id command,
+                                  struct iovec *request, unsigned ingressId);
+
+/**
+ * Returns the configured size of the content store
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t configuration_GetObjectStoreSize(Configuration *config);
+
+/**
+ * Sets the size of the content store (in objects, not bytes)
+ *
+ * Must be set before starting the forwarder
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configuration_SetObjectStoreSize(Configuration *config,
+                                      size_t maximumContentObjectCount);
+
+strategy_type configuration_GetForwardingStrategy(Configuration *config,
+                                                  const char *prefix);
+
+/**
+ * Returns the Forwarder that owns the Configuration
+ *
+ * Returns the hicn-light Forwarder.  Used primarily by associated classes in
+ * the configuration group.
+ *
+ * @param [in] config An allocated Configuration
+ *
+ * @return non-null The owning Forwarder
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * {
+ *     <#example#>
+ * }
+ * @endcode
+ */
+Forwarder *configuration_GetForwarder(const Configuration *config);
+
+/**
+ * Returns the logger used by the Configuration subsystem
+ *
+ * Returns the logger specified when the Configuration was created.
+ *
+ * @param [in] config An allocated Configuration
+ *
+ * @retval non-null The logger
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Logger *configuration_GetLogger(const Configuration *config);
+
+struct iovec *configuration_DispatchCommand(Configuration *config,
+                                            command_id command,
+                                            struct iovec *control,
+                                            unsigned ingressId);
+
+#endif  // configuration_h
diff --git a/hicn-light/src/config/configurationFile.c b/hicn-light/src/config/configurationFile.c
new file mode 100755 (executable)
index 0000000..eab8f93
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017-2019 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 <ctype.h>
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/configuration.h>
+#include <src/config/configurationFile.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+struct configuration_file {
+  Forwarder *forwarder;
+  const char *filename;
+  FILE *fh;
+
+  size_t linesRead;
+
+  // our custom state machine.
+  ControlState *controlState;
+};
+
+/*
+ * Called by a command to dispatch the correct command
+ */
+struct iovec *_writeRead(ControlState *state, struct iovec *msg) {
+  ConfigurationFile *configFile =
+      (ConfigurationFile *)controlState_GetUserdata(state);
+
+  parcAssertNotNull(msg, "Parameter msg must be non-null");
+  struct iovec *response = configuration_DispatchCommand(
+      forwarder_GetConfiguration(configFile->forwarder),
+      ((header_control_message *)msg[0].iov_base)->commandID, msg, 0);
+
+  return response;
+}
+
+/**
+ * Removes leading whitespace (space + tab).
+ *
+ * If the string is all whitespace, the return value will point to the
+ * terminating '\0'.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @retval non-null A pointer in to string of the first non-whitespace
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static char *_stripLeadingWhitespace(char *str) {
+  while (isspace(*str)) {
+    str++;
+  }
+  return str;
+}
+
+/**
+ * Removes trailing whitespace
+ *
+ * Inserts a NULL after the last non-whitespace character, modiyfing the input
+ * string.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @return non-null A pointer to the input string
+ *
+ * Example:
+ * @code
+ * {
+ *     <#example#>
+ * }
+ * @endcode
+ */
+static char *_stripTrailingWhitespace(char *str) {
+  char *p = str + strlen(str) - 1;
+  while (p > str && isspace(*p)) {
+    p--;
+  }
+
+  // cap it.  If no whitespace, p+1 == str + strlen(str), so will overwrite the
+  // current null.  If all whitespace p+1 == str+1.  For an empty string, p+1 =
+  // str.
+  *(p + 1) = 0;
+
+  // this does not catch the case where the entire string is whitespace
+  if (p == str && isspace(*p)) {
+    *p = 0;
+  }
+
+  return str;
+}
+
+/**
+ * Removed leading and trailing whitespace
+ *
+ * Modifies the input string (may add a NULL at the end).  Will return
+ * a pointer to the first non-whitespace character or the terminating NULL.
+ *
+ * @param [in] str A null-terminated c-string
+ *
+ * @return non-null A pointer in to the input string
+ *
+ * Example:
+ * @code
+ * {
+ *     <#example#>
+ * }
+ * @endcode
+ */
+static char *_trim(char *str) {
+  return _stripTrailingWhitespace(_stripLeadingWhitespace(str));
+}
+
+/**
+ * Parse a string in to a PARCList with one word per element
+ *
+ * The string passed will be modified by inserting NULLs after each token.
+ *
+ * @param [in] str A c-string (will be modified)
+ *
+ * @retval non-null A PARCList where each item is a single word
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static PARCList *_parseArgs(char *str) {
+  PARCList *list =
+      parcList(parcArrayList_Create(NULL), PARCArrayListAsPARCList);
+
+  const char delimiters[] = " \t";
+
+  char *token;
+  while ((token = strsep(&str, delimiters)) != NULL) {
+    parcList_Add(list, token);
+  }
+
+  return list;
+}
+
+// =============================================================
+
+static void _destroy(ConfigurationFile **configFilePtr) {
+  ConfigurationFile *configFile = *configFilePtr;
+  parcMemory_Deallocate((void **)&configFile->filename);
+
+  if (configFile->fh != NULL) {
+    fclose(configFile->fh);
+  }
+
+  controlState_Destroy(&configFile->controlState);
+}
+
+parcObject_ExtendPARCObject(ConfigurationFile, _destroy, NULL, NULL, NULL, NULL,
+                            NULL, NULL);
+
+parcObject_ImplementRelease(configurationFile, ConfigurationFile);
+
+ConfigurationFile *configurationFile_Create(Forwarder *forwarder,
+                                            const char *filename) {
+  parcAssertNotNull(forwarder, "Parameter hicn-fwd must be non-null");
+  parcAssertNotNull(filename, "Parameter filename must be non-null");
+
+  ConfigurationFile *configFile = parcObject_CreateInstance(ConfigurationFile);
+
+  if (configFile) {
+    configFile->linesRead = 0;
+    configFile->forwarder = forwarder;
+    configFile->filename =
+        parcMemory_StringDuplicate(filename, strlen(filename));
+    parcAssertNotNull(configFile->filename, "Could not copy string '%s'",
+                      filename);
+
+    // setup the control state for the command parser: last parameter NULL
+    // because
+    // writeRead still not implemented from configuration file.
+    configFile->controlState =
+        controlState_Create(configFile, _writeRead, false);
+
+    // we do not register Help commands
+    controlState_RegisterCommand(configFile->controlState,
+                                 controlRoot_Create(configFile->controlState));
+
+    // open the file and make sure we can read it
+    configFile->fh = fopen(configFile->filename, "r");
+
+    if (configFile->fh) {
+      if (logger_IsLoggable(forwarder_GetLogger(forwarder),
+                            LoggerFacility_Config, PARCLogLevel_Debug)) {
+        logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config,
+                   PARCLogLevel_Debug, __func__, "Open config file %s",
+                   configFile->filename);
+      }
+    } else {
+      if (logger_IsLoggable(forwarder_GetLogger(forwarder),
+                            LoggerFacility_Config, PARCLogLevel_Error)) {
+        logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_Config,
+                   PARCLogLevel_Error, __func__,
+                   "Could not open config file %s: (%d) %s",
+                   configFile->filename, errno, strerror(errno));
+      }
+
+      // failure cleanup the object -- this nulls it so final return null be
+      // NULL
+      configurationFile_Release(&configFile);
+    }
+  }
+  return configFile;
+}
+
+bool configurationFile_Process(ConfigurationFile *configFile) {
+  parcAssertNotNull(configFile, "Parameter configFile must be non-null");
+
+  // default to a "true" return value and only set to false if we encounter an
+  // error.
+  bool success = true;
+
+#define BUFFERLEN 2048
+  char buffer[BUFFERLEN];
+
+  configFile->linesRead = 0;
+
+  // always clear errors and fseek to start of file in case we get called
+  // multiple times.
+  clearerr(configFile->fh);
+  rewind(configFile->fh);
+
+  while (success && fgets(buffer, BUFFERLEN, configFile->fh) != NULL) {
+    configFile->linesRead++;
+
+    char *stripedBuffer = _trim(buffer);
+    if (strlen(stripedBuffer) > 0) {
+      if (stripedBuffer[0] != '#') {
+        // not empty and not a comment
+
+        // _parseArgs will modify the string
+        char *copy =
+            parcMemory_StringDuplicate(stripedBuffer, strlen(stripedBuffer));
+        PARCList *args = _parseArgs(copy);
+        CommandReturn result =
+            controlState_DispatchCommand(configFile->controlState, args);
+
+        // we ignore EXIT from the configuration file
+        if (result == CommandReturn_Failure) {
+          if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder),
+                                LoggerFacility_Config, PARCLogLevel_Error)) {
+            logger_Log(forwarder_GetLogger(configFile->forwarder),
+                       LoggerFacility_Config, PARCLogLevel_Error, __func__,
+                       "Error on input file %s line %d: %s",
+                       configFile->filename, configFile->linesRead,
+                       stripedBuffer);
+          }
+          success = false;
+        }
+        parcList_Release(&args);
+        parcMemory_Deallocate((void **)&copy);
+      }
+    }
+  }
+
+  if (ferror(configFile->fh)) {
+    if (logger_IsLoggable(forwarder_GetLogger(configFile->forwarder),
+                          LoggerFacility_Config, PARCLogLevel_Error)) {
+      logger_Log(forwarder_GetLogger(configFile->forwarder),
+                 LoggerFacility_Config, PARCLogLevel_Error, __func__,
+                 "Error on input file %s line %d: (%d) %s",
+                 configFile->filename, configFile->linesRead, errno,
+                 strerror(errno));
+    }
+    success = false;
+  }
+
+  return success;
+}
diff --git a/hicn-light/src/config/configurationFile.h b/hicn-light/src/config/configurationFile.h
new file mode 100755 (executable)
index 0000000..5454819
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file configurationFile.h
+ * @brief Accepts a filename and provides a means to read it into Configuration
+ *
+ * Reads a configuration file and converts the lines in to configuration
+ * commands for use in Configuration.
+ *
+ * Accepts '#' lines as comments.  Skips blank and whitespace-only lines.
+ *
+ */
+
+#ifndef configurationFile_h
+#define configurationFile_h
+
+#include <src/core/forwarder.h>
+
+struct configuration_file;
+typedef struct configuration_file ConfigurationFile;
+
+/**
+ * Creates a ConfigurationFile to prepare to process the file
+ *
+ * Prepares the object and opens the file.  Makes sure we can read the file.
+ * Does not read the file or process any commands from the file.
+ *
+ * @param [in] hicn-light An allocated Forwarder to configure with the file
+ * @param [in] filename The file to use
+ *
+ * @retval non-null An allocated ConfigurationFile that is readable
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ConfigurationFile *configurationFile_Create(Forwarder *forwarder,
+                                            const char *filename);
+
+/**
+ * Reads the configuration file line-by-line and issues commands to
+ * Configuration
+ *
+ * Reads the file line by line.  Skips '#' and blank lines.
+ *
+ * Will stop on the first error.  Lines already processed will not be un-done.
+ *
+ * @param [in] configFile An allocated ConfigurationFile
+ *
+ * @retval true The entire files was processed without error.
+ * @retval false There was an error in the file.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool configurationFile_Process(ConfigurationFile *configFile);
+
+// void configurationFile_ProcessForwardingStrategies(Configuration * config,
+// ConfigurationFile * configFile);
+
+/**
+ * Closes the underlying file and releases memory
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] configFilePtr An allocated ConfigurationFile that will be
+ * NULL'd as output
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configurationFile_Release(ConfigurationFile **configFilePtr);
+
+#endif /* defined(configurationFile_h) */
diff --git a/hicn-light/src/config/configurationListeners.c b/hicn-light/src/config/configurationListeners.c
new file mode 100755 (executable)
index 0000000..be30e2a
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2017-2019 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 <arpa/inet.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/core/system.h>
+#include <src/utils/interfaceSet.h>
+#include <src/utils/punting.h>
+
+#include <src/config/configurationListeners.h>
+#include <src/io/hicnListener.h>
+#include <src/io/tcpListener.h>
+#include <src/io/udpListener.h>
+
+#include <src/utils/addressList.h>
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static bool _setupHIcnListenerOnInet4(Forwarder *forwarder,
+                                      const char *symbolic, Address *address) {
+  bool success = false;
+#ifndef __APPLE__
+  ListenerOps *ops =
+      hicnListener_CreateInet(forwarder, (char *)symbolic, address);
+  if (ops != NULL) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add HIcn listener %s to ListenerSet",
+                   symbolic);
+  }
+#endif /* __APPLE__ */
+  return success;
+}
+
+static bool _setupHIcnListenerOnInet6(Forwarder *forwarder,
+                                      const char *symbolic, Address *address) {
+  bool success = false;
+#ifndef __APPLE__
+  ListenerOps *ops =
+      hicnListener_CreateInet6(forwarder, (char *)symbolic, address);
+  if (ops != NULL) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add HIcn listener %s to ListenerSet",
+                   symbolic);
+  }
+#endif /* __APPLE__ */
+  return success;
+}
+
+bool configurationListeners_Remove(const Configuration *config) {
+  Logger *logger = configuration_GetLogger(config);
+  if (logger_IsLoggable(logger, LoggerFacility_Config, PARCLogLevel_Warning)) {
+    logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__,
+               "Removing a listener not supported: ingress %u control %s");
+  }
+
+  return false;
+}
+
+bool _AddPuntingInet(const Configuration *config, Punting *punting,
+                     unsigned ingressId) {
+#ifndef __APPLE__
+  struct sockaddr *addr = parcNetwork_SockAddress("0.0.0.0", 1234);
+  if (addr == NULL) {
+    printf("Error creating address\n");
+    return false;
+  }
+
+  Address *fakeAddr = addressCreateFromInet((struct sockaddr_in *)addr);
+
+  ListenerOps *listenerOps = listenerSet_Find(
+      forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN,
+      fakeAddr);
+  addressDestroy(&fakeAddr);
+
+  if (listenerOps == NULL) {
+    printf("the main listener (IPV4) does not exists\n");
+    return false;
+  }
+
+  struct sockaddr_in puntingAddr;
+
+  Address *address = puntingGetAddress(punting);
+  if (address == NULL) return false;
+
+  bool res = addressGetInet(address, &puntingAddr);
+  if (!res) {
+    printf("unable to read the punting address\n");
+    return false;
+  }
+
+  char prefix[INET_ADDRSTRLEN];
+  inet_ntop(AF_INET, &(puntingAddr.sin_addr), prefix, INET_ADDRSTRLEN);
+
+  char len[5];
+  sprintf(len, "%d", puntingPrefixLen(punting));
+
+  char *prefixStr =
+      malloc(strlen(prefix) + strlen(len) + 2);  //+1 for the zero-terminator
+  if (prefixStr == NULL) {
+    printf("error while create the prefix string\n");
+    return false;
+  }
+  strcpy(prefixStr, prefix);
+  strcat(prefixStr, "/");
+  strcat(prefixStr, len);
+
+  res = hicnListener_Punting(listenerOps, prefixStr);
+  if (!res) {
+    printf("error while adding the punting rule\n");
+    return false;
+  }
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool _AddPuntingInet6(const Configuration *config, Punting *punting,
+                      unsigned ingressId) {
+#ifndef __APPLE__
+  struct sockaddr *addr = parcNetwork_SockAddress("0::0", 1234);
+  if (addr == NULL) {
+    printf("Error creating address\n");
+    return false;
+  }
+
+  Address *fakeAddr = addressCreateFromInet6((struct sockaddr_in6 *)addr);
+
+  // comments:
+  // EncapType: I use the HIcn encap since the puting is available only for HIcn
+  // listeners LocalAddress: The only listern for which we need punting rules is
+  // the main one, which has no address
+  //              so I create a fake empty address. This need to be consistent
+  //              with the address set at creation time
+
+  ListenerOps *listenerOps = listenerSet_Find(
+      forwarder_GetListenerSet(configuration_GetForwarder(config)), ENCAP_HICN,
+      fakeAddr);
+  addressDestroy(&fakeAddr);
+
+  if (listenerOps == NULL) {
+    printf("the main listener does not exists\n");
+    return false;
+  }
+
+  struct sockaddr_in6 puntingAddr;
+  bool res = addressGetInet6(puntingGetAddress(punting), &puntingAddr);
+  if (!res) {
+    printf("unable to read the punting address\n");
+    return false;
+  }
+
+  char prefix[INET6_ADDRSTRLEN];
+  inet_ntop(AF_INET6, &(puntingAddr.sin6_addr), prefix, INET6_ADDRSTRLEN);
+
+  char len[5];
+  sprintf(len, "%d", puntingPrefixLen(punting));
+
+  char *prefixStr =
+      malloc(strlen(prefix) + strlen(len) + 2);  //+1 for the zero-terminator
+  if (prefixStr == NULL) {
+    printf("error while create the prefix string\n");
+    return false;
+  }
+  strcpy(prefixStr, prefix);
+  strcat(prefixStr, "/");
+  strcat(prefixStr, len);
+
+  res = hicnListener_Punting(listenerOps, prefixStr);
+  if (!res) {
+    printf("error while adding the punting rule\n");
+    return false;
+  }
+
+  return true;
+#else
+  return false;
+#endif
+}
+
+//=============     LIGHT COMMAN    ===============
+
+static bool _addEther(Configuration *config, add_listener_command *control,
+                      unsigned ingressId) {
+  // Not implemented
+  return false;
+}
+
+static bool _setupTcpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
+                                    uint16_t *port) {
+  bool success = false;
+
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = *port;
+  addr.sin_addr.s_addr = *addr4;
+
+  ListenerOps *ops = tcpListener_CreateInet(forwarder, addr);
+  if (ops) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add TCP listener on %s to ListenerSet",
+                   addressToString(ops->getListenAddress(ops)));
+  }
+  return success;
+}
+
+static bool _setupUdpListenerOnInet(Forwarder *forwarder, ipv4_addr_t *addr4,
+                                    uint16_t *port) {
+  bool success = false;
+
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = *port;
+  addr.sin_addr.s_addr = *addr4;
+
+  ListenerOps *ops = udpListener_CreateInet(forwarder, addr);
+  if (ops) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add UDP listener on %s to ListenerSet",
+                   addressToString(ops->getListenAddress(ops)));
+  }
+  return success;
+}
+
+static bool _setupTcpListenerOnInet6Light(Forwarder *forwarder,
+                                          ipv6_addr_t *addr6, uint16_t *port,
+                                          uint32_t scopeId) {
+  bool success = false;
+
+  struct sockaddr_in6 addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port = *port;
+  addr.sin6_addr = *addr6;
+  addr.sin6_scope_id = scopeId;
+
+  ListenerOps *ops = tcpListener_CreateInet6(forwarder, addr);
+  if (ops) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add TCP6 listener on %s to ListenerSet",
+                   addressToString(ops->getListenAddress(ops)));
+  }
+  return success;
+}
+
+static bool _setupUdpListenerOnInet6Light(Forwarder *forwarder,
+                                          ipv6_addr_t *addr6, uint16_t *port) {
+  bool success = false;
+
+  struct sockaddr_in6 addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port = *port;
+  addr.sin6_addr = *addr6;
+  addr.sin6_scope_id = 0;
+
+  ListenerOps *ops = udpListener_CreateInet6(forwarder, addr);
+  if (ops) {
+    success = listenerSet_Add(forwarder_GetListenerSet(forwarder), ops);
+    parcAssertTrue(success, "Failed to add UDP6 listener on %s to ListenerSet",
+                   addressToString(ops->getListenAddress(ops)));
+  }
+  return success;
+}
+
+bool _addHicn(Configuration *config, add_listener_command *control,
+              unsigned ingressId) {
+  bool success = false;
+  const char *symbolic = control->symbolic;
+  Address *localAddress = NULL;
+
+  switch (control->addressType) {
+    case ADDR_INET: {
+      localAddress =
+          utils_AddressFromInet(&control->address.ipv4, &control->port);
+      success = _setupHIcnListenerOnInet4(configuration_GetForwarder(config),
+                                          symbolic, localAddress);
+      break;
+    }
+
+    case ADDR_INET6: {
+      localAddress =
+          utils_AddressFromInet6(&control->address.ipv6, &control->port);
+      success = _setupHIcnListenerOnInet6(configuration_GetForwarder(config),
+                                          symbolic, localAddress);
+      break;
+    }
+
+    default:
+      if (logger_IsLoggable(configuration_GetLogger(config),
+                            LoggerFacility_Config, PARCLogLevel_Warning)) {
+        logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+                   PARCLogLevel_Warning, __func__,
+                   "Unsupported address type for HICN (ingress id %u): "
+                   "must be either IPV4 or IPV6",
+                   ingressId);
+      }
+      break;
+  }
+
+  if (success == true && localAddress != NULL) {
+    if (logger_IsLoggable(configuration_GetLogger(config),
+                          LoggerFacility_Config, PARCLogLevel_Info)) {
+      logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+                 PARCLogLevel_Info, __func__,
+                 "Setup hicn listener on address %s",
+                 addressToString(localAddress));
+    }
+  }
+
+  addressDestroy(&localAddress);
+
+  return success;
+}
+
+bool _addIP(Configuration *config, add_listener_command *control,
+            unsigned ingressId) {
+  bool success = false;
+
+  switch (control->addressType) {
+    case ADDR_INET: {
+      if (control->connectionType == UDP_CONN) {
+        success =
+            _setupUdpListenerOnInet(configuration_GetForwarder(config),
+                                    &control->address.ipv4, &control->port);
+      } else if (control->connectionType == TCP_CONN) {
+        success =
+            _setupTcpListenerOnInet(configuration_GetForwarder(config),
+                                    &control->address.ipv4, &control->port);
+      }
+      break;
+    }
+
+    case ADDR_INET6: {
+      if (control->connectionType == UDP_CONN) {
+        success = _setupUdpListenerOnInet6Light(
+            configuration_GetForwarder(config), &control->address.ipv6,
+            &control->port);
+      } else if (control->connectionType == TCP_CONN) {
+        success = _setupTcpListenerOnInet6Light(
+            configuration_GetForwarder(config), &control->address.ipv6,
+            &control->port, 0);
+      }
+      break;
+    }
+
+    default:
+      if (logger_IsLoggable(configuration_GetLogger(config),
+                            LoggerFacility_Config, PARCLogLevel_Warning)) {
+        char *addrStr = utils_CommandAddressToString(
+            control->addressType, &control->address, &control->port);
+        logger_Log(
+            configuration_GetLogger(config), LoggerFacility_Config,
+            PARCLogLevel_Warning, __func__,
+            "Unsupported address type for IP encapsulation ingress id %u: %s",
+            ingressId, addrStr);
+        parcMemory_Deallocate((void **)&addrStr);
+      }
+      break;
+  }
+
+  if (success) {
+    if (logger_IsLoggable(configuration_GetLogger(config),
+                          LoggerFacility_Config, PARCLogLevel_Info)) {
+      char *addrStr = utils_CommandAddressToString(
+          control->addressType, &control->address, &control->port);
+      logger_Log(configuration_GetLogger(config), LoggerFacility_Config,
+                 PARCLogLevel_Info, __func__, "Setup listener on address %s",
+                 addrStr);
+      parcMemory_Deallocate((void **)&addrStr);
+    }
+  }
+
+  return success;
+}
+
+struct iovec *configurationListeners_Add(Configuration *config,
+                                         struct iovec *request,
+                                         unsigned ingressId) {
+  header_control_message *header = request[0].iov_base;
+  add_listener_command *control = request[1].iov_base;
+
+  bool success = false;
+
+  if (control->listenerMode == ETHER_MODE) {
+    parcTrapNotImplemented("Add Ethernet Listener is not supported");
+    success = _addEther(config, control, ingressId);
+    // it is a failure
+  } else if (control->listenerMode == IP_MODE) {
+    success = _addIP(config, control, ingressId);
+  } else if (control->listenerMode == HICN_MODE) {
+    success = _addHicn(config, control, ingressId);
+  } else {
+    Logger *logger = configuration_GetLogger(config);
+    if (logger_IsLoggable(logger, LoggerFacility_Config,
+                          PARCLogLevel_Warning)) {
+      logger_Log(logger, LoggerFacility_Config, PARCLogLevel_Warning, __func__,
+                 "Unsupported encapsulation mode (ingress id %u)", ingressId);
+    }
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(add_listener_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(add_listener_command));
+  }
+
+  return response;
+}
+
+struct iovec *configurationListeners_AddPunting(Configuration *config,
+                                                struct iovec *request,
+                                                unsigned ingressId) {
+  header_control_message *header = request[0].iov_base;
+  add_punting_command *control = request[1].iov_base;
+
+  const char *symbolicOrConnid = control->symbolicOrConnid;
+  uint32_t len = control->len;
+  in_port_t port = htons(1234);
+  bool success = false;
+
+  if (control->addressType == ADDR_INET) {
+    Address *address = utils_AddressFromInet(&control->address.ipv4, &port);
+    Punting *punting = puntingCreate(symbolicOrConnid, address, len);
+    success = _AddPuntingInet(config, punting, ingressId);
+    addressDestroy(&address);
+  } else if (control->addressType == ADDR_INET6) {
+    Address *address = utils_AddressFromInet6(&control->address.ipv6, &port);
+    Punting *punting = puntingCreate(symbolicOrConnid, address, len);
+    success = _AddPuntingInet6(config, punting, ingressId);
+    addressDestroy(&address);
+  } else {
+    printf("Invalid IP type.\n");  // will generate a Nack
+    return utils_CreateNack(header, control, sizeof(add_punting_command));
+  }
+
+  // generate ACK/NACK
+  struct iovec *response;
+  if (success) {  // ACK
+    response = utils_CreateAck(header, control, sizeof(add_punting_command));
+  } else {  // NACK
+    response = utils_CreateNack(header, control, sizeof(add_punting_command));
+  }
+
+  return response;
+}
+
+//===========================       INITIAL LISTENERS ====================
+
+static void _setupListenersOnAddress(Forwarder *forwarder,
+                                     const Address *address, uint16_t port,
+                                     const char *interfaceName) {
+  address_type type = addressGetType(address);
+  switch (type) {
+    case ADDR_INET: {
+      struct sockaddr_in tmp;
+      addressGetInet(address, &tmp);
+      _setupTcpListenerOnInet(forwarder, &tmp.sin_addr.s_addr, &port);
+      break;
+    }
+
+    case ADDR_INET6: {
+      struct sockaddr_in6 tmp;
+      addressGetInet6(address, &tmp);
+      _setupTcpListenerOnInet6Light(forwarder, &tmp.sin6_addr, &port,
+                                    tmp.sin6_scope_id);
+      break;
+    }
+
+    case ADDR_LINK:
+      // not used
+      break;
+
+    default:
+      // dont' know how to handle this, so no listeners
+      break;
+  }
+}
+
+void configurationListeners_SetupAll(const Configuration *config, uint16_t port,
+                                     const char *localPath) {
+  Forwarder *forwarder = configuration_GetForwarder(config);
+  InterfaceSet *set = system_Interfaces(forwarder);
+
+  size_t interfaceSetLen = interfaceSetLength(set);
+  for (size_t i = 0; i < interfaceSetLen; i++) {
+    Interface *iface = interfaceSetGetByOrdinalIndex(set, i);
+
+    const AddressList *addresses = interfaceGetAddresses(iface);
+    size_t addressListLen = addressListLength(addresses);
+
+    for (size_t j = 0; j < addressListLen; j++) {
+      const Address *address = addressListGetItem(addresses, j);
+
+      // Do not start on link address
+      if (addressGetType(address) != ADDR_LINK) {
+        _setupListenersOnAddress(forwarder, address, htons(port),
+                                 interfaceGetName(iface));
+      }
+    }
+  }
+
+  // if (localPath != NULL) {
+  //    _setupLocalListener(forwarder, localPath);
+  //}
+
+  interfaceSetDestroy(&set);
+}
diff --git a/hicn-light/src/config/configurationListeners.h b/hicn-light/src/config/configurationListeners.h
new file mode 100755 (executable)
index 0000000..7332b0c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file configurationListeners.h
+ * @brief Configuration routines related to Listeners
+ *
+ * Adding and removing listeners.
+ *
+ */
+
+#ifndef configurationListeners_h
+#define configurationListeners_h
+
+#include <src/config/configuration.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/address.h>
+
+/**
+ * Setup udp, tcp, and local listeners
+ *
+ *   Will bind to all available IP protocols on the given port.
+ *   Does not add Ethernet listeners.
+ *
+ * @param port is the UPD and TCP port to use
+ * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is
+ * setup
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void configurationListeners_SetupAll(const Configuration *config, uint16_t port,
+                                     const char *localPath);
+
+bool configurationListeners_Remove(const Configuration *config);
+
+// light functions
+
+struct iovec *configurationListeners_Add(Configuration *config,
+                                         struct iovec *request,
+                                         unsigned ingressId);
+
+struct iovec *configurationListeners_AddPunting(Configuration *config,
+                                                struct iovec *request,
+                                                unsigned ingressId);
+
+#endif /* defined(configurationListeners_h) */
diff --git a/hicn-light/src/config/controlAdd.c b/hicn-light/src/config/controlAdd.c
new file mode 100755 (executable)
index 0000000..72f8e97
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlAdd.h>
+#include <src/config/controlAddConnection.h>
+#include <src/config/controlAddListener.h>
+#include <src/config/controlAddPunting.h>
+#include <src/config/controlAddRoute.h>
+
+// ===================================================
+
+static void _controlAdd_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlAdd_Execute(CommandParser *parser, CommandOps *ops,
+                                         PARCList *args);
+static CommandReturn _controlAdd_HelpExecute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args);
+
+// ===================================================
+
+static const char *command_add = "add";
+static const char *help_command_add = "help add";
+
+CommandOps *webControlAdd_Create(ControlState *state) {
+  return commandOps_Create(state, command_add, _controlAdd_Init,
+                           _controlAdd_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAdd_CreateHelp(ControlState *state) {
+  return commandOps_Create(state, help_command_add, NULL,
+                           _controlAdd_HelpExecute, commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlAdd_HelpExecute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args) {
+  CommandOps *ops_add_connection = controlAddConnection_Create(NULL);
+  CommandOps *ops_add_route = controlAddRoute_Create(NULL);
+  CommandOps *ops_add_punting = controlAddPunting_Create(NULL);
+  CommandOps *ops_add_listener = controlAddListener_Create(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_add_connection->command);
+  printf("   %s\n", ops_add_route->command);
+  printf("   %s\n", ops_add_punting->command);
+  printf("   %s\n", ops_add_listener->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_add_connection);
+  commandOps_Destroy(&ops_add_route);
+  commandOps_Destroy(&ops_add_punting);
+  commandOps_Destroy(&ops_add_listener);
+  return CommandReturn_Success;
+}
+
+static void _controlAdd_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlAddListener_HelpCreate(state));
+  controlState_RegisterCommand(state, controlAddListener_Create(state));
+  controlState_RegisterCommand(state, controlAddConnection_HelpCreate(state));
+  controlState_RegisterCommand(state, controlAddRoute_HelpCreate(state));
+  controlState_RegisterCommand(state, controlAddConnection_Create(state));
+  controlState_RegisterCommand(state, controlAddRoute_Create(state));
+  controlState_RegisterCommand(state, controlAddPunting_Create(state));
+  controlState_RegisterCommand(state, controlAddPunting_HelpCreate(state));
+}
+
+static CommandReturn _controlAdd_Execute(CommandParser *parser, CommandOps *ops,
+                                         PARCList *args) {
+  return _controlAdd_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlAdd.h b/hicn-light/src/config/controlAdd.h
new file mode 100755 (executable)
index 0000000..e1955f2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Add.h
+ * @brief Command-line "add" node
+ *
+ * Implements the "add" node of the CLI tree
+ *
+ *
+ */
+
+#ifndef control_Add_h
+#define control_Add_h
+
+#include <src/config/controlState.h>
+
+CommandOps *webControlAdd_Create(ControlState *state);
+CommandOps *controlAdd_CreateHelp(ControlState *state);
+#endif  // control_Add_h
diff --git a/hicn-light/src/config/controlAddConnection.c b/hicn-light/src/config/controlAddConnection.c
new file mode 100755 (executable)
index 0000000..a0a966d
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <parc/assert/parc_Assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddConnection.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+// ===================================================
+
+static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args);
+static CommandReturn _controlAddConnection_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args);
+
+// ===================================================
+
+static CommandReturn _controlAddConnection_HIcnHelpExecute(
+    CommandParser *parser, CommandOps *ops, PARCList *args);
+static CommandReturn _controlAddConnection_HIcnExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args);
+
+static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args);
+static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args);
+
+static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args);
+static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args);
+
+// ===================================================
+
+static const char *_commandAddConnection = "add connection";
+static const char *_commandAddConnectionHIcn = "add connection hicn";
+static const char *_commandAddConnectionUdp = "add connection udp";
+static const char *_commandAddConnectionTcp = "add connection tcp";
+static const char *_commandAddConnectionHelp = "help add connection";
+static const char *_commandAddConnectionHIcnHelp = "help add connection hicn";
+static const char *_commandAddConnectionUdpHelp = "help add connection udp";
+static const char *_commandAddConnectionTcpHelp = "help add connection tcp";
+
+// ===================================================
+
+CommandOps *controlAddConnection_Create(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnection,
+                           _controlAddConnection_Init,
+                           _controlAddConnection_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddConnection_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionHelp, NULL,
+                           _controlAddConnection_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandOps *_controlAddConnection_HIcnCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionHIcn, NULL,
+                           _controlAddConnection_HIcnExecute,
+                           commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_UdpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionUdp, NULL,
+                           _controlAddConnection_UdpExecute,
+                           commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_TcpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionTcp, NULL,
+                           _controlAddConnection_TcpExecute,
+                           commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandOps *_controlAddConnection_HIcnHelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionHIcnHelp, NULL,
+                           _controlAddConnection_HIcnHelpExecute,
+                           commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_UdpHelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionUdpHelp, NULL,
+                           _controlAddConnection_UdpHelpExecute,
+                           commandOps_Destroy);
+}
+
+static CommandOps *_controlAddConnection_TcpHelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddConnectionTcpHelp, NULL,
+                           _controlAddConnection_TcpHelpExecute,
+                           commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlAddConnection_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args) {
+  printf("Available commands:\n");
+  printf("   %s\n", _commandAddConnectionHIcn);
+  printf("   %s\n", _commandAddConnectionUdp);
+  printf("   %s\n", _commandAddConnectionTcp);
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static void _controlAddConnection_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state,
+                               _controlAddConnection_HIcnHelpCreate(state));
+  controlState_RegisterCommand(state,
+                               _controlAddConnection_UdpHelpCreate(state));
+  controlState_RegisterCommand(state,
+                               _controlAddConnection_TcpHelpCreate(state));
+
+  controlState_RegisterCommand(state, _controlAddConnection_HIcnCreate(state));
+  controlState_RegisterCommand(state, _controlAddConnection_UdpCreate(state));
+  controlState_RegisterCommand(state, _controlAddConnection_TcpCreate(state));
+}
+
+static CommandReturn _controlAddConnection_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args) {
+  return _controlAddConnection_HelpExecute(parser, ops, args);
+}
+
+// ===================================================
+// functions general to all connection types
+
+/**
+ * Create a tunnel in the forwarder based on the addresses
+ *
+ * Caller retains ownership of memory.
+ * The symbolic name will be used to refer to this connection. It must be unqiue
+ * otherwise the forwarder will reject this commend.
+ *
+ * @param [in] parser An allocated CommandParser
+ * @param [in] ops Allocated CommandOps (needed to extract ControlState)
+ * @param [in] localAddress the local IP and port.  The port may be the wildcard
+ * value.
+ * @param [in] remoteAddress The remote IP and port (both must be specified)
+ * @param [in] tunnelType The tunneling protocol
+ * @param [in] symbolic The symbolic name for the connection (must be unique)
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * {
+ *      struct sockaddr_in *anyAddress = parcNetwork_SockInet4AddressAny();
+ *      struct sockaddr_in *remote     =
+ * parcNetwork_SockInet4Address("192.168.1.2", 9695);
+ *
+ *      Address *localAddress = addressCreateFromInet(anyAddress);
+ *      Address *remoteAddress = addressCreateFromInet(remote);
+ *
+ *      control_CreateTunnel(state, localAddress, remoteAddress, IPTUN_TCP,
+ * "conn7");
+ *
+ *      addressDestroy(&localAddress);
+ *      addressDestroy(&remoteAddress);
+ *      parcMemory_Deallocate((void **)&remote);
+ *      parcMemory_Deallocate((void **)&anyAddress);
+ * }
+ * @endcode
+ */
+
+static CommandReturn _controlAddConnection_CreateTunnel(
+    CommandParser *parser, CommandOps *ops, const char *local_ip,
+    const char *local_port, const char *remote_ip, const char *remote_port,
+    connection_type tunnelType, const char *symbolic) {
+  ControlState *state = ops->closure;
+  // a request like this always has an interface index of 0 [FIELD REMOVED]
+  // unsigned int interfaceIndex = 0;
+
+  // allocate command payload
+  add_connection_command *addConnectionCommand =
+      parcMemory_AllocateAndClear(sizeof(add_connection_command));
+
+  // check and set IP addresses
+  if (inet_pton(AF_INET, remote_ip, &addConnectionCommand->remoteIp.ipv4) ==
+          1 &&
+      inet_pton(AF_INET, local_ip, &addConnectionCommand->localIp.ipv4) == 1) {
+    addConnectionCommand->ipType = ADDR_INET;
+
+  } else if (inet_pton(AF_INET6, remote_ip,
+                       &addConnectionCommand->remoteIp.ipv6) == 1 &&
+             inet_pton(AF_INET6, local_ip,
+                       &addConnectionCommand->localIp.ipv6) == 1) {
+    addConnectionCommand->ipType = ADDR_INET6;
+
+  } else {
+    printf("Error: local address %s not same type as remote address %s\n",
+           local_ip, remote_ip);
+    parcMemory_Deallocate(&addConnectionCommand);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  addConnectionCommand->connectionType = tunnelType;
+  strcpy(addConnectionCommand->symbolic, symbolic);
+  addConnectionCommand->remotePort = htons((uint16_t)atoi(remote_port));
+  addConnectionCommand->localPort = htons((uint16_t)atoi(local_port));
+
+  // send message and receive response
+  struct iovec *response =
+      utils_SendRequest(state, ADD_CONNECTION, addConnectionCommand,
+                        sizeof(add_connection_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_IpHelp(CommandParser *parser,
+                                                  CommandOps *ops,
+                                                  PARCList *args,
+                                                  const char *protocol) {
+  printf("add connection hicn <symbolic> <remote_ip> <local_ip>\n");
+  printf(
+      "add connection udp <symbolic> <remote_ip> <port> <local_ip> <port>\n");
+  printf(
+      "  <symbolic>              : symbolic name, e.g. 'conn1' (must be "
+      "unique, start with alpha)\n");
+  printf(
+      "  <remote_ip>  : the IPv4 or IPv6 or hostname of the remote system\n");
+  printf("  <local_ip>              : optional local IP address to bind to\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_HIcnHelpExecute(
+    CommandParser *parser, CommandOps *ops, PARCList *args) {
+  _controlAddConnection_IpHelp(parser, ops, args, "hicn");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_HIcnExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args) {
+  static const int _indexSymbolic = 3;
+  static const int _indexRemAddr = 4;
+  static const int _indexLocAddr = 5;
+
+  if (parcList_Size(args) != 6) {
+    _controlAddConnection_HIcnHelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+  if (!utils_ValidateSymbolicName(symbolic)) {
+    printf(
+        "Invalid symbolic name.  Must begin with alpha and contain only "
+        "alphanum.\n");
+    return CommandReturn_Failure;
+  }
+
+  char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+  char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+  char *port = "1234";  // this is a random port number that will be ignored
+
+  return _controlAddConnection_CreateTunnel(
+      parser, ops, local_ip, port, remote_ip, port, HICN_CONN, symbolic);
+}
+
+static CommandReturn _controlAddConnection_UdpHelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args) {
+  _controlAddConnection_IpHelp(parser, ops, args, "udp");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_UdpExecute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args) {
+  static const int _indexSymbolic = 3;
+  static const int _indexRemAddr = 4;
+  static const int _indexRemPort = 5;
+  static const int _indexLocAddr = 6;
+  static const int _indexLocPort = 7;
+
+  if (parcList_Size(args) != 8) {
+    _controlAddConnection_UdpHelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+  if (!utils_ValidateSymbolicName(symbolic)) {
+    printf(
+        "Invalid symbolic name.  Must begin with alpha and contain only "
+        "alphanum.\n");
+    return CommandReturn_Failure;
+  }
+
+  char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+  char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+
+  char *remote_port = parcList_GetAtIndex(args, _indexRemPort);
+  char *local_port = parcList_GetAtIndex(args, _indexLocPort);
+
+  return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port,
+                                            remote_ip, remote_port, UDP_CONN,
+                                            symbolic);
+}
+
+static CommandReturn _controlAddConnection_TcpHelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args) {
+  _controlAddConnection_IpHelp(parser, ops, args, "tcp");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddConnection_TcpExecute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args) {
+  static const int _indexSymbolic = 3;
+  static const int _indexRemAddr = 4;
+  static const int _indexRemPort = 5;
+  static const int _indexLocAddr = 6;
+  static const int _indexLocPort = 7;
+
+  if (parcList_Size(args) != 8) {
+    _controlAddConnection_UdpHelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+  if (!utils_ValidateSymbolicName(symbolic)) {
+    printf(
+        "Invalid symbolic name.  Must begin with alpha and contain only "
+        "alphanum.\n");
+    return CommandReturn_Failure;
+  }
+
+  char *remote_ip = parcList_GetAtIndex(args, _indexRemAddr);
+  char *local_ip = parcList_GetAtIndex(args, _indexLocAddr);
+
+  char *remote_port = parcList_GetAtIndex(args, _indexRemPort);
+  char *local_port = parcList_GetAtIndex(args, _indexLocPort);
+
+  return _controlAddConnection_CreateTunnel(parser, ops, local_ip, local_port,
+                                            remote_ip, remote_port, TCP_CONN,
+                                            symbolic);
+}
diff --git a/hicn-light/src/config/controlAddConnection.h b/hicn-light/src/config/controlAddConnection.h
new file mode 100755 (executable)
index 0000000..7883069
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_AddConnection.h
+ * @brief Command-line "add connection" node
+ *
+ * Implements the "add connection" node of the CLI tree
+ *
+ *
+ */
+
+#ifndef controlAddConnection_h
+#define controlAddConnection_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddConnection_Create(ControlState *state);
+CommandOps *controlAddConnection_HelpCreate(ControlState *state);
+#endif  // controlAddConnection_h
diff --git a/hicn-light/src/config/controlAddListener.c b/hicn-light/src/config/controlAddListener.c
new file mode 100755 (executable)
index 0000000..8f687c3
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddListener.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddListener_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args);
+static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args);
+
+static const char *command_add_listener = "add listener";
+static const char *command_help_add_listener = "help add listener";
+
+CommandOps *controlAddListener_Create(ControlState *state) {
+  return commandOps_Create(state, command_add_listener, NULL,
+                           _controlAddListener_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddListener_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, command_help_add_listener, NULL,
+                           _controlAddListener_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static const int _indexProtocol = 2;
+static const int _indexSymbolic = 3;
+static const int _indexAddress = 4;
+static const int _indexPort = 5;
+
+static CommandReturn _controlAddListener_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args) {
+  printf("commands:\n");
+  printf("   add listener hicn <symbolic> <localAddress> \n");
+  printf("   add listener udp <symbolic> <localAddress> <port> \n");
+  printf("   add listener tcp <symbolic> <localAddress> <port> \n");
+  printf("\n");
+  printf(
+      "   symbolic:        User defined name for listener, must start with "
+      "alpha and be alphanum\n");
+  printf("   protocol:        hicn | udp\n");
+  printf(
+      "   localAddress:    IPv4 or IPv6 address (or prefix protocol = hicn) "
+      "assigend to the local interface\n");
+  printf("   port:            Udp port\n");
+  printf("\n");
+  printf("Notes:\n");
+  printf("   The symblic name must be unique or the source will reject it.\n");
+  printf(
+      "    If protocol = hinc: the address 0::0 indicates the main listern, "
+      "for which we can set punting rules.\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _CreateListener(CommandParser *parser, CommandOps *ops,
+                                     const char *symbolic, const char *addr,
+                                     const char *port, listener_mode mode,
+                                     connection_type type) {
+  ControlState *state = ops->closure;
+
+  // allocate command payload
+  add_listener_command *addListenerCommand =
+      parcMemory_AllocateAndClear(sizeof(add_listener_command));
+
+  // check and set IP address
+  if (inet_pton(AF_INET, addr, &addListenerCommand->address.ipv4) == 1) {
+    addListenerCommand->addressType = ADDR_INET;
+
+  } else if (inet_pton(AF_INET6, addr, &addListenerCommand->address.ipv6) ==
+             1) {
+    addListenerCommand->addressType = ADDR_INET6;
+
+  } else {
+    printf("Error: %s is not a valid network address \n", addr);
+    parcMemory_Deallocate(&addListenerCommand);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  addListenerCommand->listenerMode = mode;
+  addListenerCommand->connectionType = type;
+  addListenerCommand->port = htons((uint16_t)atoi(port));
+  strcpy(addListenerCommand->symbolic, symbolic);
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, ADD_LISTENER, addListenerCommand, sizeof(add_listener_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddListener_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args) {
+  if (parcList_Size(args) != 5 && parcList_Size(args) != 6) {
+    _controlAddListener_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  CommandReturn result = CommandReturn_Failure;
+
+  const char *symbolic = parcList_GetAtIndex(args, _indexSymbolic);
+
+  if (!utils_ValidateSymbolicName(symbolic)) {
+    printf(
+        "Error: symbolic name must begin with an alpha and be alphanum "
+        "after\n");
+    return result;
+  }
+
+  const char *host = parcList_GetAtIndex(args, _indexAddress);
+  const char *protocol = parcList_GetAtIndex(args, _indexProtocol);
+
+  if ((strcasecmp("hicn", protocol) == 0)) {
+    const char *port =
+        "1234";  // this is a random port number that will be ignored
+
+    // here we discard the prefix len if it exists, since we don't use it in
+    // code but we let libhicn to find the right ip address.
+    return _CreateListener(parser, ops, symbolic, host, port, HICN_MODE,
+                           HICN_CONN);
+  }
+
+  const char *port = parcList_GetAtIndex(args, _indexPort);
+
+  if ((strcasecmp("udp", protocol) == 0)) {
+    return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
+                           UDP_CONN);
+  } else if ((strcasecmp("tcp", protocol) == 0)) {
+    return _CreateListener(parser, ops, symbolic, host, port, IP_MODE,
+                           TCP_CONN);
+  } else {
+    _controlAddListener_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  if (result == CommandReturn_Failure) printf("creation failed\n");
+
+  return result;
+}
diff --git a/hicn-light/src/config/controlAddListener.h b/hicn-light/src/config/controlAddListener.h
new file mode 100755 (executable)
index 0000000..d3fc55a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_AddListener.h
+ * @brief Add a listener to an interface
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef Control_AddListener_h
+#define Control_AddListener_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddListener_Create(ControlState *state);
+CommandOps *controlAddListener_HelpCreate(ControlState *state);
+#endif  // Control_AddListener_h
diff --git a/hicn-light/src/config/controlAddPunting.c b/hicn-light/src/config/controlAddPunting.c
new file mode 100755 (executable)
index 0000000..bd87e51
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/punting.h>
+
+#include <src/config/controlAddPunting.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddPunting_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandAddPunting = "add punting";
+static const char *_commandAddPuntingHelp = "help add punting";
+
+static const int _indexSymbolic = 2;
+static const int _indexPrefix = 3;
+
+CommandOps *controlAddPunting_Create(ControlState *state) {
+  return commandOps_Create(state, _commandAddPunting, NULL,
+                           _controlAddPunting_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddPunting_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddPuntingHelp, NULL,
+                           _controlAddPunting_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlAddPunting_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("add punting <symbolic> <prefix>\n");
+  printf("    <symbolic> : listener symbolic name\n");
+  printf(
+      "    <address>  : prefix to add as a punting rule. (example "
+      "1234::0/64)\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddPunting_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 4) {
+    _controlAddPunting_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *symbolicOrConnid = parcList_GetAtIndex(args, _indexSymbolic);
+
+  if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+      !utils_IsNumber(symbolicOrConnid)) {
+    printf(
+        "ERROR: Invalid symbolic or connid:\n"
+        "symbolic name must begin with an alpha followed by alphanum;\nconnid "
+        "must be an integer\n");
+    return CommandReturn_Failure;
+  }
+
+  const char *prefixStr = parcList_GetAtIndex(args, _indexPrefix);
+  char addr[strlen(prefixStr) + 1];
+
+  // separate address and len
+  char *slash;
+  uint32_t len = 0;
+  strcpy(addr, prefixStr);
+  slash = strrchr(addr, '/');
+  if (slash != NULL) {
+    len = atoi(slash + 1);
+    *slash = '\0';
+  }
+
+  if (len == 0) {
+    printf("ERROR: a prefix can not be of length 0\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  add_punting_command *addPuntingCommand =
+      parcMemory_AllocateAndClear(sizeof(add_punting_command));
+
+  // check and set IP address
+  if (inet_pton(AF_INET, addr, &addPuntingCommand->address.ipv4) == 1) {
+    if (len > 32) {
+      printf("ERROR: exceeded INET mask length, max=32\n");
+      parcMemory_Deallocate(&addPuntingCommand);
+      return CommandReturn_Failure;
+    }
+    addPuntingCommand->addressType = ADDR_INET;
+  } else if (inet_pton(AF_INET6, addr, &addPuntingCommand->address.ipv6) == 1) {
+    if (len > 128) {
+      printf("ERROR: exceeded INET6 mask length, max=128\n");
+      parcMemory_Deallocate(&addPuntingCommand);
+      return CommandReturn_Failure;
+    }
+    addPuntingCommand->addressType = ADDR_INET6;
+  } else {
+    printf("Error: %s is not a valid network address \n", addr);
+    parcMemory_Deallocate(&addPuntingCommand);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  addPuntingCommand->len = len;
+  strcpy(addPuntingCommand->symbolicOrConnid, symbolicOrConnid);
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, ADD_PUNTING, addPuntingCommand, sizeof(add_punting_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlAddPunting.h b/hicn-light/src/config/controlAddPunting.h
new file mode 100755 (executable)
index 0000000..e4d4aac
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 controlAddPunting_h
+#define controlAddPunting_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddPunting_Create(ControlState *state);
+CommandOps *controlAddPunting_HelpCreate(ControlState *state);
+#endif
diff --git a/hicn-light/src/config/controlAddRoute.c b/hicn-light/src/config/controlAddRoute.c
new file mode 100755 (executable)
index 0000000..c5ddab5
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlAddRoute.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlAddRoute_Execute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args);
+static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser,
+                                                  CommandOps *ops,
+                                                  PARCList *args);
+
+static const char *_commandAddRoute = "add route";
+static const char *_commandAddRouteHelp = "help add route";
+
+CommandOps *controlAddRoute_Create(ControlState *state) {
+  return commandOps_Create(state, _commandAddRoute, NULL,
+                           _controlAddRoute_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlAddRoute_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandAddRouteHelp, NULL,
+                           _controlAddRoute_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlAddRoute_HelpExecute(CommandParser *parser,
+                                                  CommandOps *ops,
+                                                  PARCList *args) {
+  printf("commands:\n");
+  printf("   add route <symbolic | connid> <prefix> <cost>\n");
+  printf("\n");
+  printf("   symbolic:  The symbolic name for an exgress\n");
+  printf(
+      "   connid:    The egress connection id (see 'help list connections')\n");
+  printf(
+      "   prefix:    The hicn name as IPv4 or IPv6 address (e.g 1234::0/64)\n");
+  printf("   cost:      positive integer representing cost\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlAddRoute_Execute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 5) {
+    _controlAddRoute_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+  if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+      !utils_IsNumber(symbolicOrConnid)) {
+    printf(
+        "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+        "alpha followed by alphanum;\nconnid must be an integer\n");
+    return CommandReturn_Failure;
+  }
+
+  unsigned cost = atoi(parcList_GetAtIndex(args, 4));
+
+  if (cost == 0) {
+    printf("ERROR: cost must be positive integer, got %u from '%s'\n", cost,
+           (char *)parcList_GetAtIndex(args, 4));
+    return CommandReturn_Failure;
+  }
+
+  const char *prefixStr = parcList_GetAtIndex(args, 3);
+  char addr[strlen(prefixStr) + 1];
+
+  // separate address and len
+  char *slash;
+  uint32_t len = 0;
+  strcpy(addr, prefixStr);
+  slash = strrchr(addr, '/');
+  if (slash != NULL) {
+    len = atoi(slash + 1);
+    *slash = '\0';
+  }
+
+  if (len == 0) {
+    printf("ERROR: a prefix can not be of length 0\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  add_route_command *addRouteCommand =
+      parcMemory_AllocateAndClear(sizeof(add_route_command));
+
+  // check and set IP address
+  if (inet_pton(AF_INET, addr, &addRouteCommand->address.ipv4) == 1) {
+    if (len > 32) {
+      printf("ERROR: exceeded INET mask length, max=32\n");
+      parcMemory_Deallocate(&addRouteCommand);
+      return CommandReturn_Failure;
+    }
+    addRouteCommand->addressType = ADDR_INET;
+  } else if (inet_pton(AF_INET6, addr, &addRouteCommand->address.ipv6) == 1) {
+    if (len > 128) {
+      printf("ERROR: exceeded INET6 mask length, max=128\n");
+      parcMemory_Deallocate(&addRouteCommand);
+      return CommandReturn_Failure;
+    }
+    addRouteCommand->addressType = ADDR_INET6;
+  } else {
+    printf("Error: %s is not a valid network address \n", addr);
+    parcMemory_Deallocate(&addRouteCommand);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  addRouteCommand->len = len;
+  addRouteCommand->cost = (uint16_t)cost;
+  strcpy(addRouteCommand->symbolicOrConnid, symbolicOrConnid);
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, ADD_ROUTE, addRouteCommand,
+                                             sizeof(add_route_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlAddRoute.h b/hicn-light/src/config/controlAddRoute.h
new file mode 100755 (executable)
index 0000000..be0ad13
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_AddRoute.h
+ * @brief Add a static route
+ *
+ * Implements the "add route" node of the CLI tree
+ *
+ */
+
+#ifndef Control_AddRoute_h
+#define Control_AddRoute_h
+
+#include <src/config/controlState.h>
+CommandOps *controlAddRoute_Create(ControlState *state);
+CommandOps *controlAddRoute_HelpCreate(ControlState *state);
+#endif  // Control_AddRoute_h
diff --git a/hicn-light/src/config/controlCache.c b/hicn-light/src/config/controlCache.c
new file mode 100755 (executable)
index 0000000..d7afbfe
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCache.h>
+#include <src/config/controlCacheClear.h>
+#include <src/config/controlCacheServe.h>
+#include <src/config/controlCacheStore.h>
+
+static void _controlCache_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlCache_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args);
+static CommandReturn _controlCache_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops, PARCList *args);
+
+static const char *_commandCache = "cache";
+static const char *_commandCacheHelp = "help cache";
+
+CommandOps *controlCache_Create(ControlState *state) {
+  return commandOps_Create(state, _commandCache, _controlCache_Init,
+                           _controlCache_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCache_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandCacheHelp, NULL,
+                           _controlCache_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlCache_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops,
+                                               PARCList *args) {
+  CommandOps *ops_cache_serve = controlCacheServe_HelpCreate(NULL);
+  CommandOps *ops_cache_store = controlCacheStore_HelpCreate(NULL);
+  CommandOps *ops_cache_clear = controlCacheClear_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_cache_serve->command);
+  printf("   %s\n", ops_cache_store->command);
+  printf("   %s\n", ops_cache_clear->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_cache_serve);
+  commandOps_Destroy(&ops_cache_store);
+  commandOps_Destroy(&ops_cache_clear);
+
+  return CommandReturn_Success;
+}
+
+static void _controlCache_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlCacheServe_HelpCreate(state));
+  controlState_RegisterCommand(state, controlCacheStore_HelpCreate(state));
+  controlState_RegisterCommand(state, controlCacheClear_HelpCreate(state));
+  controlState_RegisterCommand(state, controlCacheServe_Create(state));
+  controlState_RegisterCommand(state, controlCacheStore_Create(state));
+  controlState_RegisterCommand(state, controlCacheClear_Create(state));
+}
+
+static CommandReturn _controlCache_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args) {
+  return _controlCache_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlCache.h b/hicn-light/src/config/controlCache.h
new file mode 100755 (executable)
index 0000000..a3614fc
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 controlCache_h
+#define controlCache_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCache_Create(ControlState *state);
+CommandOps *controlCache_HelpCreate(ControlState *state);
+#endif  // controlCache_h
diff --git a/hicn-light/src/config/controlCacheClear.c b/hicn-light/src/config/controlCacheClear.c
new file mode 100755 (executable)
index 0000000..c5a4e9f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheClear.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheClear_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandCacheClear = "cache clear";
+static const char *_commandCacheClearHelp = "help cache clear";
+
+// ====================================================
+
+CommandOps *controlCacheClear_Create(ControlState *state) {
+  return commandOps_Create(state, _commandCacheClear, NULL,
+                           _controlCacheClear_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheClear_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandCacheClearHelp, NULL,
+                           _controlCacheClear_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheClear_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("cache clear\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheClear_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlCacheClear_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, CACHE_CLEAR, NULL, 0);
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheClear.h b/hicn-light/src/config/controlCacheClear.h
new file mode 100755 (executable)
index 0000000..348ddba
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file controlCacheClear.h
+ * @brief Clear the cache
+ *
+ * Removes all the cached data form the local content store (if available)
+ *
+ */
+
+#ifndef Control_CacheClear_h
+#define Control_CacheClear_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheClear_Create(ControlState *state);
+CommandOps *controlCacheClear_HelpCreate(ControlState *state);
+#endif  // Control_CacheClear_h
diff --git a/hicn-light/src/config/controlCacheServe.c b/hicn-light/src/config/controlCacheServe.c
new file mode 100755 (executable)
index 0000000..85d5980
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheServe.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheServe_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandCacheServe = "cache serve";
+static const char *_commandCacheServeHelp = "help cache serve";
+
+// ====================================================
+
+CommandOps *controlCacheServe_Create(ControlState *state) {
+  return commandOps_Create(state, _commandCacheServe, NULL,
+                           _controlCacheServe_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheServe_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandCacheServeHelp, NULL,
+                           _controlCacheServe_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheServe_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("cache serve [on|off]\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheServe_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlCacheServe_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  bool active;
+  if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+    active = true;
+  } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+    active = false;
+  } else {
+    _controlCacheServe_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  cache_serve_command *cacheServeCommand =
+      parcMemory_AllocateAndClear(sizeof(cache_serve_command));
+  if (active) {
+    cacheServeCommand->activate = ACTIVATE_ON;
+  } else {
+    cacheServeCommand->activate = ACTIVATE_OFF;
+  }
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, CACHE_SERVE, cacheServeCommand, sizeof(cache_serve_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheServe.h b/hicn-light/src/config/controlCacheServe.h
new file mode 100755 (executable)
index 0000000..4bcec51
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_CacheServe_h
+#define Control_CacheServe_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheServe_Create(ControlState *state);
+CommandOps *controlCacheServe_HelpCreate(ControlState *state);
+#endif  // Control_CacheServe_h
diff --git a/hicn-light/src/config/controlCacheStore.c b/hicn-light/src/config/controlCacheStore.c
new file mode 100755 (executable)
index 0000000..3bbb343
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlCacheStore.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlCacheStore_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandCacheStore = "cache store";
+static const char *_commandCacheStoreHelp = "help cache store";
+
+// ====================================================
+
+CommandOps *controlCacheStore_Create(ControlState *state) {
+  return commandOps_Create(state, _commandCacheStore, NULL,
+                           _controlCacheStore_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlCacheStore_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandCacheStoreHelp, NULL,
+                           _controlCacheStore_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlCacheStore_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("cache store [on|off]\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlCacheStore_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlCacheStore_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  bool active;
+  if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+    active = true;
+  } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+    active = false;
+  } else {
+    _controlCacheStore_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  cache_store_command *cacheStoreCommand =
+      parcMemory_AllocateAndClear(sizeof(cache_store_command));
+  if (active) {
+    cacheStoreCommand->activate = ACTIVATE_ON;
+  } else {
+    cacheStoreCommand->activate = ACTIVATE_OFF;
+  }
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, CACHE_STORE, cacheStoreCommand, sizeof(cache_store_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlCacheStore.h b/hicn-light/src/config/controlCacheStore.h
new file mode 100755 (executable)
index 0000000..ef5aca5
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_CacheStore_h
+#define Control_CacheStore_h
+
+#include <src/config/controlState.h>
+CommandOps *controlCacheStore_Create(ControlState *state);
+CommandOps *controlCacheStore_HelpCreate(ControlState *state);
+#endif  // Control_CacheStore_h
diff --git a/hicn-light/src/config/controlList.c b/hicn-light/src/config/controlList.c
new file mode 100755 (executable)
index 0000000..8afaa60
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlList.h>
+#include <src/config/controlListConnections.h>
+//#include <src/config/controlListInterfaces.h>
+#include <src/config/controlListListeners.h>
+#include <src/config/controlListRoutes.h>
+
+static void _controlList_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlList_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args);
+static CommandReturn _controlList_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args);
+
+static const char *_commandList = "list";
+static const char *_commandListHelp = "help list";
+
+CommandOps *controlList_Create(ControlState *state) {
+  return commandOps_Create(state, _commandList, _controlList_Init,
+                           _controlList_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlList_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandListHelp, NULL,
+                           _controlList_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlList_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args) {
+  CommandOps *ops_list_connections = controlListConnections_HelpCreate(NULL);
+  // CommandOps *ops_list_interfaces = controlListInterfaces_HelpCreate(NULL);
+  CommandOps *ops_list_routes = controlListRoutes_HelpCreate(NULL);
+  CommandOps *ops_list_listeners = controlListListeners_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_list_connections->command);
+  // printf("   %s\n", ops_list_interfaces->command);
+  printf("   %s\n", ops_list_routes->command);
+  printf("   %s\n", ops_list_listeners->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_list_connections);
+  // commandOps_Destroy(&ops_list_interfaces);
+  commandOps_Destroy(&ops_list_routes);
+  commandOps_Destroy(&ops_list_listeners);
+
+  return CommandReturn_Success;
+}
+
+static void _controlList_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlListConnections_HelpCreate(state));
+  // controlState_RegisterCommand(state,
+  // controlListInterfaces_HelpCreate(state));
+  controlState_RegisterCommand(state, controlListListeners_HelpCreate(state));
+  controlState_RegisterCommand(state, controlListRoutes_HelpCreate(state));
+  controlState_RegisterCommand(state, controlListConnections_Create(state));
+  // controlState_RegisterCommand(state, controlListInterfaces_Create(state));
+  controlState_RegisterCommand(state, controlListRoutes_Create(state));
+  controlState_RegisterCommand(state, controlListListeners_Create(state));
+}
+
+static CommandReturn _controlList_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args) {
+  return _controlList_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlList.h b/hicn-light/src/config/controlList.h
new file mode 100755 (executable)
index 0000000..5319733
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_List.h
+ * @brief Root node for the "list" commands
+ *
+ * Implements the "list" node of the CLI tree.
+ *
+ */
+
+#ifndef controlList_h
+#define controlList_h
+
+#include <src/config/controlState.h>
+CommandOps *controlList_Create(ControlState *state);
+CommandOps *controlList_HelpCreate(ControlState *state);
+#endif  // controlList_h
diff --git a/hicn-light/src/config/controlListConnections.c b/hicn-light/src/config/controlListConnections.c
new file mode 100755 (executable)
index 0000000..474ddc4
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlListConnections.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListConnections_Execute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args);
+static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser,
+                                                         CommandOps *ops,
+                                                         PARCList *args);
+
+static const char *_commandListConnections = "list connections";
+static const char *_commandListConnectionsHelp = "help list connections";
+const char *connTypeString[6] = {"GRE", "TCP", "UDP", "MCAST", "L2", "HICN"};
+const char *stateString[3] = {"UP", "DOWN", "UNKNOWN"};
+
+CommandOps *controlListConnections_Create(ControlState *state) {
+  return commandOps_Create(state, _commandListConnections, NULL,
+                           _controlListConnections_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListConnections_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandListConnectionsHelp, NULL,
+                           _controlListConnections_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListConnections_HelpExecute(CommandParser *parser,
+                                                         CommandOps *ops,
+                                                         PARCList *args) {
+  printf("list connections: displays a 1-line summary of each connection\n");
+  printf("\n");
+  printf("The columns are:\n");
+  printf("   connection id : an integer index for the connection\n");
+  printf("   state         : UP or DOWN\n");
+  printf(
+      "   local address : the local network address associated with the "
+      "connection\n");
+  printf(
+      "   remote address: the remote network address associated with the "
+      "connection\n");
+  printf(
+      "   protocol      : the network protocol (tcp, udp, gre, mcast, "
+      "ether)\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlListConnections_Execute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlListConnections_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, LIST_CONNECTIONS, NULL, 0);
+  if (!response) {  // get NULL pointer = FAILURE
+    return CommandReturn_Failure;
+  }
+
+  // Process/Print message
+  header_control_message *receivedHeader =
+      (header_control_message *)response[0].iov_base;
+  uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+  char *sourceString = NULL;
+  char *destinationString = NULL;
+
+  // Allocate output to pass to the main function if the call is not interactive
+  char **commandOutputMain = NULL;
+  if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+    commandOutputMain =
+        parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+    for (size_t j = 0; j < receivedHeader->length; j++) {
+      commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+    }
+  }
+
+  // Process/Print payload
+  for (int i = 0; i < receivedHeader->length; i++) {
+    list_connections_command *listConnectionsCommand =
+        (list_connections_command *)(receivedPayload +
+                                     (i * sizeof(list_connections_command)));
+
+    sourceString = utils_CommandAddressToString(
+        listConnectionsCommand->connectionData.ipType,
+        &listConnectionsCommand->connectionData.localIp,
+        &listConnectionsCommand->connectionData.localPort);
+
+    destinationString = utils_CommandAddressToString(
+        listConnectionsCommand->connectionData.ipType,
+        &listConnectionsCommand->connectionData.remoteIp,
+        &listConnectionsCommand->connectionData.remotePort);
+
+    PARCBufferComposer *composer = parcBufferComposer_Create();
+
+    parcBufferComposer_Format(
+        composer, "%5d %4s %s %s %s", listConnectionsCommand->connid,
+        stateString[listConnectionsCommand->state], sourceString,
+        destinationString,
+        connTypeString[listConnectionsCommand->connectionData.connectionType]);
+
+    PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+    char *result = parcBuffer_ToString(tempBuffer);
+    parcBuffer_Release(&tempBuffer);
+
+    if (!controlState_IsInteractive(state)) {
+      strcpy(commandOutputMain[i], result);
+    }
+
+    puts(result);
+    parcMemory_Deallocate((void **)&result);
+    parcBufferComposer_Release(&composer);
+  }
+
+  controlState_SetCommandOutput(state, commandOutputMain);
+
+  // DEALLOCATE
+  parcMemory_Deallocate((void **)&sourceString);
+  parcMemory_Deallocate((void **)&destinationString);
+  parcMemory_Deallocate(&receivedHeader);   // free response[0].iov_base
+  parcMemory_Deallocate(&receivedPayload);  // free response[1].iov_base
+  parcMemory_Deallocate(&response);         // free iovec pointer
+
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListConnections.h b/hicn-light/src/config/controlListConnections.h
new file mode 100755 (executable)
index 0000000..17422c9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_ListConnections.h
+ * @brief List the current connections of hicn-light
+ *
+ * Implements the "list connections" node of the CLI tree
+ *
+ */
+
+#ifndef Control_ListConnections_h
+#define Control_ListConnections_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListConnections_Create(ControlState *state);
+CommandOps *controlListConnections_HelpCreate(ControlState *state);
+#endif  // Control_ListConnections_h
diff --git a/hicn-light/src/config/controlListInterfaces.c b/hicn-light/src/config/controlListInterfaces.c
new file mode 100755 (executable)
index 0000000..20338b5
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlListInterfaces.h>
+
+static CommandReturn _controlListInterfaces_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args);
+
+static const char *_commandListInterfaces = "list interfaces";
+static const char *_commandListInterfacesHelp = "help list interfaces";
+
+// ====================================================
+
+CommandOps *controlListInterfaces_Create(ControlState *state) {
+  return commandOps_Create(state, _commandListInterfaces, NULL,
+                           _controlListInterfaces_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListInterfaces_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandListInterfacesHelp, NULL,
+                           _controlListInterfaces_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListInterfaces_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args) {
+  printf("list interfaces\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlListInterfaces_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlListInterfaces_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  //==========================        NOT IMPLEMENTED
+  //===========================
+
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListInterfaces.h b/hicn-light/src/config/controlListInterfaces.h
new file mode 100755 (executable)
index 0000000..0c0ca95
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_ListInterfaces.h
+ * @brief List the icn-light interfaces
+ *
+ * Implements the "list interfaces" and "help list interfaces" nodes of the
+ * command tree
+ *
+ */
+
+#ifndef Control_ListInterfaces_h
+#define Control_ListInterfaces_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListInterfaces_Create(ControlState *state);
+CommandOps *controlListInterfaces_HelpCreate(ControlState *state);
+#endif  // Control_ListInterfaces_h
diff --git a/hicn-light/src/config/controlListListeners.c b/hicn-light/src/config/controlListListeners.c
new file mode 100755 (executable)
index 0000000..a149051
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlListListeners.h>
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListListeners_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args);
+static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args);
+
+static const char *_commandListListeners = "list listeners";
+static const char *_commandListListenersHelp = "help list listeners";
+static const char *listenerType[5] = {"TCP", "UDP", "ETHER", "LOCAL", "HICN"};
+
+// ====================================================
+
+CommandOps *controlListListeners_Create(ControlState *state) {
+  return commandOps_Create(state, _commandListListeners, NULL,
+                           _controlListListeners_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListListeners_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandListListenersHelp, NULL,
+                           _controlListListeners_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListListeners_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args) {
+  printf("list listeners\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlListListeners_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlListListeners_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, LIST_LISTENERS, NULL, 0);
+  if (!response) {  // get NULL pointer = FAILURE
+    return CommandReturn_Failure;
+  }
+
+  // Process/Print message
+  header_control_message *receivedHeader =
+      (header_control_message *)response[0].iov_base;
+  uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+  // Allocate output to pass to the main function if the call is not interactive
+  char **commandOutputMain = NULL;
+  if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+    commandOutputMain =
+        parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+    for (size_t j = 0; j < receivedHeader->length; j++) {
+      commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+    }
+  }
+
+  char *addrString = NULL;
+  if (receivedHeader->length > 0) {
+    printf("%6.6s %50.70s %s\n", "iface", "address", "type");
+  } else {
+    printf(" --- No entry in the list \n");
+  }
+
+  for (int i = 0; i < receivedHeader->length; i++) {
+    list_listeners_command *listListenersCommand =
+        (list_listeners_command *)(receivedPayload +
+                                   (i * sizeof(list_listeners_command)));
+
+    addrString = utils_CommandAddressToString(listListenersCommand->addressType,
+                                              &listListenersCommand->address,
+                                              &listListenersCommand->port);
+
+    PARCBufferComposer *composer = parcBufferComposer_Create();
+
+    parcBufferComposer_Format(composer, "%6u %50.70s %3s",
+                              listListenersCommand->connid, addrString,
+                              listenerType[listListenersCommand->encapType]);
+
+    PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+    char *result = parcBuffer_ToString(tempBuffer);
+    parcBuffer_Release(&tempBuffer);
+
+    if (!controlState_IsInteractive(state)) {
+      strcpy(commandOutputMain[i], result);
+    }
+
+    puts(result);
+    parcMemory_Deallocate((void **)&result);
+    parcBufferComposer_Release(&composer);
+  }
+
+  controlState_SetCommandOutput(state, commandOutputMain);
+
+  // DEALLOCATE
+  parcMemory_Deallocate((void **)&addrString);
+  parcMemory_Deallocate(&receivedHeader);   // free response[0].iov_base
+  parcMemory_Deallocate(&receivedPayload);  // free response[1].iov_base
+  parcMemory_Deallocate(&response);         // free iovec pointer
+
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListListeners.h b/hicn-light/src/config/controlListListeners.h
new file mode 100755 (executable)
index 0000000..1f34eea
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_ListListeners.h
+ * @brief List the icn-light listeners
+ *
+ * Implements the "list listeners" and "help list listeners" nodes of the
+ * command tree
+ *
+ */
+
+#ifndef Control_ListListeners_h
+#define Control_ListListeners_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListListeners_Create(ControlState *state);
+CommandOps *controlListListeners_HelpCreate(ControlState *state);
+#endif  // Control_ListListeners_h
diff --git a/hicn-light/src/config/controlListRoutes.c b/hicn-light/src/config/controlListRoutes.c
new file mode 100755 (executable)
index 0000000..4a21b5e
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Time.h>
+
+#include <src/config/controlListRoutes.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlListRoutes_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandListRoutes = "list routes";
+static const char *_commandListRoutesHelp = "help list routes";
+
+// ====================================================
+
+CommandOps *controlListRoutes_Create(ControlState *state) {
+  return commandOps_Create(state, _commandListRoutes, NULL,
+                           _controlListRoutes_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlListRoutes_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandListRoutesHelp, NULL,
+                           _controlListRoutes_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlListRoutes_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("command: list routes\n");
+  printf("\n");
+  printf(
+      "This command will fetch the prefix routing table.  For each route, it "
+      "will list:\n");
+  printf("   iface:    interface\n");
+  printf(
+      "   protocol: the routing protocol, such as STATIC, CONNECTED, etc.\n");
+  printf(
+      "   type:     LMP or EXACT (longest matching prefix or exact match)\n");
+  printf("   cost:     The route cost, lower being preferred\n");
+  printf("   next:     List of next hops by interface id\n");
+  printf("   prefix:   name prefix\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlListRoutes_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlListRoutes_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, LIST_ROUTES, NULL, 0);
+  if (!response) {  // get NULL pointer = FAILURE
+    return CommandReturn_Failure;
+  }
+
+  // Process/Print message
+  header_control_message *receivedHeader =
+      (header_control_message *)response[0].iov_base;
+  uint8_t *receivedPayload = (uint8_t *)response[1].iov_base;
+
+  // Allocate output to pass to the main function if the call is not interactive
+  char **commandOutputMain = NULL;
+  if (!controlState_IsInteractive(state) && receivedHeader->length > 0) {
+    commandOutputMain =
+        parcMemory_Allocate(sizeof(char *) * receivedHeader->length);
+    for (size_t j = 0; j < receivedHeader->length; j++) {
+      commandOutputMain[j] = parcMemory_Allocate(sizeof(char) * 128);
+    }
+  }
+
+  char *addrString = NULL;
+  in_port_t port = htons(1234);  // this is a random port number that is ignored
+
+  if (receivedHeader->length > 0) {
+    printf("%6.6s %8.8s %70.70s %s\n", "iface", "cost", "prefix", "len");
+  } else {
+    printf(" --- No entry in the list \n");
+  }
+
+  for (int i = 0; i < receivedHeader->length; i++) {
+    list_routes_command *listRoutesCommand =
+        (list_routes_command *)(receivedPayload +
+                                (i * sizeof(list_routes_command)));
+
+    addrString = utils_CommandAddressToString(
+        listRoutesCommand->addressType, &listRoutesCommand->address, &port);
+
+    PARCBufferComposer *composer = parcBufferComposer_Create();
+
+    parcBufferComposer_Format(
+        composer, "%6u %8u %70.70s %3d", listRoutesCommand->connid,
+        listRoutesCommand->cost, addrString, listRoutesCommand->len);
+
+    PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+    char *result = parcBuffer_ToString(tempBuffer);
+    parcBuffer_Release(&tempBuffer);
+
+    if (!controlState_IsInteractive(state)) {
+      strcpy(commandOutputMain[i], result);
+    }
+
+    puts(result);
+    parcMemory_Deallocate((void **)&result);
+    parcBufferComposer_Release(&composer);
+  }
+
+  controlState_SetCommandOutput(state, commandOutputMain);
+
+  // DEALLOCATE
+  parcMemory_Deallocate((void **)&addrString);
+  parcMemory_Deallocate(&receivedHeader);   // free response[0].iov_base
+  parcMemory_Deallocate(&receivedPayload);  // free response[1].iov_base
+  parcMemory_Deallocate(&response);         // free iovec pointer
+
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlListRoutes.h b/hicn-light/src/config/controlListRoutes.h
new file mode 100755 (executable)
index 0000000..018c88a
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_ListRoutes.h
+ * @brief List the icn-light routes
+ *
+ * Implements the "list routes" and "help list routes" nodes of the command tree
+ *
+ */
+#ifndef Control_ListRoutes_h
+#define Control_ListRoutes_h
+
+#include <src/config/controlState.h>
+CommandOps *controlListRoutes_Create(ControlState *state);
+CommandOps *controlListRoutes_HelpCreate(ControlState *state);
+#endif  // Control_ListRoutes_h
diff --git a/hicn-light/src/config/controlMapMe.c b/hicn-light/src/config/controlMapMe.c
new file mode 100755 (executable)
index 0000000..2253f52
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlMapMe.h>
+#include <src/config/controlMapMeDiscovery.h>
+#include <src/config/controlMapMeEnable.h>
+#include <src/config/controlMapMeRetx.h>
+#include <src/config/controlMapMeTimescale.h>
+
+static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlMapMe_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args);
+static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops, PARCList *args);
+
+static const char *_commandMapMe = "mapme";
+static const char *_commandMapMeHelp = "help mapme";
+
+CommandOps *controlMapMe_Create(ControlState *state) {
+  return commandOps_Create(state, _commandMapMe, _controlMapMe_Init,
+                           _controlMapMe_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMe_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeHelp, NULL,
+                           _controlMapMe_HelpExecute, commandOps_Destroy);
+}
+
+// =====================================================
+
+static CommandReturn _controlMapMe_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops,
+                                               PARCList *args) {
+  CommandOps *ops_mapme_enable = controlMapMeEnable_HelpCreate(NULL);
+  CommandOps *ops_mapme_discovery = controlMapMeDiscovery_HelpCreate(NULL);
+  CommandOps *ops_mapme_timescale = controlMapMeTimescale_HelpCreate(NULL);
+  CommandOps *ops_mapme_retx = controlMapMeRetx_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_mapme_enable->command);
+  printf("   %s\n", ops_mapme_discovery->command);
+  printf("   %s\n", ops_mapme_timescale->command);
+  printf("   %s\n", ops_mapme_retx->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_mapme_enable);
+  commandOps_Destroy(&ops_mapme_discovery);
+  commandOps_Destroy(&ops_mapme_timescale);
+  commandOps_Destroy(&ops_mapme_retx);
+
+  return CommandReturn_Success;
+}
+
+static void _controlMapMe_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlMapMeEnable_HelpCreate(state));
+  controlState_RegisterCommand(state, controlMapMeDiscovery_HelpCreate(state));
+  controlState_RegisterCommand(state, controlMapMeTimescale_HelpCreate(state));
+  controlState_RegisterCommand(state, controlMapMeRetx_HelpCreate(state));
+  controlState_RegisterCommand(state, controlMapMeEnable_Create(state));
+  controlState_RegisterCommand(state, controlMapMeDiscovery_Create(state));
+  controlState_RegisterCommand(state, controlMapMeTimescale_Create(state));
+  controlState_RegisterCommand(state, controlMapMeRetx_Create(state));
+}
+
+static CommandReturn _controlMapMe_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args) {
+  return _controlMapMe_HelpExecute(parser, ops, args);
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlMapMe.h b/hicn-light/src/config/controlMapMe.h
new file mode 100755 (executable)
index 0000000..d9cfdb8
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 controlMapMe_h
+#define controlMapMe_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMe_Create(ControlState *state);
+CommandOps *controlMapMe_HelpCreate(ControlState *state);
+#endif  // controlMapMe_h
diff --git a/hicn-light/src/config/controlMapMeDiscovery.c b/hicn-light/src/config/controlMapMeDiscovery.c
new file mode 100755 (executable)
index 0000000..f8f4bf0
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeDiscovery.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args);
+
+static const char *_commandMapMeDiscovery = "mapme discovery";
+static const char *_commandMapMeDiscoveryHelp = "help mapme discovery";
+
+// ====================================================
+
+CommandOps *controlMapMeDiscovery_Create(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeDiscovery, NULL,
+                           _controlMapMeDiscovery_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeDiscoveryHelp, NULL,
+                           _controlMapMeDiscovery_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeDiscovery_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args) {
+  printf("mapme discovery [on|off]\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeDiscovery_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlMapMeDiscovery_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  bool active;
+  if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+    active = true;
+  } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+    active = false;
+  } else {
+    _controlMapMeDiscovery_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  mapme_activator_command *mapmeDiscoveryCommand =
+      parcMemory_AllocateAndClear(sizeof(mapme_activator_command));
+  if (active) {
+    mapmeDiscoveryCommand->activate = ACTIVATE_ON;
+  } else {
+    mapmeDiscoveryCommand->activate = ACTIVATE_OFF;
+  }
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response =
+      utils_SendRequest(state, MAPME_DISCOVERY, mapmeDiscoveryCommand,
+                        sizeof(mapme_activator_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeDiscovery.h b/hicn-light/src/config/controlMapMeDiscovery.h
new file mode 100755 (executable)
index 0000000..c492fa0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_MapMeDiscovery_h
+#define Control_MapMeDiscovery_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeDiscovery_Create(ControlState *state);
+CommandOps *controlMapMeDiscovery_HelpCreate(ControlState *state);
+#endif  // Control_MapMeDiscovery_h
diff --git a/hicn-light/src/config/controlMapMeEnable.c b/hicn-light/src/config/controlMapMeEnable.c
new file mode 100755 (executable)
index 0000000..db77450
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeEnable.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args);
+static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args);
+
+static const char *_commandMapMeEnable = "mapme enable";
+static const char *_commandMapMeEnableHelp = "help mapme enable";
+
+// ====================================================
+
+CommandOps *controlMapMeEnable_Create(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeEnable, NULL,
+                           _controlMapMeEnable_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeEnable_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeEnableHelp, NULL,
+                           _controlMapMeEnable_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeEnable_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args) {
+  printf("mapme enable [on|off]\n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeEnable_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlMapMeEnable_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  bool active;
+  if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+    active = true;
+  } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+    active = false;
+  } else {
+    _controlMapMeEnable_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  mapme_activator_command *mapmeEnableCommand =
+      parcMemory_AllocateAndClear(sizeof(mapme_activator_command));
+  if (active) {
+    mapmeEnableCommand->activate = ACTIVATE_ON;
+  } else {
+    mapmeEnableCommand->activate = ACTIVATE_OFF;
+  }
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, MAPME_ENABLE, mapmeEnableCommand, sizeof(mapme_activator_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeEnable.h b/hicn-light/src/config/controlMapMeEnable.h
new file mode 100755 (executable)
index 0000000..f7ca620
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_MapMeEnable_h
+#define Control_MapMeEnable_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeEnable_Create(ControlState *state);
+CommandOps *controlMapMeEnable_HelpCreate(ControlState *state);
+#endif  // Control_MapMeEnable_h
diff --git a/hicn-light/src/config/controlMapMeRetx.c b/hicn-light/src/config/controlMapMeRetx.c
new file mode 100755 (executable)
index 0000000..bb16b88
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeRetx.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser,
+                                               CommandOps *ops, PARCList *args);
+static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args);
+
+static const char *_commandMapMeRetx = "mapme retx";
+static const char *_commandMapMeRetxHelp = "help mapme retx";
+
+// ====================================================
+
+CommandOps *controlMapMeRetx_Create(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeRetx, NULL,
+                           _controlMapMeRetx_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeRetx_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeRetxHelp, NULL,
+                           _controlMapMeRetx_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeRetx_HelpExecute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args) {
+  printf("mapme retx <milliseconds>n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeRetx_Execute(CommandParser *parser,
+                                               CommandOps *ops,
+                                               PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlMapMeRetx_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *rtx = parcList_GetAtIndex(args, 2);
+  if (!utils_IsNumber(rtx)) {
+    printf(
+        "ERROR: retransmission value (expressed in ms) must be a positive "
+        "integer \n");
+    return CommandReturn_Failure;
+  }
+
+  mapme_timing_command *mapmeRetxCommand =
+      parcMemory_AllocateAndClear(sizeof(mapme_timing_command));
+  mapmeRetxCommand->timePeriod = (unsigned)strtold(rtx, NULL);
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, MAPME_RETX, mapmeRetxCommand, sizeof(mapme_timing_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeRetx.h b/hicn-light/src/config/controlMapMeRetx.h
new file mode 100755 (executable)
index 0000000..611bd36
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_MapMeRetx_h
+#define Control_MapMeRetx_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeRetx_Create(ControlState *state);
+CommandOps *controlMapMeRetx_HelpCreate(ControlState *state);
+#endif  // Control_MapMeRetx_h
diff --git a/hicn-light/src/config/controlMapMeTimescale.c b/hicn-light/src/config/controlMapMeTimescale.c
new file mode 100755 (executable)
index 0000000..9303b4b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config/controlMapMeTimescale.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args);
+
+static const char *_commandMapMeTimescale = "mapme timescale";
+static const char *_commandMapMeTimescaleHelp = "help mapme timescale";
+
+// ====================================================
+
+CommandOps *controlMapMeTimescale_Create(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeTimescale, NULL,
+                           _controlMapMeTimescale_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandMapMeTimescaleHelp, NULL,
+                           _controlMapMeTimescale_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlMapMeTimescale_HelpExecute(CommandParser *parser,
+                                                        CommandOps *ops,
+                                                        PARCList *args) {
+  printf("mapme timescale <milliseconds>n");
+  printf("\n");
+
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlMapMeTimescale_Execute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  if (parcList_Size(args) != 3) {
+    _controlMapMeTimescale_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *ts = parcList_GetAtIndex(args, 2);
+  if (!utils_IsNumber(ts)) {
+    printf(
+        "ERROR: timescale value (expressed in ms) must be a positive integer "
+        "\n");
+    return CommandReturn_Failure;
+  }
+
+  mapme_timing_command *mapmeTimescaleCommand =
+      parcMemory_AllocateAndClear(sizeof(mapme_timing_command));
+  mapmeTimescaleCommand->timePeriod = (unsigned)strtold(ts, NULL);
+
+  ControlState *state = ops->closure;
+  // send message and receive response
+  struct iovec *response =
+      utils_SendRequest(state, MAPME_TIMESCALE, mapmeTimescaleCommand,
+                        sizeof(mapme_timing_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlMapMeTimescale.h b/hicn-light/src/config/controlMapMeTimescale.h
new file mode 100755 (executable)
index 0000000..d4b3836
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_MapMeTimescale_h
+#define Control_MapMeTimescale_h
+
+#include <src/config/controlState.h>
+CommandOps *controlMapMeTimescale_Create(ControlState *state);
+CommandOps *controlMapMeTimescale_HelpCreate(ControlState *state);
+#endif  // Control_MapMeTimescale_h
diff --git a/hicn-light/src/config/controlQuit.c b/hicn-light/src/config/controlQuit.c
new file mode 100755 (executable)
index 0000000..635fe27
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlQuit.h>
+
+static CommandReturn _controlQuit_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args);
+static CommandReturn _controlQuit_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args);
+
+static const char *_commandQuit = "quit";
+static const char *_commandQuitHelp = "help quit";
+
+// ====================================================
+
+CommandOps *controlQuit_Create(ControlState *state) {
+  return commandOps_Create(state, _commandQuit, NULL, _controlQuit_Execute,
+                           commandOps_Destroy);
+}
+
+CommandOps *controlQuit_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandQuitHelp, NULL,
+                           _controlQuit_HelpExecute, commandOps_Destroy);
+}
+
+// ==============================================
+
+static CommandReturn _controlQuit_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args) {
+  printf("Exits the interactive control program\n\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlQuit_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args) {
+  printf("exiting interactive shell\n");
+  return CommandReturn_Exit;
+}
diff --git a/hicn-light/src/config/controlQuit.h b/hicn-light/src/config/controlQuit.h
new file mode 100755 (executable)
index 0000000..e2ba354
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Quit.h
+ * @brief The quit command
+ *
+ * Implements the "quit" and "help quit" nodes of the command tree
+ *
+ */
+#ifndef Control_Quit_h
+#define Control_Quit_h
+
+#include <src/config/controlState.h>
+CommandOps *controlQuit_Create(ControlState *state);
+CommandOps *controlQuit_HelpCreate(ControlState *state);
+#endif  // Control_Quit_h
diff --git a/hicn-light/src/config/controlRemove.c b/hicn-light/src/config/controlRemove.c
new file mode 100755 (executable)
index 0000000..ede075a
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlRemove.h>
+#include <src/config/controlRemoveConnection.h>
+#include <src/config/controlRemovePunting.h>
+#include <src/config/controlRemoveRoute.h>
+
+static void _controlRemove_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlRemove_Execute(CommandParser *parser,
+                                            CommandOps *ops, PARCList *args);
+static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+
+static const char *_commandRemove = "remove";
+static const char *_commandRemoveHelp = "help remove";
+
+// ====================================================
+
+CommandOps *controlRemove_Create(ControlState *state) {
+  return commandOps_Create(state, _commandRemove, _controlRemove_Init,
+                           _controlRemove_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemove_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandRemoveHelp, NULL,
+                           _controlRemove_HelpExecute, commandOps_Destroy);
+}
+
+// ==============================================
+
+static CommandReturn _controlRemove_HelpExecute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  CommandOps *ops_remove_connection = controlRemoveConnection_Create(NULL);
+  CommandOps *ops_remove_route = controlRemoveRoute_Create(NULL);
+  CommandOps *ops_remove_punting = controlRemovePunting_Create(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_remove_connection->command);
+  printf("   %s\n", ops_remove_route->command);
+  printf("   %s\n", ops_remove_punting->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_remove_connection);
+  commandOps_Destroy(&ops_remove_route);
+  commandOps_Destroy(&ops_remove_punting);
+  return CommandReturn_Success;
+}
+
+static void _controlRemove_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state,
+                               controlRemoveConnection_HelpCreate(state));
+  controlState_RegisterCommand(state, controlRemoveRoute_HelpCreate(state));
+  controlState_RegisterCommand(state, controlRemoveConnection_Create(state));
+  controlState_RegisterCommand(state, controlRemoveRoute_Create(state));
+  controlState_RegisterCommand(state, controlRemovePunting_Create(state));
+  controlState_RegisterCommand(state, controlRemovePunting_HelpCreate(state));
+}
+
+static CommandReturn _controlRemove_Execute(CommandParser *parser,
+                                            CommandOps *ops, PARCList *args) {
+  return _controlRemove_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlRemove.h b/hicn-light/src/config/controlRemove.h
new file mode 100755 (executable)
index 0000000..d75ecfe
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Remove.h
+ * @brief Implements the remove node of the CLI tree
+ *
+ * Implements the "remove" and "help remove" nodes of the command tree
+ *
+ */
+#ifndef controlRemove_h
+#define controlRemove_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemove_Create(ControlState *state);
+CommandOps *controlRemove_HelpCreate(ControlState *state);
+#endif  // controlRemove_h
diff --git a/hicn-light/src/config/controlRemoveConnection.c b/hicn-light/src/config/controlRemoveConnection.c
new file mode 100755 (executable)
index 0000000..93365ad
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/address.h>
+
+#include <src/config/controlRemoveConnection.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args);
+static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemoveConnection = "remove connection";
+static const char *_commandRemoveConnectionHelp = "help remove connection";
+
+// ====================================================
+
+CommandOps *controlRemoveConnection_Create(ControlState *state) {
+  return commandOps_Create(state, _commandRemoveConnection, NULL,
+                           _controlRemoveConnection_Execute,
+                           commandOps_Destroy);
+}
+
+CommandOps *controlRemoveConnection_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandRemoveConnectionHelp, NULL,
+                           _controlRemoveConnection_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlRemoveConnection_HelpExecute(CommandParser *parser,
+                                                          CommandOps *ops,
+                                                          PARCList *args) {
+  printf("command:\n");
+  printf("    remove connection <symbolic|id>\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemoveConnection_Execute(CommandParser *parser,
+                                                      CommandOps *ops,
+                                                      PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 3) {
+    _controlRemoveConnection_HelpExecute(parser, ops, args);
+    return false;
+  }
+
+  if ((strcmp(parcList_GetAtIndex(args, 0), "remove") != 0) ||
+      (strcmp(parcList_GetAtIndex(args, 1), "connection") != 0)) {
+    _controlRemoveConnection_HelpExecute(parser, ops, args);
+    return false;
+  }
+
+  const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+  if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+      !utils_IsNumber(symbolicOrConnid)) {
+    printf(
+        "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+        "alpha followed by alphanum;\nconnid must be an integer\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  remove_connection_command *removeConnectionCommand =
+      parcMemory_AllocateAndClear(sizeof(remove_connection_command));
+  // fill payload
+  strcpy(removeConnectionCommand->symbolicOrConnid, symbolicOrConnid);
+
+  // send message and receive response
+  struct iovec *response =
+      utils_SendRequest(state, REMOVE_CONNECTION, removeConnectionCommand,
+                        sizeof(remove_connection_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlRemoveConnection.h b/hicn-light/src/config/controlRemoveConnection.h
new file mode 100755 (executable)
index 0000000..1dd1af2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_RemoveConnection.h
+ * @brief Remove a connection from the connection table
+ *
+ * Implements the "remove connection" and "help remove connection" nodes of the
+ * CLI tree
+ *
+ */
+
+#ifndef Control_RemoveConnection_h
+#define Control_RemoveConnection_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemoveConnection_Create(ControlState *state);
+CommandOps *controlRemoveConnection_HelpCreate(ControlState *state);
+#endif  // Control_RemoveConnection_h
diff --git a/hicn-light/src/config/controlRemovePunting.c b/hicn-light/src/config/controlRemovePunting.c
new file mode 100755 (executable)
index 0000000..cf4c4fb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <src/utils/address.h>
+
+#include <src/config/controlRemovePunting.h>
+
+static CommandReturn _controlRemovePunting_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args);
+static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemovePunting = "remove punting";
+static const char *_commandRemovePuntingHelp = "help punting connection";
+
+// ====================================================
+
+CommandOps *controlRemovePunting_Create(ControlState *state) {
+  return commandOps_Create(state, _commandRemovePunting, NULL,
+                           _controlRemovePunting_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemovePunting_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandRemovePuntingHelp, NULL,
+                           _controlRemovePunting_HelpExecute,
+                           commandOps_Destroy);
+}
+
+// ====================================================
+
+// ====================================================
+
+static CommandReturn _controlRemovePunting_HelpExecute(CommandParser *parser,
+                                                       CommandOps *ops,
+                                                       PARCList *args) {
+  printf("remove punting <symbolic> <prefix>\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemovePunting_Execute(CommandParser *parser,
+                                                   CommandOps *ops,
+                                                   PARCList *args) {
+  printf("command not implemented\n");
+  return _controlRemovePunting_HelpExecute(parser, ops, args);
+}
+
+// ==================================================
diff --git a/hicn-light/src/config/controlRemovePunting.h b/hicn-light/src/config/controlRemovePunting.h
new file mode 100755 (executable)
index 0000000..89b1343
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_RemovePunting.h
+ *
+ */
+
+#ifndef Control_RemovePunting_h
+#define Control_RemovePunting_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemovePunting_Create(ControlState *state);
+CommandOps *controlRemovePunting_HelpCreate(ControlState *state);
+#endif  // Control_RemovePunting_h
diff --git a/hicn-light/src/config/controlRemoveRoute.c b/hicn-light/src/config/controlRemoveRoute.c
new file mode 100755 (executable)
index 0000000..b9b4ed1
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/utils/address.h>
+
+#include <src/config/controlRemoveRoute.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args);
+static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args);
+
+// ===================================================
+
+static const char *_commandRemoveRoute = "remove route";
+static const char *_commandRemoveRouteHelp = "help remove route";
+
+// ====================================================
+
+CommandOps *controlRemoveRoute_Create(ControlState *state) {
+  return commandOps_Create(state, _commandRemoveRoute, NULL,
+                           _controlRemoveRoute_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRemoveRoute_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandRemoveRouteHelp, NULL,
+                           _controlRemoveRoute_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlRemoveRoute_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args) {
+  printf("commands:\n");
+  printf("    remove route <symbolic | connid> <prefix>\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlRemoveRoute_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 4) {
+    _controlRemoveRoute_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *symbolicOrConnid = parcList_GetAtIndex(args, 2);
+
+  if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+      !utils_IsNumber(symbolicOrConnid)) {
+    printf(
+        "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+        "alpha followed by alphanum;\nconnid must be an integer\n");
+    return CommandReturn_Failure;
+  }
+
+  const char *prefixStr = parcList_GetAtIndex(args, 3);
+  char addr[strlen(prefixStr) + 1];
+
+  // separate address and len
+  char *slash;
+  uint32_t len = 0;
+  strcpy(addr, prefixStr);
+  slash = strrchr(addr, '/');
+  if (slash != NULL) {
+    len = atoi(slash + 1);
+    *slash = '\0';
+  }
+
+  if (len == 0) {
+    printf("ERROR: a prefix can not be of length 0\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  remove_route_command *removeRouteCommand =
+      parcMemory_AllocateAndClear(sizeof(remove_route_command));
+
+  // check and set IP address
+  if (inet_pton(AF_INET, addr, &removeRouteCommand->address.ipv4) == 1) {
+    if (len > 32) {
+      printf("ERROR: exceeded INET mask length, max=32\n");
+      parcMemory_Deallocate(&removeRouteCommand);
+      return CommandReturn_Failure;
+    }
+    removeRouteCommand->addressType = ADDR_INET;
+  } else if (inet_pton(AF_INET6, addr, &removeRouteCommand->address.ipv6) ==
+             1) {
+    if (len > 128) {
+      printf("ERROR: exceeded INET6 mask length, max=128\n");
+      parcMemory_Deallocate(&removeRouteCommand);
+      return CommandReturn_Failure;
+    }
+    removeRouteCommand->addressType = ADDR_INET6;
+  } else {
+    printf("Error: %s is not a valid network address \n", addr);
+    parcMemory_Deallocate(&removeRouteCommand);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  removeRouteCommand->len = len;
+  strcpy(removeRouteCommand->symbolicOrConnid, symbolicOrConnid);
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, REMOVE_ROUTE, removeRouteCommand, sizeof(remove_route_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlRemoveRoute.h b/hicn-light/src/config/controlRemoveRoute.h
new file mode 100755 (executable)
index 0000000..a3c0ee4
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_RemoveRoute.h
+ * @brief Remove a route from the FIB
+ *
+ * Implements the "remove route" and "help remove route" nodes of the command
+ * tree
+ *
+ */
+
+#ifndef Control_RemoveRoute_h
+#define Control_RemoveRoute_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRemoveRoute_Create(ControlState *state);
+CommandOps *controlRemoveRoute_HelpCreate(ControlState *state);
+#endif  // Control_RemoveRoute_h
diff --git a/hicn-light/src/config/controlRoot.c b/hicn-light/src/config/controlRoot.c
new file mode 100755 (executable)
index 0000000..5d6c5f9
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/config/controlAdd.h>
+#include <src/config/controlCache.h>
+#include <src/config/controlList.h>
+#include <src/config/controlMapMe.h>
+#include <src/config/controlQuit.h>
+#include <src/config/controlRemove.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlSet.h>
+#include <src/config/controlUnset.h>
+
+static void _controlRoot_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlRoot_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args);
+static CommandReturn _controlRoot_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args);
+
+static const char *_commandRoot = "";
+static const char *_commandRootHelp = "help";
+
+// ====================================================
+
+CommandOps *controlRoot_Create(ControlState *state) {
+  return commandOps_Create(state, _commandRoot, _controlRoot_Init,
+                           _controlRoot_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlRoot_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandRootHelp, NULL,
+                           _controlRoot_HelpExecute, commandOps_Destroy);
+}
+
+// ===================================================
+
+static CommandReturn _controlRoot_HelpExecute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args) {
+  printf("Command-line execution:\n");
+  printf(
+      "   controller [--keystore <keystorepath>] [--password <password>] "
+      "command\n");
+  printf("\n");
+  printf("Interactive execution:\n");
+  printf("   controller [--keystore <keystorepath>] [--password <password>]\n");
+  printf("\n");
+  printf(
+      "If the keystore is not specified, the default path is used. Keystore "
+      "must exist prior to running program.\n");
+  printf("If the password is not specified, the user will be prompted.\n");
+  printf("\n");
+
+  CommandOps *ops_help_add = controlAdd_CreateHelp(NULL);
+  CommandOps *ops_help_list = controlList_HelpCreate(NULL);
+  CommandOps *ops_help_quit = controlQuit_HelpCreate(NULL);
+  CommandOps *ops_help_remove = controlRemove_HelpCreate(NULL);
+  CommandOps *ops_help_set = controlSet_HelpCreate(NULL);
+  CommandOps *ops_help_unset = controlUnset_HelpCreate(NULL);
+  CommandOps *ops_help_cache = controlCache_HelpCreate(NULL);
+  CommandOps *ops_help_mapme = controlMapMe_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_help_add->command);
+  printf("   %s\n", ops_help_list->command);
+  printf("   %s\n", ops_help_quit->command);
+  printf("   %s\n", ops_help_remove->command);
+  printf("   %s\n", ops_help_set->command);
+  printf("   %s\n", ops_help_unset->command);
+  printf("   %s\n", ops_help_cache->command);
+  printf("   %s\n", ops_help_mapme->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_help_add);
+  commandOps_Destroy(&ops_help_list);
+  commandOps_Destroy(&ops_help_quit);
+  commandOps_Destroy(&ops_help_remove);
+  commandOps_Destroy(&ops_help_set);
+  commandOps_Destroy(&ops_help_unset);
+  commandOps_Destroy(&ops_help_cache);
+  commandOps_Destroy(&ops_help_mapme);
+
+  return CommandReturn_Success;
+}
+
+static void _controlRoot_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+
+  controlState_RegisterCommand(state, controlAdd_CreateHelp(state));
+  controlState_RegisterCommand(state, controlList_HelpCreate(state));
+  controlState_RegisterCommand(state, controlQuit_HelpCreate(state));
+  controlState_RegisterCommand(state, controlRemove_HelpCreate(state));
+  controlState_RegisterCommand(state, controlSet_HelpCreate(state));
+  controlState_RegisterCommand(state, controlUnset_HelpCreate(state));
+  controlState_RegisterCommand(state, controlCache_HelpCreate(state));
+  controlState_RegisterCommand(state, controlMapMe_HelpCreate(state));
+
+  controlState_RegisterCommand(state, webControlAdd_Create(state));
+  controlState_RegisterCommand(state, controlList_Create(state));
+  controlState_RegisterCommand(state, controlQuit_Create(state));
+  controlState_RegisterCommand(state, controlRemove_Create(state));
+  controlState_RegisterCommand(state, controlSet_Create(state));
+  controlState_RegisterCommand(state, controlUnset_Create(state));
+  controlState_RegisterCommand(state, controlCache_Create(state));
+  controlState_RegisterCommand(state, controlMapMe_Create(state));
+}
+
+static CommandReturn _controlRoot_Execute(CommandParser *parser,
+                                          CommandOps *ops, PARCList *args) {
+  return CommandReturn_Success;
+}
+
+// ======================================================================
diff --git a/hicn-light/src/config/controlRoot.h b/hicn-light/src/config/controlRoot.h
new file mode 100755 (executable)
index 0000000..a62126e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Root.h
+ * @brief Root of the command tree
+ *
+ * Implements the root of the command tree.  This is the one module that
+ * needs to be seeded to the control state to build the whole tree.
+ *
+ */
+
+#ifndef Control_Root_h
+#define Control_Root_h
+
+#include <src/config/controlState.h>
+CommandOps *controlRoot_Create(ControlState *state);
+CommandOps *controlRoot_HelpCreate(ControlState *state);
+#endif  // Control_Root_h
diff --git a/hicn-light/src/config/controlSet.c b/hicn-light/src/config/controlSet.c
new file mode 100755 (executable)
index 0000000..c6fd9aa
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlSet.h>
+#include <src/config/controlSetDebug.h>
+#include <src/config/controlSetStrategy.h>
+#include <src/config/controlSetWldr.h>
+
+static void _controlSet_Init(CommandParser *parser, CommandOps *ops);
+static CommandReturn _controlSet_Execute(CommandParser *parser, CommandOps *ops,
+                                         PARCList *args);
+static CommandReturn _controlSet_HelpExecute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args);
+
+static const char *_commandSet = "set";
+static const char *_commandSetHelp = "help set";
+
+// ===========================================================
+
+CommandOps *controlSet_Create(ControlState *state) {
+  return commandOps_Create(state, _commandSet, _controlSet_Init,
+                           _controlSet_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSet_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandSetHelp, NULL,
+                           _controlSet_HelpExecute, commandOps_Destroy);
+}
+
+// ===========================================================
+
+static void _controlSet_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlSetDebug_Create(state));
+  controlState_RegisterCommand(state, controlSetDebug_HelpCreate(state));
+  controlState_RegisterCommand(state, controlSetStrategy_Create(state));
+  controlState_RegisterCommand(state, controlSetStrategy_HelpCreate(state));
+  controlState_RegisterCommand(state, controlSetWldr_Create(state));
+  controlState_RegisterCommand(state, controlSetWldr_HelpCreate(state));
+}
+
+static CommandReturn _controlSet_HelpExecute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args) {
+  CommandOps *ops_help_set_debug = controlSetDebug_HelpCreate(NULL);
+  CommandOps *ops_help_set_strategy = controlSetStrategy_HelpCreate(NULL);
+  CommandOps *ops_help_set_wldr = controlSetWldr_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_help_set_debug->command);
+  printf("   %s\n", ops_help_set_strategy->command);
+  printf("   %s\n", ops_help_set_wldr->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_help_set_debug);
+  commandOps_Destroy(&ops_help_set_strategy);
+  commandOps_Destroy(&ops_help_set_wldr);
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlSet_Execute(CommandParser *parser, CommandOps *ops,
+                                         PARCList *args) {
+  return _controlSet_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlSet.h b/hicn-light/src/config/controlSet.h
new file mode 100755 (executable)
index 0000000..4289aad
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Set.h
+ * @brief Implements the set node of the CLI tree
+ *
+ * Implements the "set" and "help set" nodes of the command tree
+ *
+ */
+#ifndef Control_Set_h
+#define Control_Set_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSet_Create(ControlState *state);
+CommandOps *controlSet_HelpCreate(ControlState *state);
+#endif  // Control_Set_h
diff --git a/hicn-light/src/config/controlSetDebug.c b/hicn-light/src/config/controlSetDebug.c
new file mode 100755 (executable)
index 0000000..ca43242
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static CommandReturn _controlSetDebug_Execute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args);
+static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser,
+                                                  CommandOps *ops,
+                                                  PARCList *args);
+
+static const char *_commandSetDebug = "set debug";
+static const char *_commandSetDebugHelp = "help set debug";
+
+// ====================================================
+
+CommandOps *controlSetDebug_Create(ControlState *state) {
+  return commandOps_Create(state, _commandSetDebug, NULL,
+                           _controlSetDebug_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetDebug_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandSetDebugHelp, NULL,
+                           _controlSetDebug_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlSetDebug_HelpExecute(CommandParser *parser,
+                                                  CommandOps *ops,
+                                                  PARCList *args) {
+  printf("set debug: will enable the debug flag for more verbose output\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetDebug_Execute(CommandParser *parser,
+                                              CommandOps *ops, PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlSetDebug_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+  controlState_SetDebug(state, true);
+  printf("Debug flag set\n\n");
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetDebug.h b/hicn-light/src/config/controlSetDebug.h
new file mode 100755 (executable)
index 0000000..5335ebc
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_SetDebug.h
+ * @brief Sets the debug flag for more verbose output
+ *
+ * Implements the "set debug" and "help set debug" nodes of the command tree
+ *
+ */
+
+#ifndef Control_SetDebug_h
+#define Control_SetDebug_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetDebug_Create(ControlState *state);
+CommandOps *controlSetDebug_HelpCreate(ControlState *state);
+#endif  // Control_SetDebug_h
diff --git a/hicn-light/src/config/controlSetStrategy.c b/hicn-light/src/config/controlSetStrategy.c
new file mode 100755 (executable)
index 0000000..7b7c117
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlSetStrategy_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args);
+static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args);
+
+static const char *_commandSetStrategy = "set strategy";
+static const char *_commandSetStrategyHelp = "help set strategy";
+
+static const char *_commandSetStrategyOptions[LAST_STRATEGY_VALUE] = {
+    "loadbalancer",
+    "random",
+    "random_per_dash_segment",
+    "loadbalancer_with_delay",
+    "loadbalancer_by_rate",
+    "loadbalancer_best_route"};
+
+// ====================================================
+
+CommandOps *controlSetStrategy_Create(ControlState *state) {
+  return commandOps_Create(state, _commandSetStrategy, NULL,
+                           _controlSetStrategy_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetStrategy_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandSetStrategyHelp, NULL,
+                           _controlSetStrategy_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+strategy_type _validStrategy(const char *strategy) {
+  strategy_type validStrategy = LAST_STRATEGY_VALUE;
+
+  for (int i = 0; i < LAST_STRATEGY_VALUE; i++) {
+    if (strcmp(_commandSetStrategyOptions[i], strategy) == 0) {
+      validStrategy = i;
+      break;
+    }
+  }
+  return validStrategy;
+}
+
+static CommandReturn _controlSetStrategy_HelpExecute(CommandParser *parser,
+                                                     CommandOps *ops,
+                                                     PARCList *args) {
+  printf("set strategy <prefix> <strategy>\n");
+  printf("prefix: ipv4/ipv6 address (ex: 1234::/64)\n");
+  printf("strategy: strategy identifier\n");
+  printf("available strategies:\n");
+  printf("    random\n");
+  printf("    loadbalancer\n");
+  printf("    random_per_dash_segment\n");
+  printf("    loadbalancer_with_delay\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetStrategy_Execute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 4) {
+    _controlSetStrategy_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) ||
+       (strcmp(parcList_GetAtIndex(args, 1), "strategy") != 0))) {
+    _controlSetStrategy_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  const char *prefixStr = parcList_GetAtIndex(args, 2);
+  char addr[strlen(prefixStr) + 1];
+  // separate address and len
+  char *slash;
+  uint32_t len = UINT32_MAX;
+  strcpy(addr, prefixStr);
+  slash = strrchr(addr, '/');
+  if (slash != NULL) {
+    len = atoi(slash + 1);
+    *slash = '\0';
+  }
+  if (len == 0) {
+    printf("ERROR: a prefix can not be of length 0\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  set_strategy_command *setStrategyCommand =
+      parcMemory_AllocateAndClear(sizeof(set_strategy_command));
+
+  // check and set IP address
+  if (inet_pton(AF_INET, addr, &setStrategyCommand->address.ipv4) == 1) {
+    if (len == UINT32_MAX) {
+      printf("Netmask not specified: set to 32 by default\n");
+      len = 32;
+    } else if (len > 32) {
+      printf("ERROR: exceeded INET mask length, max=32\n");
+      parcMemory_Deallocate(&setStrategyCommand);
+      return CommandReturn_Failure;
+    }
+    setStrategyCommand->addressType = ADDR_INET;
+  } else if (inet_pton(AF_INET6, addr, &setStrategyCommand->address.ipv6) ==
+             1) {
+    if (len == UINT32_MAX) {
+      printf("Netmask not specified: set to 128 by default\n");
+      len = 128;
+    } else if (len > 128) {
+      printf("ERROR: exceeded INET6 mask length, max=128\n");
+      parcMemory_Deallocate(&setStrategyCommand);
+      return CommandReturn_Failure;
+    }
+    setStrategyCommand->addressType = ADDR_INET6;
+  } else {
+    printf("Error: %s is not a valid network address \n", addr);
+    parcMemory_Deallocate(&setStrategyCommand);
+    return CommandReturn_Failure;
+  }
+
+  const char *strategyStr = parcList_GetAtIndex(args, 3);
+  // check valid strategy
+  strategy_type strategy;
+  if ((strategy = _validStrategy(strategyStr)) == LAST_STRATEGY_VALUE) {
+    printf("Error: invalid strategy \n");
+    parcMemory_Deallocate(&setStrategyCommand);
+    _controlSetStrategy_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  // Fill remaining payload fields
+  setStrategyCommand->len = len;
+  setStrategyCommand->strategyType = strategy;
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(
+      state, SET_STRATEGY, setStrategyCommand, sizeof(set_strategy_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetStrategy.h b/hicn-light/src/config/controlSetStrategy.h
new file mode 100755 (executable)
index 0000000..53ce891
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_SetStrategy_h
+#define Control_SetStrategy_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetStrategy_Create(ControlState *state);
+CommandOps *controlSetStrategy_HelpCreate(ControlState *state);
+#endif  // Control_SetStrategy_h
diff --git a/hicn-light/src/config/controlSetWldr.c b/hicn-light/src/config/controlSetWldr.c
new file mode 100755 (executable)
index 0000000..9da4040
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlSetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+static CommandReturn _controlSetWldr_Execute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args);
+static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args);
+
+static const char *_commandSetWldr = "set wldr";
+static const char *_commandSetWldrHelp = "help set wldr";
+
+// ====================================================
+
+CommandOps *controlSetWldr_Create(ControlState *state) {
+  return commandOps_Create(state, _commandSetWldr, NULL,
+                           _controlSetWldr_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlSetWldr_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandSetWldrHelp, NULL,
+                           _controlSetWldr_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlSetWldr_HelpExecute(CommandParser *parser,
+                                                 CommandOps *ops,
+                                                 PARCList *args) {
+  printf("set wldr <on|off> <connection_id>\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlSetWldr_Execute(CommandParser *parser,
+                                             CommandOps *ops, PARCList *args) {
+  ControlState *state = ops->closure;
+
+  if (parcList_Size(args) != 4) {
+    _controlSetWldr_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  if (((strcmp(parcList_GetAtIndex(args, 0), "set") != 0) ||
+       (strcmp(parcList_GetAtIndex(args, 1), "wldr") != 0))) {
+    _controlSetWldr_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  bool active;
+  if (strcmp(parcList_GetAtIndex(args, 2), "on") == 0) {
+    active = true;
+  } else if (strcmp(parcList_GetAtIndex(args, 2), "off") == 0) {
+    active = false;
+  } else {
+    _controlSetWldr_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  // check if valid connid
+  const char *symbolicOrConnid = parcList_GetAtIndex(args, 3);
+
+  if (!utils_ValidateSymbolicName(symbolicOrConnid) &&
+      !utils_IsNumber(symbolicOrConnid)) {
+    printf(
+        "ERROR: Invalid symbolic or connid:\nsymbolic name must begin with an "
+        "alpha followed by alphanum;\nconnid must be an integer\n");
+    return CommandReturn_Failure;
+  }
+
+  // allocate command payload
+  set_wldr_command *setWldrCommand =
+      parcMemory_AllocateAndClear(sizeof(set_wldr_command));
+  strcpy(setWldrCommand->symbolicOrConnid, symbolicOrConnid);
+  if (active) {
+    setWldrCommand->activate = ACTIVATE_ON;
+  } else {
+    setWldrCommand->activate = ACTIVATE_OFF;
+  }
+
+  // send message and receive response
+  struct iovec *response = utils_SendRequest(state, SET_WLDR, setWldrCommand,
+                                             sizeof(set_wldr_command));
+
+  if (!response) {  // get NULL pointer
+    return CommandReturn_Failure;
+  }
+
+  parcMemory_Deallocate(&response);  // free iovec pointer
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlSetWldr.h b/hicn-light/src/config/controlSetWldr.h
new file mode 100755 (executable)
index 0000000..59c0b0f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 Control_SetWldr_h
+#define Control_SetWldr_h
+
+#include <src/config/controlState.h>
+CommandOps *controlSetWldr_Create(ControlState *state);
+CommandOps *controlSetWldr_HelpCreate(ControlState *state);
+#endif  // Control_SetWldr_h
diff --git a/hicn-light/src/config/controlState.c b/hicn-light/src/config/controlState.c
new file mode 100755 (executable)
index 0000000..d8260e8
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <string.h>
+
+#include <parc/security/parc_Security.h>
+
+#include <parc/algol/parc_List.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+#include <src/config/commandParser.h>
+#include <src/config/controlRoot.h>
+#include <src/config/controlState.h>
+
+#include <src/utils/commands.h>
+
+#define SRV_IP "127.0.0.1"
+#define PORT 9695
+
+struct controller_state {
+  CommandParser *parser;
+  bool debugFlag;
+
+  void *userdata;
+  struct iovec *(*writeRead)(ControlState *state, struct iovec *msg);
+  int sockfd;
+  char **commandOutput;
+  bool isInteractive;
+};
+
+int controlState_connectToFwdDeamon() {
+  int sockfd;
+  struct sockaddr_in servaddr;
+
+  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+    printf("\nSocket Creation Failed \n");
+    exit(EXIT_FAILURE);
+  }
+
+  memset(&servaddr, 0, sizeof(servaddr));
+
+  // Filling server information
+  servaddr.sin_family = AF_INET;
+  servaddr.sin_port = htons(PORT);
+  servaddr.sin_addr.s_addr = INADDR_ANY;
+
+  // Establish connection
+  if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
+    printf("\nConnection Failed: hicn-light Daemon is not running \n");
+    exit(EXIT_FAILURE);
+  }
+
+  return sockfd;
+}
+
+ControlState *controlState_Create(
+    void *userdata,
+    struct iovec *(*writeRead)(ControlState *state, struct iovec *msg),
+    bool openControllerConnetion) {
+  ControlState *state = parcMemory_AllocateAndClear(sizeof(ControlState));
+  parcAssertNotNull(state, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ControlState));
+  state->parser = commandParser_Create();
+
+  state->userdata = userdata;
+  state->writeRead = writeRead;
+  state->debugFlag = false;
+  state->commandOutput = NULL;
+  state->isInteractive = true;
+
+  if (openControllerConnetion) {
+    state->sockfd = controlState_connectToFwdDeamon();
+  } else {
+    state->sockfd = 2;  // stderr
+  }
+
+  return state;
+}
+
+void controlState_Destroy(ControlState **statePtr) {
+  parcAssertNotNull(statePtr, "Parameter statePtr must be non-null");
+  parcAssertNotNull(*statePtr,
+                    "Parameter statePtr must dereference t non-null");
+  ControlState *state = *statePtr;
+  // printf("sockid destroyed: %d\n", state->sockfd);
+  // close the connection with the fwd deamon
+  shutdown(state->sockfd, 2);
+
+  commandParser_Destroy(&state->parser);
+  parcMemory_Deallocate((void **)&state);
+  *statePtr = NULL;
+}
+
+void controlState_SetDebug(ControlState *state, bool debugFlag) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  state->debugFlag = debugFlag;
+  commandParser_SetDebug(state->parser, debugFlag);
+}
+
+bool controlState_GetDebug(ControlState *state) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  return state->debugFlag;
+}
+
+void controlState_RegisterCommand(ControlState *state, CommandOps *ops) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  commandParser_RegisterCommand(state->parser, ops);
+}
+
+struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  parcAssertNotNull(msg, "Parameter msg must be non-null");
+
+  return state->writeRead(state, msg);
+}
+
+static PARCList *_controlState_ParseStringIntoTokens(
+    const char *originalString) {
+  PARCList *list =
+      parcList(parcArrayList_Create(parcArrayList_StdlibFreeFunction),
+               PARCArrayListAsPARCList);
+
+  char *token;
+
+  char *tofree =
+      parcMemory_StringDuplicate(originalString, strlen(originalString) + 1);
+  char *string = tofree;
+
+  while ((token = strsep(&string, " \t\n")) != NULL) {
+    if (strlen(token) > 0) {
+      parcList_Add(list, strdup(token));
+    }
+  }
+
+  parcMemory_Deallocate((void **)&tofree);
+
+  return list;
+}
+
+CommandReturn controlState_DispatchCommand(ControlState *state,
+                                           PARCList *args) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  return commandParser_DispatchCommand(state->parser, args);
+}
+
+int controlState_Interactive(ControlState *state) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  char *line = NULL;
+  size_t linecap = 0;
+  CommandReturn controlReturn = CommandReturn_Success;
+
+  while (controlReturn != CommandReturn_Exit && !feof(stdin)) {
+    fputs("> ", stdout);
+    fflush(stdout);
+    ssize_t failure = getline(&line, &linecap, stdin);
+    parcAssertTrue(failure > -1, "Error getline");
+
+    PARCList *args = _controlState_ParseStringIntoTokens(line);
+    controlReturn = controlState_DispatchCommand(state, args);
+    // release and get command
+    parcList_Release(&args);
+  }
+  return 0;
+}
+
+void controlState_SetCommandOutput(ControlState *state, char **commandData) {
+  state->commandOutput = commandData;
+}
+
+void controlState_ReleaseCommandOutput(ControlState *state, char **commandData,
+                                       size_t commandLenght) {
+  for (size_t i = 0; i < commandLenght; i++) {
+    parcMemory_Deallocate(&commandData[i]);
+  }
+  parcMemory_Deallocate(&commandData);
+  state->commandOutput = NULL;
+}
+
+char **controlState_GetCommandOutput(ControlState *state) {
+  return state->commandOutput;
+}
+
+// size_t
+// controlState_GetCommandLen(ControlState *state){
+
+// }
+
+void controlState_SetInteractiveFlag(ControlState *state, bool interactive) {
+  state->isInteractive = interactive;
+}
+
+bool controlState_IsInteractive(ControlState *state) {
+  return state->isInteractive;
+}
+
+int controlState_GetSockfd(ControlState *state) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  return state->sockfd;
+}
+
+void *controlState_GetUserdata(ControlState *state) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  return state->userdata;
+}
+
+bool controlState_isConfigFile(ControlState *state) {
+  parcAssertNotNull(state, "Parameter state must be non-null");
+  if (state->sockfd != 2) {
+    return false;
+  } else {
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/hicn-light/src/config/controlState.h b/hicn-light/src/config/controlState.h
new file mode 100755 (executable)
index 0000000..905c56c
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file controlState.h
+ * @brief A control program for hicn-light using CLI commands
+ *
+ * Implements the state machine for the control program.  It takes a "writeRead"
+ * function as part of the constructor.  This abstracts out the backend.  It
+ * could be a Portal from hicnLightControl program down to the forwarder or it
+ * could be an internal function within hicn-light.
+ *
+ */
+
+#ifndef control_h
+#define control_h
+
+#include <parc/algol/parc_List.h>
+#include <src/config/commandParser.h>
+
+#include <src/utils/commands.h>
+
+struct controller_state;
+typedef struct controller_state ControlState;
+
+/**
+ * controlState_Create
+ *
+ * Creates the global state for the Control program.  The user provides the
+ * writeRead function for sending and receiving the message wrapping command
+ * arguments.  For configuration file inside hicn-light, it would make direct
+ * calls to Configuration -> Dispatcher.
+ *
+ * @param [in] userdata A closure passed back to the user when calling
+ * writeRead.
+ * @param [in] writeRead The function to write then read configuration messages
+ * to hicn-light
+ *
+ * @return non-null The control state
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+
+ControlState *controlState_Create(
+    void *userdata,
+    struct iovec *(*writeRead)(ControlState *state, struct iovec *msg),
+    bool openControllerConnetion);
+
+/**
+ * Destroys the control state, closing all network connections
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void controlState_Destroy(ControlState **statePtr);
+
+/**
+ * Registers a CommandOps with the system.
+ *
+ * Each command has its complete command prefix in the "command" field.
+ * RegisterCommand will put these command prefixes in to a tree and then match
+ * what a user types against the longest-matching prefix in the tree.  If
+ * there's a match, it will call the "execute" function.
+ *
+ * @param [in] state An allocated ControlState
+ * @param [in] command The command to register with the system
+ *
+ * Example:
+ * @code
+ *      static CommandReturn
+ *      control_Root_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ *      {
+ *          printf("Root Command\n");
+ *          return CommandReturn_Success;
+ *      }
+ *
+ *      static CommandReturn
+ *      control_FooBar_Execute(CommandParser *parser, CommandOps *ops, PARCList
+ * *args)
+ *      {
+ *          printf("Foo Bar Command\n");
+ *          return CommandReturn_Success;
+ *      }
+ *
+ *      const CommandOps control_Root = {
+ *      .command = "", // empty string for root
+ *      .init    = NULL,
+ *      .execute = control_Root_Execute
+ *      };
+ *
+ *      const CommandOps control_FooBar = {
+ *      .command = "foo bar", // empty string for root
+ *      .init    = NULL,
+ *      .execute = control_FooBar_Execute
+ *      };
+ *
+ *   void startup(void)
+ *   {
+ *      ControlState *state = controlState_Create("happy", "day");
+ *      controlState_RegisterCommand(state, control_FooBar);
+ *      controlState_RegisterCommand(state, control_Root);
+ *
+ *      // this executes "root"
+ *      controlState_DispatchCommand(state, "foo");
+ *      controlState_Destroy(&state);
+ *  }
+ * @endcode
+ */
+void controlState_RegisterCommand(ControlState *state, CommandOps *command);
+
+/**
+ * Performs a longest-matching prefix of the args to the command tree
+ *
+ * The command tree is created with controlState_RegisterCommand.
+ *
+ * @param [in] state The allocated ControlState
+ * @param [in] args  Each command_line word parsed to the ordered list
+ *
+ * @return CommandReturn_Success the command was successful
+ * @return CommandReturn_Failure the command failed or was not found
+ * @return CommandReturn_Exit the command indicates that the interactive mode
+ * should exit
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+CommandReturn controlState_DispatchCommand(ControlState *state, PARCList *args);
+
+/**
+ * Begin an interactive shell
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+int controlState_Interactive(ControlState *state);
+
+/**
+ * Write then Read a command
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+struct iovec *controlState_WriteRead(ControlState *state, struct iovec *msg);
+
+/**
+ * Sets the Debug mode, which will print out much more information.
+ *
+ * Prints out much more diagnostic information about what hicn-light controller
+ * is doing. yes, you would make a CommandOps to set and unset this :)
+ *
+ * @param [in] debugFlag true means to print debug info, false means to turn it
+ * off
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void controlState_SetDebug(ControlState *state, bool debugFlag);
+
+/**
+ * Returns the debug state of ControlState
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool controlState_GetDebug(ControlState *state);
+#endif  // control_h
+
+void controlState_SetCommandOutput(ControlState *state, char **commandData);
+
+void controlState_ReleaseCommandOutput(ControlState *state, char **commandData,
+                                       size_t commandLenght);
+
+char **controlState_GetCommandOutput(ControlState *state);
+
+void controlState_SetInteractiveFlag(ControlState *state, bool interactive);
+
+bool controlState_IsInteractive(ControlState *state);
+
+void *controlState_GetUserdata(ControlState *state);
+
+bool controlState_isConfigFile(ControlState *state);
+
+int controlState_GetSockfd(ControlState *state);
diff --git a/hicn-light/src/config/controlUnset.c b/hicn-light/src/config/controlUnset.c
new file mode 100755 (executable)
index 0000000..2da6a65
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/security/parc_Security.h>
+
+#include <src/config/controlUnset.h>
+#include <src/config/controlUnsetDebug.h>
+
+static void _controlUnset_Init(CommandParser *parser, CommandOps *ops);
+
+static CommandReturn _controlUnset_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args);
+static CommandReturn _controlUnset_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops, PARCList *args);
+
+static const char *_commandUnset = "unset";
+static const char *_commandUnsetHelp = "help unset";
+
+// ===========================================================
+
+CommandOps *controlUnset_Create(ControlState *state) {
+  return commandOps_Create(state, _commandUnset, _controlUnset_Init,
+                           _controlUnset_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlUnset_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandUnsetHelp, NULL,
+                           _controlUnset_HelpExecute, commandOps_Destroy);
+}
+
+// ===========================================================
+
+static void _controlUnset_Init(CommandParser *parser, CommandOps *ops) {
+  ControlState *state = ops->closure;
+  controlState_RegisterCommand(state, controlUnsetDebug_Create(state));
+  controlState_RegisterCommand(state, controlUnsetDebug_HelpCreate(state));
+}
+
+static CommandReturn _controlUnset_HelpExecute(CommandParser *parser,
+                                               CommandOps *ops,
+                                               PARCList *args) {
+  CommandOps *ops_help_unset_debug = controlUnsetDebug_HelpCreate(NULL);
+
+  printf("Available commands:\n");
+  printf("   %s\n", ops_help_unset_debug->command);
+  printf("\n");
+
+  commandOps_Destroy(&ops_help_unset_debug);
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlUnset_Execute(CommandParser *parser,
+                                           CommandOps *ops, PARCList *args) {
+  return _controlUnset_HelpExecute(parser, ops, args);
+}
diff --git a/hicn-light/src/config/controlUnset.h b/hicn-light/src/config/controlUnset.h
new file mode 100755 (executable)
index 0000000..6eeb983
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_Unset.h
+ * @brief Implements the unset node of the CLI tree
+ *
+ * Implements the "unset" and "help unset" nodes of the command tree
+ *
+ */
+#ifndef Control_Unset_h
+#define Control_Unset_h
+
+#include <src/config/controlState.h>
+CommandOps *controlUnset_Create(ControlState *state);
+CommandOps *controlUnset_HelpCreate(ControlState *state);
+#endif  // Control_Unset_h
diff --git a/hicn-light/src/config/controlUnsetDebug.c b/hicn-light/src/config/controlUnsetDebug.c
new file mode 100755 (executable)
index 0000000..4892bd5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <src/config/controlUnsetDebug.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+
+static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args);
+static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args);
+
+static const char *_commandUnsetDebug = "unset debug";
+static const char *_commandUnsetDebugHelp = "help unset debug";
+
+// ====================================================
+
+CommandOps *controlUnsetDebug_Create(ControlState *state) {
+  return commandOps_Create(state, _commandUnsetDebug, NULL,
+                           _controlUnsetDebug_Execute, commandOps_Destroy);
+}
+
+CommandOps *controlUnsetDebug_HelpCreate(ControlState *state) {
+  return commandOps_Create(state, _commandUnsetDebugHelp, NULL,
+                           _controlUnsetDebug_HelpExecute, commandOps_Destroy);
+}
+
+// ====================================================
+
+static CommandReturn _controlUnsetDebug_HelpExecute(CommandParser *parser,
+                                                    CommandOps *ops,
+                                                    PARCList *args) {
+  printf("unset debug: will disable the debug flag\n");
+  printf("\n");
+  return CommandReturn_Success;
+}
+
+static CommandReturn _controlUnsetDebug_Execute(CommandParser *parser,
+                                                CommandOps *ops,
+                                                PARCList *args) {
+  if (parcList_Size(args) != 2) {
+    _controlUnsetDebug_HelpExecute(parser, ops, args);
+    return CommandReturn_Failure;
+  }
+
+  ControlState *state = ops->closure;
+  controlState_SetDebug(state, false);
+  printf("Debug flag cleared\n\n");
+
+  return CommandReturn_Success;
+}
diff --git a/hicn-light/src/config/controlUnsetDebug.h b/hicn-light/src/config/controlUnsetDebug.h
new file mode 100755 (executable)
index 0000000..e34f8aa
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file control_UnsetDebug.h
+ * @brief Unsets the debug flag for more verbose output
+ *
+ * Implements the "unset debug" and "help unset debug" nodes of the CLI tree
+ *
+ */
+
+#ifndef Control_UnsetDebug_h
+#define Control_UnsetDebug_h
+
+#include <src/config/controlState.h>
+CommandOps *controlUnsetDebug_Create(ControlState *state);
+CommandOps *controlUnsetDebug_HelpCreate(ControlState *state);
+#endif  // Control_UnsetDebug_h
diff --git a/hicn-light/src/config/symbolicNameTable.c b/hicn-light/src/config/symbolicNameTable.c
new file mode 100755 (executable)
index 0000000..ccf416d
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017-2019 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 <ctype.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/config/symbolicNameTable.h>
+
+struct symblic_name_table {
+  PARCHashCodeTable *symbolicNameTable;
+  PARCHashCodeTable *indexToNameTable;
+};
+
+// ========================================================================================
+// symbolic name table functions
+
+static bool _symbolicNameEquals(const void *keyA, const void *keyB) {
+  return (strcasecmp((const char *)keyA, (const char *)keyB) == 0);
+}
+
+static HashCodeType _symbolicNameHash(const void *keyA) {
+  const char *str = (const char *)keyA;
+  size_t length = strlen(str);
+  return parcHash32_Data(str, length);
+}
+
+static bool _connectionIdEquals(const void *keyA, const void *keyB) {
+  unsigned idA = *((unsigned *)keyA);
+  unsigned idB = *((unsigned *)keyB);
+  return (idA == idB);
+}
+
+static HashCodeType _connectionIdHash(const void *keyA) {
+  unsigned idA = *((unsigned *)keyA);
+  return parcHash32_Int32(idA);
+}
+
+// ========================================================================================
+
+SymbolicNameTable *symbolicNameTable_Create(void) {
+  SymbolicNameTable *table = parcMemory_Allocate(sizeof(SymbolicNameTable));
+
+  if (table) {
+    // key = char *
+    // value = uint32_t *
+    table->symbolicNameTable = parcHashCodeTable_Create(
+        _symbolicNameEquals, _symbolicNameHash, parcMemory_DeallocateImpl,
+        parcMemory_DeallocateImpl);
+    table->indexToNameTable = parcHashCodeTable_Create(
+        _connectionIdEquals, _connectionIdHash, parcMemory_DeallocateImpl,
+        parcMemory_DeallocateImpl);
+  }
+
+  return table;
+}
+
+void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr) {
+  SymbolicNameTable *table = *tablePtr;
+  parcHashCodeTable_Destroy(&table->symbolicNameTable);
+  // parcHashCodeTable_Destroy(&table->indexToNameTable);
+  parcMemory_Deallocate((void **)&table);
+  *tablePtr = NULL;
+}
+
+static char *_createKey(const char *symbolicName) {
+  char *key = parcMemory_StringDuplicate(symbolicName, strlen(symbolicName));
+
+  // convert key to upper case
+  char *p = key;
+
+  // keeps looping until the first null
+  while ((*p = toupper(*p))) {
+    p++;
+  }
+  return key;
+}
+
+bool symbolicNameTable_Exists(SymbolicNameTable *table,
+                              const char *symbolicName) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+  char *key = _createKey(symbolicName);
+  bool found = (parcHashCodeTable_Get(table->symbolicNameTable, key) != NULL);
+  parcMemory_Deallocate((void **)&key);
+  return found;
+}
+
+void symbolicNameTable_Remove(SymbolicNameTable *table,
+                              const char *symbolicName) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+  char *key = _createKey(symbolicName);
+
+  unsigned id = symbolicNameTable_Get(table, symbolicName);
+  uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+  *value = id;
+
+  parcHashCodeTable_Del(table->symbolicNameTable, key);
+  parcHashCodeTable_Del(table->indexToNameTable, value);
+  parcMemory_Deallocate((void **)&key);
+  parcMemory_Deallocate((void **)&value);
+}
+
+bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName,
+                           unsigned connid) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+  parcAssertTrue(connid < UINT32_MAX, "Parameter connid must be less than %u",
+                 UINT32_MAX);
+
+  char *key = _createKey(symbolicName);
+
+  uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+  *value = connid;
+
+  bool success = parcHashCodeTable_Add(table->symbolicNameTable, key, value);
+  success = parcHashCodeTable_Add(table->indexToNameTable, value, key);
+  if (!success) {
+    parcMemory_Deallocate((void **)&key);
+    parcMemory_Deallocate((void **)&value);
+  }
+
+  return success;
+}
+
+unsigned symbolicNameTable_Get(SymbolicNameTable *table,
+                               const char *symbolicName) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(symbolicName, "Parameter symbolicName must be non-null");
+
+  unsigned connid = UINT32_MAX;
+
+  char *key = _createKey(symbolicName);
+
+  uint32_t *value = parcHashCodeTable_Get(table->symbolicNameTable, key);
+  if (value) {
+    connid = *value;
+  }
+
+  parcMemory_Deallocate((void **)&key);
+  return connid;
+}
+
+const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table,
+                                             unsigned id) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+
+  uint32_t *value = parcMemory_Allocate(sizeof(uint32_t));
+  *value = id;
+
+  const char *name = parcHashCodeTable_Get(table->indexToNameTable, value);
+  if (name == NULL) name = "";
+
+  parcMemory_Deallocate((void **)&value);
+  return name;
+}
diff --git a/hicn-light/src/config/symbolicNameTable.h b/hicn-light/src/config/symbolicNameTable.h
new file mode 100755 (executable)
index 0000000..69919cf
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file symbolicNameTable.h
+ * @brief The symbolic name table maps a string name to a connection id
+ *
+ * When configuring tunnels/connections, the user provides a string name
+ * (symbolic name) that they will use to refer to that connection.  The symblic
+ * name table translates that symbolic name to a connection id.
+ *
+ */
+
+#ifndef symbolicNameTable_h
+#define symbolicNameTable_h
+
+struct symblic_name_table;
+typedef struct symblic_name_table SymbolicNameTable;
+
+#include <stdbool.h>
+
+/**
+ * Creates a symbolic name table
+ *
+ * Allocates a SymbolicNameTable, which will store the symbolic names
+ * in a hash table.
+ *
+ * @retval non-null An allocated SymbolicNameTable
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+SymbolicNameTable *symbolicNameTable_Create(void);
+
+/**
+ * Destroys a name table
+ *
+ * All keys and data are released.
+ *
+ * @param [in,out] tablePtr A pointer to a SymbolicNameTable, which will be
+ * NULL'd
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void symbolicNameTable_Destroy(SymbolicNameTable **tablePtr);
+
+/**
+ * Checks if the name (case insensitive) is in the table
+ *
+ * Does a case-insensitive match to see if the name is in the table
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to check for
+ *
+ * @retval true The name is in the table
+ * @retval false The name is not in the talbe
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool symbolicNameTable_Exists(SymbolicNameTable *table,
+                              const char *symbolicName);
+
+/**
+ * Adds a (name, connid) pair to the table.
+ *
+ * The name is stored case insensitive.  The value UINT_MAX is used to indicate
+ * a non-existent key, so it should not be stored as a value in the table.
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to save (will make a copy)
+ * @param [in] connid The connection id to associate with the name
+ *
+ * @retval true The pair was added
+ * @retval false The pair was not added (likely duplicate key)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool symbolicNameTable_Add(SymbolicNameTable *table, const char *symbolicName,
+                           unsigned connid);
+
+/**
+ * Returns the connection id associated with the symbolic name
+ *
+ * This function will look for the given name (case insensitive) and return the
+ * corresponding connid.  If the name is not in the table, the function will
+ * return UINT_MAX.
+ *
+ * @param [in] table An allocated SymbolicNameTable
+ * @param [in] symbolicName The name to retrieve
+ *
+ * @retval UINT_MAX symbolicName not found
+ * @retval number the corresponding connid.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned symbolicNameTable_Get(SymbolicNameTable *table,
+                               const char *symbolicName);
+
+void symbolicNameTable_Remove(SymbolicNameTable *table,
+                              const char *symbolicName);
+const char *symbolicNameTable_GetNameByIndex(SymbolicNameTable *table,
+                                             unsigned id);
+
+#endif /* defined(symbolicNameTable_h) */
diff --git a/hicn-light/src/content_store/CMakeLists.txt b/hicn-light/src/content_store/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..85643cf
--- /dev/null
@@ -0,0 +1,33 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreInterface.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreLRU.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/listLRU.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/listTimeOrdered.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/contentStoreEntry.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/content_store/contentStoreEntry.c b/hicn-light/src/content_store/contentStoreEntry.c
new file mode 100755 (executable)
index 0000000..d36ed61
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/content_store/contentStoreEntry.h>
+
+#include <parc/assert/parc_Assert.h>
+
+const uint64_t contentStoreEntry_MaxExpiryTime = UINT64_MAX;
+
+struct contentstore_entry {
+  Message *message;
+  ListLruEntry *lruEntry;
+  unsigned refcount;
+  bool hasExpiryTimeTicks;
+  uint64_t expiryTimeTicks;
+};
+
+ContentStoreEntry *contentStoreEntry_Create(Message *contentMessage,
+                                            ListLru *listLRU) {
+  parcAssertNotNull(contentMessage, "Parameter objectMessage must be non-null");
+
+  ContentStoreEntry *entry =
+      parcMemory_AllocateAndClear(sizeof(ContentStoreEntry));
+  parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ContentStoreEntry));
+  entry->message = message_Acquire(contentMessage);
+  entry->refcount = 1;
+
+  if (listLRU != NULL) {
+    entry->lruEntry = listLRU_NewHeadEntry(listLRU, entry);
+  }
+
+  entry->hasExpiryTimeTicks = message_HasContentExpiryTime(contentMessage);
+
+  if (entry->hasExpiryTimeTicks) {
+    entry->expiryTimeTicks = message_GetContentExpiryTimeTicks(contentMessage);
+  }
+
+  return entry;
+}
+
+ContentStoreEntry *contentStoreEntry_Acquire(
+    const ContentStoreEntry *original) {
+  parcAssertNotNull(original, "Parameter must be non-null");
+  ((ContentStoreEntry *)original)->refcount++;
+  return (ContentStoreEntry *)original;
+}
+
+void contentStoreEntry_Release(ContentStoreEntry **entryPtr) {
+  parcAssertNotNull(entryPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*entryPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  ContentStoreEntry *entry = *entryPtr;
+  parcAssertTrue(entry->refcount > 0, "Illegal state: has refcount of 0");
+
+  entry->refcount--;
+  if (entry->refcount == 0) {
+    if (entry->lruEntry) {
+      listLRU_EntryDestroy(&entry->lruEntry);
+    }
+    message_Release(&entry->message);
+    parcMemory_Deallocate((void **)&entry);
+  }
+  *entryPtr = NULL;
+}
+
+Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry) {
+  parcAssertNotNull(storeEntry, "Parameter must be non-null");
+  return storeEntry->message;
+}
+
+bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry) {
+  parcAssertNotNull(storeEntry, "Parameter must be non-null");
+  return storeEntry->hasExpiryTimeTicks;
+}
+
+uint64_t contentStoreEntry_GetExpiryTimeTicks(
+    const ContentStoreEntry *storeEntry) {
+  parcAssertNotNull(storeEntry, "Parameter must be non-null");
+  parcAssertTrue(storeEntry->hasExpiryTimeTicks,
+                 "storeEntry has no ExpiryTimeTicks. Did you call "
+                 "contentStoreEntry_HasExpiryTimeTicks() first?");
+  return storeEntry->expiryTimeTicks;
+}
+
+int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *value1,
+                                        const ContentStoreEntry *value2) {
+  // A signum comparison. negative if key 1 is smaller, 0 if key1 == key2,
+  // greater than 0 if key1 is bigger.
+
+  ContentStoreEntry *v1 = (ContentStoreEntry *)value1;
+  ContentStoreEntry *v2 = (ContentStoreEntry *)value2;
+
+  if (v1->expiryTimeTicks < v2->expiryTimeTicks) {
+    return -1;
+  } else if (v1->expiryTimeTicks > v2->expiryTimeTicks) {
+    return +1;
+  } else {
+    // At this point, the times are the same. Use the address of the message as
+    // the decider. This allows us to store multiple messages with the same
+    // expiry/cache time.
+    if (v1->message < v2->message) {
+      return -1;
+    } else if (v1->message > v2->message) {
+      return +1;
+    }
+  }
+
+  return 0;  // The same message has been encountered.
+}
+
+void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry) {
+  parcAssertNotNull(storeEntry, "Parameter must be non-null");
+  parcAssertNotNull(storeEntry->lruEntry,
+                    "ContentStoreEntry is not attached to an ListLru");
+  if (storeEntry->lruEntry) {
+    listLRU_EntryMoveToHead(storeEntry->lruEntry);
+  }
+}
diff --git a/hicn-light/src/content_store/contentStoreEntry.h b/hicn-light/src/content_store/contentStoreEntry.h
new file mode 100755 (executable)
index 0000000..766cc15
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017-2019 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 contentStoreEntry_h
+#define contentStoreEntry_h
+
+#include <src/content_store/listLRU.h>
+#include <src/core/message.h>
+
+struct contentstore_entry;
+typedef struct contentstore_entry ContentStoreEntry;
+
+/**
+ * The max time allowed for an ExpiryTime. Will never be exceeded.
+ */
+extern const uint64_t contentStoreEntry_MaxExpiryTime;
+
+/**
+ * Creates a new `ContentStoreEntry` instance, acquiring a reference to the
+ * supplied `Message`.
+ *
+ * @param message the message to store
+ * @param listLRU the LRU list that this entry will be stored in.
+ * @return A newly created `ContentStoreEntry` instance that must eventually be
+ * released by calling
+ *         {@link contentStoreEntry_Release}.
+ *
+ * @see contentStoreEntry_Release
+ */
+ContentStoreEntry *contentStoreEntry_Create(Message *objectMessage,
+                                            ListLru *listLRU);
+
+/**
+ * Returns a reference counted copy of the supplied `ContentStoreEntry`.
+ *
+ * @param original the ContentStoreEntry to return a reference to.
+ * @return Reference counted copy, must call
+ * <code>contentStoreEntry_Destroy()</code> on it.
+ */
+ContentStoreEntry *contentStoreEntry_Acquire(const ContentStoreEntry *original);
+
+/**
+ * Releases one reference count and destroys object when reaches zero
+ *
+ * @param [in,out] entryPtr A pointer to an allocated ContentStoreEntry
+ *
+ */
+void contentStoreEntry_Release(ContentStoreEntry **entryPtr);
+
+/**
+ * Returns a pointer to the contained {@link Message}.
+ * The caller must called {@link message_Acquire()} if they want to keep a
+ * reference to the returned message.
+ *
+ * @param storeEntry the ContentStoreEntry from which to retrieve the `Message`
+ * pointer.
+ * @return the address of the `Message` contained in the storeEntry.
+ * @see message_Acquire
+ */
+Message *contentStoreEntry_GetMessage(const ContentStoreEntry *storeEntry);
+
+/**
+ * Return true if the message stored in this `ContentStoreEntry` has an
+ * ExpiryTime.
+ *
+ * @param storeEntry the ContentStoreEntry containing the message.
+ * @return true if the referenced message has an ExpiryTime. False, otherwise.
+ */
+bool contentStoreEntry_HasExpiryTimeTicks(const ContentStoreEntry *storeEntry);
+
+/**
+ * Return the ExpiryTime stored in this `ContentStoreEntry`.
+ *
+ * @param storeEntry the ContentStoreEntry from which to retrieve the `Message`
+ * pointer.
+ * @return the address of the `Message` contained in the storeEntry.
+ */
+uint64_t contentStoreEntry_GetExpiryTimeTicks(
+    const ContentStoreEntry *storeEntry);
+
+/**
+ * A signum function comparing two `ContentStoreEntry` instances, using their
+ * ExpiryTime and, if necessary, the addresses of the referenced Message. In
+ * other words, if two ContentStoreEntries have the same ExpiryTime, the
+ * comparison will then be made on the memory addresses of the Messages
+ * referenced by the ContentStoreEntrys. So, the only way two ContentStoreEntrys
+ * will compare equally (0) is if they both have the same ExpiryTime and
+ * reference the same Message.
+ *
+ * Used to determine the ordering relationship of two `ContentStoreEntry`
+ * instances. This is used by the {@link ListTimeOrdered} to keep a list of
+ * ContentStoreEntrys, sorted by ExpiryTime.
+ *
+ * @param [in] storeEntry1 A pointer to a `ContentStoreEntry` instance.
+ * @param [in] storeEntry2 A pointer to a `ContentStoreEntry` instance to be
+ * compared to `storeEntry1`.
+ *
+ * @return 0 if `storeEntry1` and `storeEntry2` are equivalent
+ * @return < 0 if `storeEntry1` < `storeEntry2`
+ * @return > 0 if `storeEntry1` > `storeEntry2`
+ *
+ * Example:
+ * @code
+ * {
+ *     ContentStoreEntry *entry1 = contentStoreEntry_Create(...);
+ *     ContentStoreEntry *entry2 = contentStoreEntry_Create(...);
+ *
+ *     int val = contentStoreEntry_CompareExpiryTime(entry1, entry2);
+ *     if (val < 0) {
+ *         // entry1 has a lower ExpiryTime, or the same ExpiryTime as entry2
+ * and a different message. } else if (val > 0) {
+ *         // entry2 has a lower ExpiryTime, or the same ExpiryTime as entry1
+ * and a different message. } else {
+ *         // entry1 and entry2 have the same ExpiryTime AND the same message.
+ *     }
+ *
+ *     contentStoreEntry_Release(&entry1);
+ *     contentStoreEntry_Release(&entry2);
+ *
+ * }
+ * @endcode
+ */
+int contentStoreEntry_CompareExpiryTime(const ContentStoreEntry *storeEntry1,
+                                        const ContentStoreEntry *storeEntry2);
+
+/**
+ * Move this entry to the head of the LRU list
+ *
+ * Moves the entry to the head of the LRU list it was created with
+ *
+ * @param [in] storeEntry An allocated ContenstoreEntry
+ */
+void contentStoreEntry_MoveToHead(ContentStoreEntry *storeEntry);
+#endif  // contentStoreEntry_h
diff --git a/hicn-light/src/content_store/contentStoreInterface.c b/hicn-light/src/content_store/contentStoreInterface.c
new file mode 100755 (executable)
index 0000000..a420416
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/content_store/contentStoreInterface.h>
+
+void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr) {
+  (*storeImplPtr)->release(storeImplPtr);
+}
+
+bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl,
+                                      Message *content,
+                                      uint64_t currentTimeTicks) {
+  return storeImpl->putContent(storeImpl, content, currentTimeTicks);
+}
+
+bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl,
+                                         Message *content) {
+  return storeImpl->removeContent(storeImpl, content);
+}
+
+Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl,
+                                             Message *interest,
+                                             uint64_t currentTimeTicks) {
+  return storeImpl->matchInterest(storeImpl, interest, currentTimeTicks);
+}
+
+size_t contentStoreInterface_GetObjectCapacity(
+    ContentStoreInterface *storeImpl) {
+  return storeImpl->getObjectCapacity(storeImpl);
+}
+
+size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl) {
+  return storeImpl->getObjectCount(storeImpl);
+}
+
+void contentStoreInterface_Log(ContentStoreInterface *storeImpl) {
+  storeImpl->log(storeImpl);
+}
+
+void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl) {
+  return storeImpl->_privateData;
+}
diff --git a/hicn-light/src/content_store/contentStoreInterface.h b/hicn-light/src/content_store/contentStoreInterface.h
new file mode 100755 (executable)
index 0000000..d73c630
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017-2019 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 contentStoreInterface_h
+#define contentStoreInterface_h
+
+#include <stdio.h>
+
+#include <src/core/message.h>
+
+typedef struct contentstore_config {
+  size_t objectCapacity;
+} ContentStoreConfig;
+
+typedef struct contentstore_interface ContentStoreInterface;
+
+struct contentstore_interface {
+  /**
+   * Place a Message representing a ContentObject into the ContentStore. If
+   * necessary to make room, remove expired content or content that has exceeded
+   * the Recommended Cache Time.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   * @param content - a pointer to a `Message` to place in the store.
+   * @param currentTimeTicks - the current time, in hicn-light ticks, since the
+   * UTC epoch.
+   */
+  bool (*putContent)(ContentStoreInterface *storeImpl, Message *content,
+                     uint64_t currentTimeTicks);
+
+  /**
+   * The function to call to remove content from the ContentStore.
+   * It will Release any references that were created when the content was
+   * placed into the ContentStore.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   * @param content - a pointer to a `Message` to remove from the store.
+   */
+  bool (*removeContent)(ContentStoreInterface *storeImpl, Message *content);
+
+  /**
+   * Given a Message that represents and Interest, try to find a matching
+   * ContentObject.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   * @param interest - a pointer to a `Message` representing the Interest to
+   * match.
+   *
+   * @return a pointer to a Message containing the matching ContentObject
+   * @return NULL if no matching ContentObject was found
+   */
+  Message *(*matchInterest)(ContentStoreInterface *storeImpl, Message *interest,
+                            uint64_t currentTimeTicks);
+
+  /**
+   * Return the maximum number of ContentObjects that can be stored in this
+   * ContentStore. This is a raw count, not based on memory size.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   *
+   * @return the maximum number of ContentObjects that can be stored
+   */
+  size_t (*getObjectCapacity)(ContentStoreInterface *storeImpl);
+
+  /**
+   * Return the number of ContentObjects currently stored in the ContentStore.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   *
+   * @return the current number of ContentObjects in the ContentStore
+   */
+  size_t (*getObjectCount)(ContentStoreInterface *storeImpl);
+
+  /**
+   * Log a ContentStore implementation specific version of store-related
+   * information.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   */
+  void (*log)(ContentStoreInterface *storeImpl);
+
+  /**
+   * Acquire a new reference to the specified ContentStore instance. This
+   * reference will eventually need to be released by calling {@link
+   * contentStoreInterface_Release}.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   */
+  ContentStoreInterface *(*acquire)(const ContentStoreInterface *storeImpl);
+
+  /**
+   * Release the ContentStore, which will also Release any references held by
+   * it.
+   *
+   * @param storeImpl - a pointer to this ContentStoreInterface instance.
+   */
+  void (*release)(ContentStoreInterface **storeImpl);
+
+  /**
+   * A pointer to opaque private data used by the ContentStore instance
+   * represented by this instance of ContentStoreInterface.
+   */
+  void *_privateData;
+};
+
+/**
+ * Place a Message representing a ContentObject into the ContentStore. If
+ * necessary to make room, remove expired content or content that has exceeded
+ * the Recommended Cache Time.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to place in the store.
+ *
+ * @param currentTimeTicks - the current time, in hicn-light ticks, since the
+ * UTC epoch.
+ */
+bool contentStoreInterface_PutContent(ContentStoreInterface *storeImpl,
+                                      Message *content,
+                                      uint64_t currentTimeTicks);
+
+/**
+ * The function to call to remove content from the ContentStore.
+ * It will Release any references that were created when the content was placed
+ * into the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param content - a pointer to a `Message` to remove from the store.
+ */
+bool contentStoreInterface_RemoveContent(ContentStoreInterface *storeImpl,
+                                         Message *content);
+
+/**
+ * Given a Message that represents and Interest, try to find a matching
+ * ContentObject.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ * @param interest - a pointer to a `Message` representing the Interest to
+ * match.
+ *
+ * @return a pointer to a Message containing the matching ContentObject
+ * @return NULL if no matching ContentObject was found
+ */
+Message *contentStoreInterface_MatchInterest(ContentStoreInterface *storeImpl,
+                                             Message *interest,
+                                             uint64_t currentTimeTicks);
+
+/**
+ * Return the maximum number of ContentObjects that can be stored in this
+ * ContentStore. This is a raw count, not based on memory size.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the maximum number of ContentObjects that can be stored
+ */
+size_t contentStoreInterface_GetObjectCapacity(
+    ContentStoreInterface *storeImpl);
+
+/**
+ * Return the number of ContentObjects currently stored in the ContentStore.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ *
+ * @return the current number of ContentObjects in the ContentStore
+ */
+size_t contentStoreInterface_GetObjectCount(ContentStoreInterface *storeImpl);
+
+/**
+ * Loga ContentStore implementation specific version of store-related
+ * information.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void contentStoreInterface_Log(ContentStoreInterface *storeImpl);
+
+/**
+ * Acquire a new reference to the specified ContentStore instance. This
+ * reference will eventually need to be released by calling {@link
+ * contentStoreInterface_Release}.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+ContentStoreInterface *contentStoreInterface_Aquire(
+    const ContentStoreInterface *storeImpl);
+
+/**
+ * Release the ContentStore, which will also Release any references held by it.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void contentStoreInterface_Release(ContentStoreInterface **storeImplPtr);
+
+/**
+ * Return a pointer to the data private to this implementation of the
+ * ContentStore interface.
+ *
+ * @param storeImpl - a pointer to this ContentStoreInterface instance.
+ */
+void *contentStoreInterface_GetPrivateData(ContentStoreInterface *storeImpl);
+#endif  // contentStoreInterface_h
diff --git a/hicn-light/src/content_store/contentStoreLRU.c b/hicn-light/src/content_store/contentStoreLRU.c
new file mode 100755 (executable)
index 0000000..9b69d51
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Object.h>
+
+#include <src/core/logger.h>
+
+#include <src/content_store/contentStoreLRU.h>
+
+#include <src/content_store/contentStoreEntry.h>
+#include <src/content_store/contentStoreInterface.h>
+#include <src/content_store/listLRU.h>
+#include <src/content_store/listTimeOrdered.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/hashTableFunction.h>
+
+typedef struct contentstore_stats {
+  uint64_t countExpiryEvictions;
+  uint64_t countRCTEvictions;
+  uint64_t countLruEvictions;
+  uint64_t countAdds;
+  uint64_t countHits;
+  uint64_t countMisses;
+} _ContentStoreLRUStats;
+
+typedef struct contentstore_lru_data {
+  size_t objectCapacity;
+  size_t objectCount;
+
+  Logger *logger;
+
+  // This LRU is just for keeping track of insertion and access order.
+  ListLru *lru;
+
+  ListTimeOrdered *indexByExpirationTime;
+
+  PARCHashCodeTable *storageByName;
+
+  _ContentStoreLRUStats stats;
+} _ContentStoreLRU;
+
+static void _destroyIndexes(_ContentStoreLRU *store) {
+  if (store->indexByExpirationTime != NULL) {
+    listTimeOrdered_Release(&(store->indexByExpirationTime));
+  }
+
+  if (store->storageByName != NULL) {
+    parcHashCodeTable_Destroy(&(store->storageByName));
+  }
+
+  if (store->lru != NULL) {
+    listLRU_Destroy(&(store->lru));
+  }
+}
+
+static void _contentStoreInterface_Destroy(
+    ContentStoreInterface **storeImplPtr) {
+  _ContentStoreLRU *store = contentStoreInterface_GetPrivateData(*storeImplPtr);
+
+  parcObject_Release((PARCObject **)&store);
+}
+
+static bool _contentStoreLRU_Destructor(_ContentStoreLRU **storePtr) {
+  _ContentStoreLRU *store = *storePtr;
+
+  _destroyIndexes(store);
+  logger_Release(&store->logger);
+
+  return true;
+}
+
+parcObject_Override(_ContentStoreLRU, PARCObject,
+                    .destructor = (PARCObjectDestructor *)
+                        _contentStoreLRU_Destructor);
+
+parcObject_ExtendPARCObject(ContentStoreInterface,
+                            _contentStoreInterface_Destroy, NULL, NULL, NULL,
+                            NULL, NULL, NULL);
+
+static parcObject_ImplementAcquire(_contentStoreLRU, ContentStoreInterface);
+static parcObject_ImplementRelease(_contentStoreLRU, ContentStoreInterface);
+
+static void _hashTableFunction_ContentStoreEntryDestroyer(void **dataPtr) {
+  contentStoreEntry_Release((ContentStoreEntry **)dataPtr);
+}
+
+static bool _contentStoreLRU_Init(_ContentStoreLRU *store,
+                                  ContentStoreConfig *config, Logger *logger) {
+  bool result = false;
+
+  store->logger = logger_Acquire(logger);
+
+  size_t initialSize = config->objectCapacity * 2;
+  memset(&store->stats, 0, sizeof(_ContentStoreLRUStats));
+
+  store->objectCapacity = config->objectCapacity;
+  store->objectCount = 0;
+
+  // initial size must be at least 1 or else the data structures break.
+  initialSize = (initialSize == 0) ? 1 : initialSize;
+
+  store->indexByExpirationTime = listTimeOrdered_Create(
+      (TimeOrderList_KeyCompare *)contentStoreEntry_CompareExpiryTime);
+
+  store->storageByName = parcHashCodeTable_Create_Size(
+      hashTableFunction_MessageNameEquals,
+      hashTableFunction_MessageNameHashCode, NULL,
+      _hashTableFunction_ContentStoreEntryDestroyer, initialSize);
+
+  store->lru = listLRU_Create();
+
+  // If any of the index tables couldn't be allocated, we can't continue.
+  if ((store->indexByExpirationTime == NULL) ||
+      (store->storageByName == NULL) || (store->lru == NULL)) {
+    if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Error)) {
+      logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Error,
+                 __func__,
+                 "ContentStoreLRU could not be created. Could not allocate all "
+                 "index tables.",
+                 (void *)store, store->objectCapacity);
+    }
+
+    _destroyIndexes(store);
+    result = false;
+  } else {
+    result = true;
+  }
+  return result;
+}
+
+/**
+ * Remove a ContentStoreEntry from all tables and indices.
+ */
+static void _contentStoreLRU_PurgeStoreEntry(_ContentStoreLRU *store,
+                                             ContentStoreEntry *entryToPurge) {
+  if (contentStoreEntry_HasExpiryTimeTicks(entryToPurge)) {
+    listTimeOrdered_Remove(store->indexByExpirationTime, entryToPurge);
+  }
+
+  Message *content = contentStoreEntry_GetMessage(entryToPurge);
+
+  // This _Del call will call the Release/Destroy on the ContentStoreEntry,
+  // which will remove it from the LRU as well.
+  parcHashCodeTable_Del(store->storageByName, content);
+
+  store->objectCount--;
+}
+
+static bool _contentStoreLRU_RemoveLeastUsed(_ContentStoreLRU *store) {
+  bool result = false;
+
+  if (store->objectCount > 0) {
+    ListLruEntry *lruEntry = listLRU_PopTail(store->lru);
+    ContentStoreEntry *storeEntry =
+        (ContentStoreEntry *)listLRU_EntryGetData(lruEntry);
+
+    if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(
+          store->logger, LoggerFacility_Processor, PARCLogLevel_Debug, __func__,
+          "ContentStore %p evict message %p by LRU (LRU evictions %" PRIu64 ")",
+          (void *)store, (void *)contentStoreEntry_GetMessage(storeEntry),
+          store->stats.countLruEvictions);
+    }
+
+    _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+
+    result = true;
+  }
+  return result;
+}
+
+static void _evictByStorePolicy(_ContentStoreLRU *store,
+                                uint64_t currentTimeInTicks) {
+  // We need to make room. Here's the plan:
+  //  1) Check to see if anything has expired. If so, remove it and we're done.
+  //  If not, 2) Remove the least recently used item.
+
+  ContentStoreEntry *entry =
+      listTimeOrdered_GetOldest(store->indexByExpirationTime);
+  if (entry && contentStoreEntry_HasExpiryTimeTicks(entry) &&
+      (currentTimeInTicks > contentStoreEntry_GetExpiryTimeTicks(entry))) {
+    // Found an expired entry. Remove it, and we're done.
+
+    store->stats.countExpiryEvictions++;
+    if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                 __func__,
+                 "ContentStore %p evict message %p by ExpiryTime (ExpiryTime "
+                 "evictions %" PRIu64 ")",
+                 (void *)store, (void *)contentStoreEntry_GetMessage(entry),
+                 store->stats.countExpiryEvictions);
+    }
+
+    _contentStoreLRU_PurgeStoreEntry(store, entry);
+  } else {
+    store->stats.countLruEvictions++;
+    _contentStoreLRU_RemoveLeastUsed(store);
+  }
+}
+
+static bool _contentStoreLRU_PutContent(ContentStoreInterface *storeImpl,
+                                        Message *content,
+                                        uint64_t currentTimeTicks)
+
+{
+  bool result = false;
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+  parcAssertNotNull(store, "Parameter store must be non-null");
+  parcAssertNotNull(content, "Parameter objectMessage must be non-null");
+
+  parcAssertTrue(message_GetType(content) == MessagePacketType_ContentObject,
+                 "Parameter objectMessage must be a Content Object");
+
+  if (store->objectCapacity == 0) {
+    return false;
+  }
+
+  uint64_t expiryTimeTicks = contentStoreEntry_MaxExpiryTime;
+
+  if (message_HasContentExpiryTime(content)) {
+    expiryTimeTicks = message_GetContentExpiryTimeTicks(content);
+  }
+  // Don't add anything that's already expired or has exceeded RCT.
+  if (currentTimeTicks >= expiryTimeTicks) {
+    return false;
+  }
+
+  if (store->objectCount >= store->objectCapacity) {
+    // Store is full. Need to make room.
+    _evictByStorePolicy(store, currentTimeTicks);
+  }
+
+  // And now add a new entry to the head of the LRU.
+
+  ContentStoreEntry *entry = contentStoreEntry_Create(content, store->lru);
+
+  if (entry != NULL) {
+    if (parcHashCodeTable_Add(store->storageByName, content, entry)) {
+      if (contentStoreEntry_HasExpiryTimeTicks(entry)) {
+        listTimeOrdered_Add(store->indexByExpirationTime, entry);
+      }
+
+      store->objectCount++;
+      store->stats.countAdds++;
+
+      if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                            PARCLogLevel_Debug)) {
+        logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                   __func__,
+                   "ContentStoreLRU %p saved message %p (object count %" PRIu64
+                   ")",
+                   (void *)store, (void *)content, store->objectCount);
+      }
+
+      result = true;
+    } else {
+      // Free what we just created, but did not add. 'entry' has ownership of
+      // 'copy', and so will call _Release() on it
+      contentStoreEntry_Release(&entry);
+
+      if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                            PARCLogLevel_Warning)) {
+        logger_Log(store->logger, LoggerFacility_Processor,
+                   PARCLogLevel_Warning, __func__,
+                   "ContentStoreLRU %p failed to add message %p to hash table",
+                   (void *)store, (void *)content);
+      }
+    }
+  }
+
+  return result;
+}
+
+static Message *_contentStoreLRU_MatchInterest(ContentStoreInterface *storeImpl,
+                                               Message *interest,
+                                               uint64_t currentTimeTicks) {
+  Message *result = NULL;
+
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+  parcAssertNotNull(store, "Parameter store must be non-null");
+  parcAssertNotNull(interest, "Parameter interestMessage must be non-null");
+  parcAssertTrue(message_GetType(interest) == MessagePacketType_Interest,
+                 "Parameter interestMessage must be an Interest");
+
+  PARCHashCodeTable *table;
+  table = store->storageByName;
+
+  ContentStoreEntry *storeEntry = parcHashCodeTable_Get(table, interest);
+
+  bool foundEntry = false;
+
+  if (storeEntry) {
+    if (contentStoreEntry_HasExpiryTimeTicks(storeEntry) &&
+        contentStoreEntry_GetExpiryTimeTicks(storeEntry) < currentTimeTicks) {
+      // the entry is expired, we can remove it
+      _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+    } else {
+      foundEntry = true;
+    }
+  }
+
+  if (foundEntry) {
+    contentStoreEntry_MoveToHead(storeEntry);
+    result = contentStoreEntry_GetMessage(storeEntry);
+
+    store->stats.countHits++;
+
+    if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                 __func__,
+                 "ContentStoreLRU %p matched interest %p (hits %" PRIu64
+                 ", misses %" PRIu64 ")",
+                 (void *)store, (void *)interest, store->stats.countHits,
+                 store->stats.countMisses);
+    }
+  } else {
+    store->stats.countMisses++;
+
+    if (logger_IsLoggable(store->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                 __func__,
+                 "ContentStoreLRU %p missed interest %p (hits %" PRIu64
+                 ", misses %" PRIu64 ")",
+                 (void *)store, (void *)interest, store->stats.countHits,
+                 store->stats.countMisses);
+    }
+  }
+
+  return result;
+}
+
+static bool _contentStoreLRU_RemoveContent(ContentStoreInterface *storeImpl,
+                                           Message *content) {
+  bool result = false;
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+  ContentStoreEntry *storeEntry =
+      parcHashCodeTable_Get(store->storageByName, content);
+
+  if (storeEntry != NULL) {
+    _contentStoreLRU_PurgeStoreEntry(store, storeEntry);
+    result = true;
+  }
+
+  return result;
+}
+
+static void _contentStoreLRU_Log(ContentStoreInterface *storeImpl) {
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+
+  logger_Log(store->logger, LoggerFacility_Processor, PARCLogLevel_All,
+             __func__,
+             "ContentStoreLRU @%p {count = %zu, capacity = %zu {"
+             "stats = @%p {adds = %" PRIu64 ", hits = %" PRIu64
+             ", misses = %" PRIu64 ", LRUEvictons = %" PRIu64
+             ", ExpiryEvictions = %" PRIu64 ", RCTEvictions = %" PRIu64 "} }",
+             store, store->objectCount, store->objectCapacity, &store->stats,
+             store->stats.countAdds, store->stats.countHits,
+             store->stats.countMisses, store->stats.countLruEvictions,
+             store->stats.countExpiryEvictions, store->stats.countRCTEvictions);
+}
+
+static size_t _contentStoreLRU_GetObjectCapacity(
+    ContentStoreInterface *storeImpl) {
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+  return store->objectCapacity;
+}
+
+static size_t _contentStoreLRU_GetObjectCount(
+    ContentStoreInterface *storeImpl) {
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+  return store->objectCount;
+}
+
+static size_t _contentStoreLRU_SetObjectCapacity(
+    ContentStoreInterface *storeImpl, size_t newCapacity) {
+  _ContentStoreLRU *store =
+      (_ContentStoreLRU *)contentStoreInterface_GetPrivateData(storeImpl);
+  return store->objectCapacity = newCapacity;
+}
+
+ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config,
+                                              Logger *logger) {
+  ContentStoreInterface *storeImpl = NULL;
+
+  parcAssertNotNull(logger, "ContentStoreLRU requires a non-NULL logger");
+
+  storeImpl = parcObject_CreateAndClearInstance(ContentStoreInterface);
+
+  if (storeImpl != NULL) {
+    storeImpl->_privateData =
+        parcObject_CreateAndClearInstance(_ContentStoreLRU);
+
+    if (_contentStoreLRU_Init(storeImpl->_privateData, config, logger)) {
+      storeImpl->putContent = &_contentStoreLRU_PutContent;
+      storeImpl->removeContent = &_contentStoreLRU_RemoveContent;
+
+      storeImpl->matchInterest = &_contentStoreLRU_MatchInterest;
+
+      storeImpl->getObjectCount = &_contentStoreLRU_GetObjectCount;
+      storeImpl->getObjectCapacity = &_contentStoreLRU_GetObjectCapacity;
+
+      storeImpl->log = &_contentStoreLRU_Log;
+
+      storeImpl->acquire = &_contentStoreLRU_Acquire;
+      storeImpl->release = &_contentStoreLRU_Release;
+
+      // Initialize from the config passed to us.
+      _contentStoreLRU_SetObjectCapacity(storeImpl, config->objectCapacity);
+
+      if (logger_IsLoggable(logger, LoggerFacility_Processor,
+                            PARCLogLevel_Info)) {
+        logger_Log(logger, LoggerFacility_Processor, PARCLogLevel_Info,
+                   __func__, "ContentStoreLRU %p created with capacity %zu",
+                   (void *)storeImpl,
+                   contentStoreInterface_GetObjectCapacity(storeImpl));
+      }
+    }
+  } else {
+    parcObject_Release((void **)&storeImpl);
+  }
+
+  return storeImpl;
+}
diff --git a/hicn-light/src/content_store/contentStoreLRU.h b/hicn-light/src/content_store/contentStoreLRU.h
new file mode 100755 (executable)
index 0000000..3c0815e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2019 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 contentStoreLRU_h
+#define contentStoreLRU_h
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/core/logger.h>
+#include <stdio.h>
+
+/**
+ * Create and Initialize an instance of contentStoreLRU. A newly allocated
+ * {@link ContentStoreInterface} object is initialized and returned. It must
+ * eventually be released by calling {@link contentStoreInterface_Release}.
+ *
+ *
+ * @param config An instance of `ContentStoreConfig`, specifying options to be
+ * applied by the underlying contentStoreLRU instance.
+ * @param logger An instance of a {@link Logger} to use for logging content
+ * store events.
+ *
+ * @return a newly created contentStoreLRU instance.
+ *
+ */
+ContentStoreInterface *contentStoreLRU_Create(ContentStoreConfig *config,
+                                              Logger *logger);
+#endif  // contentStoreLRU_h
diff --git a/hicn-light/src/content_store/listLRU.c b/hicn-light/src/content_store/listLRU.c
new file mode 100755 (executable)
index 0000000..42b491d
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/queue.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/content_store/listLRU.h>
+
+struct list_lru_entry {
+  void *userData;
+
+  // always set to the list
+  ListLru *parentList;
+
+  // indicates if the Entry is currently in the list
+  bool inList;
+
+  TAILQ_ENTRY(list_lru_entry) list;
+};
+
+// this defines the TAILQ structure so we can access the tail pointer
+TAILQ_HEAD(lru_s, list_lru_entry);
+
+struct list_lru {
+  struct lru_s head;
+  size_t itemsInList;
+};
+
+void listLRU_EntryDestroy(ListLruEntry **entryPtr) {
+  parcAssertNotNull(entryPtr,
+                    "Parameter entryPtr must be non-null double pointer");
+
+  ListLruEntry *entry = *entryPtr;
+  if (entry->inList) {
+    TAILQ_REMOVE(&entry->parentList->head, entry, list);
+    parcAssertTrue(
+        entry->parentList->itemsInList > 0,
+        "Invalid state, removed entry from list, but itemsInList is 0");
+    entry->parentList->itemsInList--;
+  }
+
+  parcMemory_Deallocate((void **)&entry);
+  *entryPtr = NULL;
+}
+
+void listLRU_EntryMoveToHead(ListLruEntry *entry) {
+  parcAssertNotNull(entry, "Parameter entry must be non-null");
+
+  TAILQ_REMOVE(&entry->parentList->head, entry, list);
+  TAILQ_INSERT_HEAD(&entry->parentList->head, entry, list);
+}
+
+void *listLRU_EntryGetData(ListLruEntry *entry) { return entry->userData; }
+
+ListLru *listLRU_Create() {
+  ListLru *list = parcMemory_AllocateAndClear(sizeof(ListLru));
+  parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListLru));
+  list->itemsInList = 0;
+  TAILQ_INIT(&list->head);
+  return list;
+}
+
+void listLRU_Destroy(ListLru **lruPtr) {
+  parcAssertNotNull(lruPtr, "Parameter lruPtr must be non-null double pointer");
+
+  ListLru *lru = *lruPtr;
+
+  ListLruEntry *entry = TAILQ_FIRST(&lru->head);
+  while (entry != NULL) {
+    ListLruEntry *next = TAILQ_NEXT(entry, list);
+    listLRU_EntryDestroy(&entry);
+    entry = next;
+  }
+
+  parcMemory_Deallocate((void **)&lru);
+  *lruPtr = NULL;
+}
+
+ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data) {
+  parcAssertNotNull(lru, "Parameter lru must be non-null");
+  parcAssertNotNull(data, "Parameter data must be non-null");
+
+  ListLruEntry *entry = parcMemory_AllocateAndClear(sizeof(ListLruEntry));
+  parcAssertNotNull(entry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListLruEntry));
+  entry->userData = data;
+  entry->parentList = lru;
+  entry->inList = true;
+
+  TAILQ_INSERT_HEAD(&lru->head, entry, list);
+  lru->itemsInList++;
+
+  return entry;
+}
+
+ListLruEntry *listLRU_PopTail(ListLru *lru) {
+  parcAssertNotNull(lru, "Parameter lru must be non-null");
+
+  ListLruEntry *entry = TAILQ_LAST(&lru->head, lru_s);
+
+  if (entry) {
+    parcAssertTrue(
+        lru->itemsInList > 0,
+        "Invalid state, removed entry from list, but itemsInList is 0");
+    lru->itemsInList--;
+    TAILQ_REMOVE(&lru->head, entry, list);
+    entry->inList = false;
+  }
+
+  return entry;
+}
+
+size_t listLRU_Length(const ListLru *lru) {
+  parcAssertNotNull(lru, "Parameter lru must be non-null");
+  return lru->itemsInList;
+}
diff --git a/hicn-light/src/content_store/listLRU.h b/hicn-light/src/content_store/listLRU.h
new file mode 100755 (executable)
index 0000000..75f698b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file listLRU.h
+ * @brief Maintains an LRU for the content store
+ *
+ * An LRU list is make up of LRU entries.  The entries are bound to the list.
+ * The user of the list is reponsible for knowing when there's too many things
+ * and wants to remove one.  The LRU list will grow without bound otherwise.
+ *
+ * The LRU list is meant to be used as an auxiliary data structure, not the
+ * primary storage of data elements.
+ *
+ */
+
+#ifndef listLRU_h
+#define listLRU_h
+
+struct list_lru_entry;
+typedef struct list_lru_entry ListLruEntry;
+
+struct list_lru;
+typedef struct list_lru ListLru;
+
+/**
+ * @function lruEntry_Destroy
+ * @abstract Destroys and element.  This will also remove it from the list.
+ */
+void listLRU_EntryDestroy(ListLruEntry **entryPtr);
+
+/**
+ * @function listLRU_EntryMoveToHead
+ * @abstract move an element to head
+ */
+void listLRU_EntryMoveToHead(ListLruEntry *entry);
+
+/**
+ * @function lruEntry_GetData
+ * @abstract Returns the user-supplied opaque data when the entry was created
+ */
+void *listLRU_EntryGetData(ListLruEntry *entry);
+
+/**
+ * @function listLRU_Create
+ * @abstract Creates a new Least-Recently-Used list
+ */
+ListLru *listLRU_Create();
+
+/**
+ * @function listLRU_Destroy
+ * @abstract Destroys a list and frees all the elements in it
+ */
+void listLRU_Destroy(ListLru **listPtr);
+
+/**
+ * Returns the number of items in the list
+ *
+ * @param [in] lru An allocated ListLru
+ * @retval number The number of items in the LRU list
+ */
+size_t listLRU_Length(const ListLru *lru);
+
+/**
+ * @function listLRU_NewHeadEntry
+ * @abstract Creates a new entry for the list.  It is inserted at the head of
+ * the list.
+ */
+ListLruEntry *listLRU_NewHeadEntry(ListLru *lru, void *data);
+
+/**
+ * @function listLRU_PopTail
+ * @abstract Removes the tail element from the list and returns it to the user
+ * @discussion
+ *   Pops the tail element.  The user should examine its data to destroy their
+ *   tail object, then call <code>LruEntry_Destroy()</code> to free the
+ *   LRU entry.
+ *
+ * @return The tail element, or NULL for an empty list
+ */
+ListLruEntry *listLRU_PopTail(ListLru *list);
+#endif  // listLRU_h
diff --git a/hicn-light/src/content_store/listTimeOrdered.c b/hicn-light/src/content_store/listTimeOrdered.c
new file mode 100755 (executable)
index 0000000..44697d2
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <src/content_store/listTimeOrdered.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+
+/**
+ * A list of ContentStoreEntrys, kept in sorted order by time. The ordering is
+ * calculated by a key compare function (e.g. {@link TimeOrderList_KeyCompare}),
+ * passed in.
+ *
+ * This container does not hold references to the objects that it contains. In
+ * other words, it does not Acquire() the Messages that are placed in it. That
+ * reference count is managed by the owning ContentStore. This is purely an
+ * index, and provides an easy to way index Messages based on a specified time
+ * value. Typically, that would be the Expiration Time.
+ *
+ * It maintains a tree, sorted by the time values passed in to the Add()
+ * function. It does not manage capacity, and can grow uncontrollably if the
+ * owning ContentStore does not manage it. Items are indexed first by time, then
+ * address of the Message (just as a distringuishing attribute). This allows us
+ * to store multiple items with the same expiration time.
+ */
+
+struct list_timeordered {
+  PARCTreeRedBlack *timeOrderedTree;
+};
+
+static void _finalRelease(ListTimeOrdered **listP) {
+  ListTimeOrdered *list = *listP;
+  parcTreeRedBlack_Destroy(&list->timeOrderedTree);
+}
+
+parcObject_ExtendPARCObject(ListTimeOrdered, _finalRelease, NULL, NULL, NULL,
+                            NULL, NULL, NULL);
+
+parcObject_ImplementAcquire(listTimeOrdered, ListTimeOrdered);
+
+parcObject_ImplementRelease(listTimeOrdered, ListTimeOrdered);
+
+ListTimeOrdered *listTimeOrdered_Create(
+    TimeOrderList_KeyCompare *keyCompareFunction) {
+  ListTimeOrdered *result = parcObject_CreateInstance(ListTimeOrdered);
+  if (NULL != result) {
+    result->timeOrderedTree =
+        parcTreeRedBlack_Create(keyCompareFunction,  // keyCompare
+                                NULL,                // keyFree
+                                NULL,                // keyCopy
+                                NULL,                // valueEquals
+                                NULL,                // valueFree
+                                NULL);               // valueCopy
+  }
+  return result;
+}
+
+void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *entry) {
+  parcTreeRedBlack_Insert(list->timeOrderedTree, entry, entry);
+}
+
+ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list) {
+  return parcTreeRedBlack_FirstKey(list->timeOrderedTree);
+}
+
+bool listTimeOrdered_Remove(ListTimeOrdered *list,
+                            ContentStoreEntry *storeEntry) {
+  bool result = false;
+
+  ContentStoreEntry *entry = (ContentStoreEntry *)parcTreeRedBlack_Remove(
+      list->timeOrderedTree, storeEntry);
+  if (entry != NULL) {
+    result = true;
+  }
+  return result;
+}
+
+size_t listTimeOrdered_Length(ListTimeOrdered *list) {
+  return (size_t)parcTreeRedBlack_Size(list->timeOrderedTree);
+}
diff --git a/hicn-light/src/content_store/listTimeOrdered.h b/hicn-light/src/content_store/listTimeOrdered.h
new file mode 100755 (executable)
index 0000000..b18bd16
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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 listTimeOrdered_h
+#define listTimeOrdered_h
+
+#include <parc/algol/parc_TreeRedBlack.h>
+#include <src/content_store/contentStoreEntry.h>
+#include <src/core/message.h>
+#include <stdio.h>
+
+struct list_timeordered;
+typedef struct list_timeordered ListTimeOrdered;
+
+/**
+ * A signum function that takes two instances of ContentStoreEntrys and
+ * returns a value based on their relative values.
+ */
+typedef PARCTreeRedBlack_KeyCompare TimeOrderList_KeyCompare;
+
+/**
+ * Create a new instance of `ListTimeOrdered` that will maintain the order of
+ * its list items using the supplied `keyCompareFunction`.
+ *
+ * The newly created `ListTimeOrdered` must eventually be released by calling
+ * {@link listTimeOrdered_Release}.
+ *
+ * @param keyCompareFunction the signum comparison function to use to sort
+ * stored items.
+ * @return a new instance of `TimeOrderList`.
+ * @return NULL if the new instance couldn't be created.
+ *
+ */
+ListTimeOrdered *listTimeOrdered_Create(
+    TimeOrderList_KeyCompare *keyCompareFunction);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ */
+void listTimeOrdered_Release(ListTimeOrdered **listP);
+
+/**
+ * Add a {@link ContentStoreEntry} instance to the specified list. Note that a
+ * new refernece to the specified `storeEntry` is not acquired.
+ *
+ * @param list the list instance into which to add the specified storeEntry.
+ * @param storeEntry the storeEntry instance to add.
+ *
+ */
+void listTimeOrdered_Add(ListTimeOrdered *list, ContentStoreEntry *storeEntry);
+
+/**
+ * Remove a {@link ContentStoreEntry} instance from the specified list.
+ *
+ * @param list the list instance from which to remove the specified storeEntry.
+ * @param storeEntry the storeEntry instance to remove.
+ * @return true if the removal was succesful.
+ * @return false if the removal was not succesful.
+ *
+ */
+bool listTimeOrdered_Remove(ListTimeOrdered *list,
+                            ContentStoreEntry *storeEntry);
+
+/**
+ * Return the oldest {@link ContentStoreEntry} instance in this list. That is,
+ * the one with the smallest time value.
+ *
+ * @param list the list instance from which to retrieve the oldest storeEntry.
+ * @param the oldest `ContentStoreEntry` in the list
+ * @param NULL if no `ContentStoreEntry` was available.
+ *
+ */
+ContentStoreEntry *listTimeOrdered_GetOldest(ListTimeOrdered *list);
+
+/**
+ * Return the number of items currently stored in the list.
+ *
+ * @param list the `ListTimeOrdered` instance from which to retrieve the count.
+ * @return the number of items in the list.
+ *
+ */
+size_t listTimeOrdered_Length(ListTimeOrdered *list);
+#endif /* defined(listTimeOrdered_h) */
diff --git a/hicn-light/src/core/CMakeLists.txt b/hicn-light/src/core/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1d7dc03
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/ticks.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/connection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/logger.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/message.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/messagePacketType.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/system.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/wldr.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/messageHandler.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/connection.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionList.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionManager.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/connectionTable.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/forwarder.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/logger.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/message.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/numberSet.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/streamBuffer.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/mapMe.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/wldr.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/nameBitvector.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/core/connection.c b/hicn-light/src/core/connection.c
new file mode 100755 (executable)
index 0000000..073b726
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017-2019 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 <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/core/connection.h>
+#include <src/core/messageHandler.h>
+#include <src/core/ticks.h>
+#include <src/core/wldr.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+struct connection {
+  const AddressPair *addressPair;
+  IoOperations *ops;
+
+  unsigned refCount;
+
+  bool probing_active;
+  unsigned probing_interval;
+  unsigned counter;
+  Ticks last_sent;
+  Ticks delay;
+
+  bool wldrAutoStart;  // if true, wldr can be set automatically
+                       // by default this value is set to true.
+                       // if wldr is activated using a command (config
+                       // file/hicnLightControl) this value is set to false so
+                       // that a base station can not disable wldr at the client
+  Wldr *wldr;
+};
+
+Connection *connection_Create(IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  Connection *conn = parcMemory_AllocateAndClear(sizeof(Connection));
+  parcAssertNotNull(conn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Connection));
+  conn->addressPair = ioOperations_GetAddressPair(ops);
+  conn->ops = ops;
+  conn->refCount = 1;
+  conn->wldr = NULL;
+  conn->probing_active = false;
+
+  conn->wldrAutoStart = true;
+  conn->probing_interval = 0;
+  conn->counter = 0;
+  conn->last_sent = 0;
+  conn->delay = INT_MAX;
+  return conn;
+}
+
+Connection *connection_Acquire(Connection *connection) {
+  parcAssertNotNull(connection, "Parameter conn must be non-null");
+  connection->refCount++;
+  return connection;
+}
+
+void connection_Release(Connection **connectionPtr) {
+  parcAssertNotNull(connectionPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*connectionPtr,
+                    "Parameter must dereference to non-null pointer");
+  Connection *conn = *connectionPtr;
+
+  parcAssertTrue(
+      conn->refCount > 0,
+      "Invalid state, connection reference count should be positive, got 0.");
+  conn->refCount--;
+  if (conn->refCount == 0) {
+    // don't destroy addressPair, its part of ops.
+    ioOperations_Release(&conn->ops);
+    if (conn->wldr != NULL) {
+      wldr_Destroy(&(conn->wldr));
+    }
+    parcMemory_Deallocate((void **)&conn);
+  }
+  *connectionPtr = NULL;
+}
+
+bool connection_Send(const Connection *conn, Message *message) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  if (ioOperations_IsUp(conn->ops)) {
+    if (message_GetType(message) == MessagePacketType_ContentObject) {
+      uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
+      message_UpdatePathLabel(message, connectionId);
+    }
+    if (conn->wldr != NULL) {
+      wldr_SetLabel(conn->wldr, message);
+    } else {
+      message_ResetWldrLabel(message);
+    }
+    return ioOperations_Send(conn->ops, NULL, message);
+  }
+  return false;
+}
+
+static void _sendProbe(Connection *conn, unsigned probeType, uint8_t *message) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+
+  if (probeType == PACKET_TYPE_PROBE_REQUEST) {
+    Ticks now = ioOperations_SendProbe(conn->ops, probeType, message);
+    if (now != 0) {
+      conn->last_sent = now;
+    }
+  } else {
+    ioOperations_SendProbe(conn->ops, probeType, message);
+  }
+}
+
+void connection_Probe(Connection *conn) {
+  _sendProbe(conn, PACKET_TYPE_PROBE_REQUEST, NULL);
+}
+
+void connection_HandleProbe(Connection *conn, uint8_t *probe,
+                            Ticks actualTime) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  parcAssertNotNull(probe, "Parameter pkt must be non-null");
+
+  uint8_t probeType = messageHandler_GetProbePacketType(probe);
+  if (probeType == PACKET_TYPE_PROBE_REQUEST) {
+    _sendProbe(conn, PACKET_TYPE_PROBE_REPLY, probe);
+  } else if (probeType == PACKET_TYPE_PROBE_REPLY) {
+    Ticks delay = actualTime - conn->last_sent;
+    if (delay == 0) {
+      delay = 1;
+    }
+    if (delay < conn->delay) {
+      conn->delay = delay;
+    }
+  } else {
+    printf("receivde unkwon probe type\n");
+  }
+}
+
+uint64_t connection_GetDelay(Connection *conn) { return (uint64_t)conn->delay; }
+
+IoOperations *connection_GetIoOperations(const Connection *conn) {
+  return conn->ops;
+}
+
+unsigned connection_GetConnectionId(const Connection *conn) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  return ioOperations_GetConnectionId(conn->ops);
+}
+
+const AddressPair *connection_GetAddressPair(const Connection *conn) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  return ioOperations_GetAddressPair(conn->ops);
+}
+
+bool connection_IsUp(const Connection *conn) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  if (!conn->ops) return false;
+  return ioOperations_IsUp(conn->ops);
+}
+
+bool connection_IsLocal(const Connection *conn) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  return ioOperations_IsLocal(conn->ops);
+}
+
+const void *connection_Class(const Connection *conn) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  return ioOperations_Class(conn->ops);
+}
+
+bool connection_ReSend(const Connection *conn, Message *message,
+                       bool notification) {
+  parcAssertNotNull(conn, "Parameter conn must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  bool res = false;
+
+  if (connection_IsUp(conn)) {
+    // here the wldr header is alreay set: this message is a retransmission or a
+    // notification
+
+    // we need to recompiute the path lable since we always store a pointer to
+    // the same message if this message will be sent again to someonelse, the new
+    // path label must be computed starting from the orignal labelorignal label.
+    // Notice that we heve the same problem in case of PIT aggregation. That case
+    // is handled insied the MessageProcessor. This is specific to WLDR
+    // retransmittions. This is done only for data packets
+
+    if (message_GetType(message) == MessagePacketType_ContentObject) {
+      uint8_t connectionId = (uint8_t)connection_GetConnectionId(conn);
+      uint32_t old_path_label = message_GetPathLabel(message);
+      message_UpdatePathLabel(message, connectionId);
+
+      res = ioOperations_Send(conn->ops, NULL, message);
+
+      message_SetPathLabel(message, old_path_label);
+    } else {
+      res = ioOperations_Send(conn->ops, NULL, message);
+    }
+  }
+
+  if (notification) {
+    // the notification is never destroyed
+    message_Release(&message);
+  }
+
+  return res;
+}
+
+void connection_AllowWldrAutoStart(Connection *conn, bool allow) {
+  conn->wldrAutoStart = allow;
+}
+
+void connection_EnableWldr(Connection *conn) {
+  if (!connection_IsLocal(conn)) {
+    if (conn->wldr == NULL) {
+      printf("----------------- enable wldr\n");
+      conn->wldr = wldr_Init();
+    }
+  }
+}
+
+void connection_DisableWldr(Connection *conn) {
+  if (!connection_IsLocal(conn)) {
+    if (conn->wldr != NULL) {
+      printf("----------------- disable wldr\n");
+      wldr_Destroy(&(conn->wldr));
+      conn->wldr = NULL;
+    }
+  }
+}
+
+bool connection_HasWldr(const Connection *conn) {
+  if (conn->wldr == NULL) {
+    return false;
+  } else {
+    return true;
+  }
+}
+
+bool connection_WldrAutoStartAllowed(const Connection *conn) {
+  return conn->wldrAutoStart;
+}
+
+void connection_DetectLosses(Connection *conn, Message *message) {
+  if (conn->wldr != NULL) wldr_DetectLosses(conn->wldr, conn, message);
+}
+
+void connection_HandleWldrNotification(Connection *conn, Message *message) {
+  if (conn->wldr != NULL)
+    wldr_HandleWldrNotification(conn->wldr, conn, message);
+}
diff --git a/hicn-light/src/core/connection.h b/hicn-light/src/core/connection.h
new file mode 100755 (executable)
index 0000000..b5c7035
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file connection.h
+ * @brief Wrapper for different types of connections
+ *
+ * A connection wraps a specific set of {@link IoOperations}.  Those operations
+ * allow for input and output.  Connections get stored in the Connection Table.
+ *
+ */
+
+#ifndef connection_h
+#define connection_h
+#include <src/config.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+// packet types for probing
+#define PACKET_TYPE_PROBE_REQUEST 5
+#define PACKET_TYPE_PROBE_REPLY 6
+
+struct connection;
+typedef struct connection Connection;
+
+/**
+ * Creates a connection object.
+ */
+Connection *connection_Create(IoOperations *ops);
+
+/**
+ * @function connection_Release
+ * @abstract Releases a reference count, destroying on last release
+ * @discussion
+ *   Only frees the memory on the final reference count.  The pointer will
+ *   always be NULL'd.
+ */
+void connection_Release(Connection **connectionPtr);
+
+/**
+ * @function connection_Acquire
+ * @abstract A reference counted copy.
+ * @discussion
+ *   A shallow copy, they share the same memory.
+ */
+Connection *connection_Acquire(Connection *connection);
+
+/**
+ * @function connection_Send
+ * @abstract Sends the message on the connection
+ * @return true if message sent, false if connection not up
+ */
+bool connection_Send(const Connection *conn, Message *message);
+
+/**
+ * Return the `IoOperations` instance associated with the specified `Connection`
+ * instance.
+ * @param [in] connection The allocated connection
+ * @return a pointer to the IoOperations instance associated by th specified
+ * connection.
+ */
+IoOperations *connection_GetIoOperations(const Connection *conn);
+
+/**
+ * Returns the unique identifier of the connection
+ * Calls the underlying IoOperations to fetch the connection id
+ * @param [in] connection The allocated connection
+ * @return unsigned The unique connection id
+ */
+unsigned connection_GetConnectionId(const Connection *conn);
+
+/**
+ * Returns the (remote, local) address pair that describes the connection
+ * @param [in] connection The allocated connection
+ * @return non-null The connection's remote and local address
+ * @return null Should never return NULL
+ */
+const AddressPair *connection_GetAddressPair(const Connection *conn);
+
+/**
+ * Checks if the connection is in the "up" state
+ * @param [in] connection The allocated connection
+ * @return true The connection is in the "up" state
+ * @return false The connection is not in the "up" state
+ */
+bool connection_IsUp(const Connection *conn);
+
+/**
+ * Checks if the connection is to a Local/Loopback address
+ *
+ * A local connection is PF_LOCAL (PF_UNIX) and a loopback connection is
+ * 127.0.0.0/8 or ::1 for IPv6.
+ *
+ * @param [in] connection The allocated connection
+ *
+ * @retval true The connection is local or loopback
+ * @retval false The connection is not local or loopback
+ */
+bool connection_IsLocal(const Connection *conn);
+
+/**
+ * Returns an opaque pointer representing the class of the Io Operations
+ *
+ * Returns an opaque pointer that an implementation can use to detect if
+ * the connection is based on that class.
+ *
+ * @param [in] conn The Connection to analyze
+ *
+ * @return non-null An opaque pointer for each concrete implementation
+ */
+const void *connection_Class(const Connection *conn);
+
+bool connection_ReSend(const Connection *conn, Message *message,
+                       bool notification);
+
+void connection_Probe(Connection *conn);
+
+void connection_HandleProbe(Connection *conn, uint8_t *message,
+                            Ticks actualTime);
+
+uint64_t connection_GetDelay(Connection *conn);
+
+void connection_AllowWldrAutoStart(Connection *conn, bool allow);
+
+void connection_EnableWldr(Connection *conn);
+
+void connection_DisableWldr(Connection *conn);
+
+bool connection_HasWldr(const Connection *conn);
+
+bool connection_WldrAutoStartAllowed(const Connection *conn);
+
+void connection_DetectLosses(Connection *conn, Message *message);
+
+void connection_HandleWldrNotification(Connection *conn, Message *message);
+#endif  // connection_h
diff --git a/hicn-light/src/core/connectionList.c b/hicn-light/src/core/connectionList.c
new file mode 100755 (executable)
index 0000000..b2913fa
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connectionList.h>
+
+struct connection_list {
+  PARCArrayList *listOfConnections;
+};
+
+static void connectionList_ArrayDestroyer(void **voidPtr) {
+  Connection **entryPtr = (Connection **)voidPtr;
+  connection_Release(entryPtr);
+}
+
+ConnectionList *connectionList_Create() {
+  ConnectionList *list = parcMemory_AllocateAndClear(sizeof(ConnectionList));
+  parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ConnectionList));
+  list->listOfConnections = parcArrayList_Create(connectionList_ArrayDestroyer);
+  return list;
+}
+
+void connectionList_Destroy(ConnectionList **listPtr) {
+  parcAssertNotNull(listPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+  ConnectionList *list = *listPtr;
+  parcArrayList_Destroy(&list->listOfConnections);
+  parcMemory_Deallocate((void **)&list);
+  *listPtr = NULL;
+}
+
+void connectionList_Append(ConnectionList *list, Connection *entry) {
+  parcAssertNotNull(list, "Parameter list must be non-null");
+  parcAssertNotNull(entry, "Parameter entry must be non-null");
+
+  parcArrayList_Add(list->listOfConnections, connection_Acquire(entry));
+}
+
+size_t connectionList_Length(const ConnectionList *list) {
+  parcAssertNotNull(list, "Parameter list must be non-null");
+  return parcArrayList_Size(list->listOfConnections);
+}
+
+Connection *connectionList_Get(ConnectionList *list, size_t index) {
+  parcAssertNotNull(list, "Parameter list must be non-null");
+  Connection *original =
+      (Connection *)parcArrayList_Get(list->listOfConnections, index);
+  return original;
+}
diff --git a/hicn-light/src/core/connectionList.h b/hicn-light/src/core/connectionList.h
new file mode 100755 (executable)
index 0000000..cdca129
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file connectionList.h
+ * @brief A typesafe list of Connection objects
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef connectionList_h
+#define connectionList_h
+
+struct connection_list;
+typedef struct connection_list ConnectionList;
+
+#include <src/core/connection.h>
+
+/**
+ * Creates a lis of Connection
+ *
+ * @return non-null An allocated list
+ * @return null An error
+ */
+ConnectionList *connectionList_Create(void);
+
+/**
+ * Destroys the list and all objects inside it
+ */
+void connectionList_Destroy(ConnectionList **listPtr);
+
+/**
+ * @function connectionList_Append
+ * @abstract Adds a connection entry to the list.
+ * @discussion
+ *   Acquires a reference to the passed entry and stores it in the list.
+ */
+void connectionList_Append(ConnectionList *list, Connection *entry);
+
+/**
+ * Returns the number of items on the list
+ * @param [in] list The allocated list to check
+ * @return number The number of items on the list
+ */
+size_t connectionList_Length(const ConnectionList *list);
+
+/**
+ * @function connectionList_Get
+ * @abstract Returns the connection entry.
+ * @discussion
+ *   Caller must not destroy the returned value.  If you will store the
+ *   entry in your own data structure, you should acquire your own reference.
+ *   Will assert if you go beyond the end of the list.
+ *
+ */
+Connection *connectionList_Get(ConnectionList *list, size_t index);
+#endif  // connectionList_h
diff --git a/hicn-light/src/core/connectionManager.c b/hicn-light/src/core/connectionManager.c
new file mode 100755 (executable)
index 0000000..2089e14
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * The Connection Manager sets itself up as a listener to the Messenger so it
+ * can take action based on system events.
+ *
+ * The Connection Manager queues and then processes in a later time slice the
+ * messages.
+ *
+ */
+
+#include <src/config.h>
+#include <src/core/connectionManager.h>
+#include <src/core/forwarder.h>
+#include <src/messenger/messenger.h>
+#include <src/messenger/messengerRecipient.h>
+#include <src/messenger/missiveDeque.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct connection_manager {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  MessengerRecipient *messengerRecipient;
+
+  // we queue missives as they come in to process in our own
+  // event timeslice
+  MissiveDeque *missiveQueue;
+
+  // for deferred queue processing
+  PARCEventTimer *timerEvent;
+};
+
+/**
+ * Receives missives from the messenger, queues them, and schedules our
+ * execution
+ *
+ * We defer processing of missives to a later time slice
+ */
+static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
+                                                Missive *missive);
+
+/**
+ * Event callback
+ *
+ * This is our main run loop to process our queue of messages.  It is scheduled
+ * in {@link connectionManager_MessengerCallback} when the queue becomes
+ * non-empty.
+ *
+ * When we are called here, we have exclusive use of the system, so we will not
+ * create any message loops
+ *
+ * @param [in] fd unused, required for compliance with function prototype
+ * @param [in] which_event unused, required for compliance with function
+ * prototype
+ * @param [in] connManagerVoidPtr A void* to ConnectionManager
+ *
+ */
+static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
+                                           void *connManagerVoidPtr);
+
+static void connectionManager_ProcessClosedMissive(
+    ConnectionManager *connManager, const Missive *missive);
+
+// ========================================================
+// Public API
+
+ConnectionManager *connectionManager_Create(Forwarder *forwarder) {
+  ConnectionManager *connManager =
+      parcMemory_AllocateAndClear(sizeof(ConnectionManager));
+  parcAssertNotNull(connManager,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ConnectionManager));
+  connManager->forwarder = forwarder;
+  connManager->missiveQueue = missiveDeque_Create();
+  connManager->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
+
+  // creates the timer, but does not start it
+  PARCEventScheduler *base =
+      dispatcher_GetEventScheduler(forwarder_GetDispatcher(forwarder));
+  connManager->timerEvent = parcEventTimer_Create(
+      base, 0, connectionManager_ProcessQueue, connManager);
+
+  connManager->messengerRecipient = messengerRecipient_Create(
+      connManager, connectionManager_MessengerCallback);
+  messenger_Register(messenger, connManager->messengerRecipient);
+  return connManager;
+}
+
+void connectionManager_Destroy(ConnectionManager **managerPtr) {
+  parcAssertNotNull(managerPtr, "Double pointer must be non-null");
+  parcAssertNotNull(*managerPtr, "Double pointer must dereference to non-null");
+
+  ConnectionManager *connManager = *managerPtr;
+
+  Messenger *messenger = forwarder_GetMessenger(connManager->forwarder);
+  parcEventTimer_Destroy(&(connManager->timerEvent));
+  messenger_Unregister(messenger, connManager->messengerRecipient);
+  messengerRecipient_Destroy(&connManager->messengerRecipient);
+  missiveDeque_Release(&connManager->missiveQueue);
+  logger_Release(&connManager->logger);
+
+  parcMemory_Deallocate((void **)&connManager);
+  *managerPtr = NULL;
+}
+
+// ========================================================
+// Internal Functions
+
+static void connectionManager_MessengerCallback(MessengerRecipient *recipient,
+                                                Missive *missive) {
+  ConnectionManager *connManager =
+      messengerRecipient_GetRecipientContext(recipient);
+
+  // we do not release our reference count, we store it until later
+  // We are called with our own reference, so we do not need to acquire the
+  // missive here.
+  missiveDeque_Append(connManager->missiveQueue, missive);
+
+  if (missiveDeque_Size(connManager->missiveQueue) == 1) {
+    // When it becomes non-empty, schedule {@link
+    // connectionManager_ProcessQueue}
+    struct timeval immediateTimeout = {0, 0};
+    parcEventTimer_Start(connManager->timerEvent, &immediateTimeout);
+  }
+}
+
+static void connectionManager_ProcessQueue(int fd, PARCEventType which_event,
+                                           void *connManagerVoidPtr) {
+  ConnectionManager *connManager = (ConnectionManager *)connManagerVoidPtr;
+
+  Missive *missive;
+  while ((missive = missiveDeque_RemoveFirst(connManager->missiveQueue)) !=
+         NULL) {
+    switch (missive_GetType(missive)) {
+      case MissiveType_ConnectionCreate:
+        // hook to signal that a new connection was created
+        break;
+      case MissiveType_ConnectionUp:
+        // hook to signal that a new connection is up
+        break;
+      case MissiveType_ConnectionDown:
+        // hook to signal that a connection is down
+        break;
+      case MissiveType_ConnectionClosed:
+        connectionManager_ProcessClosedMissive(connManager, missive);
+        break;
+      case MissiveType_ConnectionDestroyed:
+        // hook to signal that a connection was destroyed
+        break;
+      default:
+        parcTrapUnexpectedState("Missive %p of unknown type: %d",
+                                (void *)missive, missive_GetType(missive));
+    }
+    missive_Release(&missive);
+  }
+}
+
+static void connectionManager_ProcessClosedMissive(
+    ConnectionManager *connManager, const Missive *missive) {
+  logger_Log(connManager->logger, LoggerFacility_Core, PARCLogLevel_Debug,
+             __func__, "Processing CLOSED message for connid %u",
+             missive_GetConnectionId(missive));
+
+  ConnectionTable *table = forwarder_GetConnectionTable(connManager->forwarder);
+  const Connection *conn =
+      connectionTable_FindById(table, missive_GetConnectionId(missive));
+
+  if (conn) {
+    // this will destroy the connection if its the last reference count
+    connectionTable_Remove(table, conn);
+
+    // remove from FIB
+    forwarder_RemoveConnectionIdFromRoutes(connManager->forwarder,
+                                           missive_GetConnectionId(missive));
+  }
+}
diff --git a/hicn-light/src/core/connectionManager.h b/hicn-light/src/core/connectionManager.h
new file mode 100755 (executable)
index 0000000..b77553e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file connectionManager.h
+ * @brief The connection manager handles connection events, such as going down
+ *
+ * The connection manager listens to the event notification system.  Based on
+ * those events, the connection manager will take specific actions.  This is
+ * expected to be a singleton instantiated by the forwarder.
+ *
+ */
+
+#ifndef connectionManager_h
+#define connectionManager_h
+
+#include <src/core/forwarder.h>
+
+struct connection_manager;
+typedef struct connection_manager ConnectionManager;
+
+ConnectionManager *connectionManager_Create(Forwarder *forwarder);
+
+void connectionManager_Destroy(ConnectionManager **managerPtr);
+#endif  // connectionManager_h
diff --git a/hicn-light/src/core/connectionTable.c b/hicn-light/src/core/connectionTable.c
new file mode 100755 (executable)
index 0000000..ba0942d
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @header ConnectionTable
+ * @abstract Records all the current connections and references to them
+ * @discussion
+ *
+ */
+
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_TreeRedBlack.h>
+#include <src/core/connectionTable.h>
+#include <src/io/addressPair.h>
+
+struct connection_table {
+  // The main storage table that has a Destroy method.
+  // The key is an unsigned int pointer.  We use an unsigned int pointer
+  // because we want to be able to lookup by the id alone, and not have to
+  // have the IoOperations everywhere.
+  PARCHashCodeTable *storageTableById;
+
+  // The key is a AddressPair
+  // It does not have a destroy method for the data or key,
+  // as they are derived from the storage table.
+  PARCHashCodeTable *indexByAddressPair;
+
+  // An iterable stucture organized by connection id.  The keys and
+  // values are the same pointers as in storageTableById, so there
+  // are no destructors in the tree.
+  // The only reason to keep this tree is so we have an iterable list
+  // of connections, which the hash table does not give us.
+  PARCTreeRedBlack *listById;
+};
+
+static bool connectionTable_ConnectionIdEquals(const void *keyA,
+                                               const void *keyB) {
+  unsigned idA = *((unsigned *)keyA);
+  unsigned idB = *((unsigned *)keyB);
+  return (idA == idB);
+}
+
+static int connectionTable_ConnectionIdCompare(const void *keyA,
+                                               const void *keyB) {
+  unsigned idA = *((unsigned *)keyA);
+  unsigned idB = *((unsigned *)keyB);
+  if (idA < idB) {
+    return -1;
+  }
+  if (idA > idB) {
+    return +1;
+  }
+  return 0;
+}
+
+static bool connectionTable_AddressPairEquals(const void *keyA,
+                                              const void *keyB) {
+  const AddressPair *pairA = (const AddressPair *)keyA;
+  const AddressPair *pairB = (const AddressPair *)keyB;
+
+  return addressPair_Equals(pairA, pairB);
+}
+
+static HashCodeType connectionTable_ConnectionIdHashCode(const void *keyA) {
+  unsigned idA = *((unsigned *)keyA);
+  return parcHash32_Int32(idA);
+}
+
+static HashCodeType connectionTable_AddressPairHashCode(const void *keyA) {
+  const AddressPair *pairA = (const AddressPair *)keyA;
+  return addressPair_HashCode(pairA);
+}
+
+static void connectionTable_ConnectionIdDestroyer(void **dataPtr) {
+  unsigned *idA = (unsigned *)*dataPtr;
+  parcMemory_Deallocate((void **)&idA);
+  *dataPtr = NULL;
+}
+
+static void connectionTable_ConnectionDestroyer(void **dataPtr) {
+  connection_Release((Connection **)dataPtr);
+}
+
+ConnectionTable *connectionTable_Create() {
+  size_t initialSize = 16384;
+
+  ConnectionTable *conntable =
+      parcMemory_AllocateAndClear(sizeof(ConnectionTable));
+  parcAssertNotNull(conntable, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ConnectionTable));
+
+  conntable->storageTableById = parcHashCodeTable_Create_Size(
+      connectionTable_ConnectionIdEquals, connectionTable_ConnectionIdHashCode,
+      connectionTable_ConnectionIdDestroyer,
+      connectionTable_ConnectionDestroyer, initialSize);
+
+  // no key or data destroyer, this is an index into storageByid.
+  conntable->indexByAddressPair = parcHashCodeTable_Create_Size(
+      connectionTable_AddressPairEquals, connectionTable_AddressPairHashCode,
+      NULL, NULL, initialSize);
+
+  conntable->listById =
+      parcTreeRedBlack_Create(connectionTable_ConnectionIdCompare,
+                              NULL,   // key free
+                              NULL,   // key copy
+                              NULL,   // value equals
+                              NULL,   // value free
+                              NULL);  // value copy
+
+  return conntable;
+}
+
+void connectionTable_Destroy(ConnectionTable **conntablePtr) {
+  parcAssertNotNull(conntablePtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*conntablePtr,
+                    "Parameter must dereference to non-null pointer");
+
+  ConnectionTable *conntable = *conntablePtr;
+
+  parcTreeRedBlack_Destroy(&conntable->listById);
+  parcHashCodeTable_Destroy(&conntable->indexByAddressPair);
+  parcHashCodeTable_Destroy(&conntable->storageTableById);
+  parcMemory_Deallocate((void **)&conntable);
+  *conntablePtr = NULL;
+}
+
+/**
+ * @function connectionTable_Add
+ * @abstract Add a connection, takes ownership of memory
+ */
+void connectionTable_Add(ConnectionTable *table, Connection *connection) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(connection, "Parameter connection must be non-null");
+
+  unsigned *connectionIdKey = parcMemory_Allocate(sizeof(unsigned));
+  parcAssertNotNull(connectionIdKey, "parcMemory_Allocate(%zu) returned NULL",
+                    sizeof(unsigned));
+  *connectionIdKey = connection_GetConnectionId(connection);
+
+  if (parcHashCodeTable_Add(table->storageTableById, connectionIdKey,
+                            connection)) {
+    parcHashCodeTable_Add(table->indexByAddressPair,
+                          (void *)connection_GetAddressPair(connection),
+                          connection);
+    parcTreeRedBlack_Insert(table->listById, connectionIdKey, connection);
+  } else {
+    parcTrapUnexpectedState(
+        "Could not add connection id %u -- is it a duplicate?",
+        *connectionIdKey);
+  }
+}
+
+/**
+ * @function connectionTable_Remove
+ * @abstract Removes the connection, calling Destroy on our copy
+ */
+void connectionTable_Remove(ConnectionTable *table,
+                            const Connection *connection) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  parcAssertNotNull(connection, "Parameter connection must be non-null");
+
+  unsigned connid = connection_GetConnectionId(connection);
+
+  parcTreeRedBlack_Remove(table->listById, &connid);
+  parcHashCodeTable_Del(table->indexByAddressPair,
+                        connection_GetAddressPair(connection));
+  parcHashCodeTable_Del(table->storageTableById, &connid);
+}
+
+void connectionTable_RemoveById(ConnectionTable *table, unsigned id) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  const Connection *connection = connectionTable_FindById(table, id);
+  if (connection) {
+    connectionTable_Remove(table, connection);
+  }
+}
+
+const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
+                                                    const AddressPair *pair) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  return (Connection *)parcHashCodeTable_Get(table->indexByAddressPair, pair);
+}
+
+const Connection *connectionTable_FindById(ConnectionTable *table,
+                                           unsigned id) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  return (Connection *)parcHashCodeTable_Get(table->storageTableById, &id);
+}
+
+ConnectionList *connectionTable_GetEntries(const ConnectionTable *table) {
+  parcAssertNotNull(table, "Parameter table must be non-null");
+  ConnectionList *list = connectionList_Create();
+
+  PARCArrayList *values = parcTreeRedBlack_Values(table->listById);
+  for (size_t i = 0; i < parcArrayList_Size(values); i++) {
+    Connection *original = parcArrayList_Get(values, i);
+    connectionList_Append(list, original);
+  }
+  parcArrayList_Destroy(&values);
+  return list;
+}
diff --git a/hicn-light/src/core/connectionTable.h b/hicn-light/src/core/connectionTable.h
new file mode 100755 (executable)
index 0000000..30517ae
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017-2019 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 connectionTable_h
+#define connectionTable_h
+
+#include <src/core/connection.h>
+#include <src/core/connectionList.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+
+struct connection_table;
+typedef struct connection_table ConnectionTable;
+
+/**
+ * Creates an empty connection table
+ */
+ConnectionTable *connectionTable_Create(void);
+
+/**
+ * Destroys the connection table
+ * This will release the reference to all connections stored in the connection
+ * table.
+ * @param [in,out] conntablePtr Pointer to the allocated connection table, will
+ * be NULL'd
+ */
+void connectionTable_Destroy(ConnectionTable **conntablePtr);
+
+/**
+ * @function connectionTable_Add
+ * @abstract Add a connection, takes ownership of memory
+ */
+void connectionTable_Add(ConnectionTable *table, Connection *connection);
+
+/**
+ * @function connectionTable_Remove
+ * @abstract Removes the connection, calling Destroy on our copy
+ */
+void connectionTable_Remove(ConnectionTable *table,
+                            const Connection *connection);
+
+/**
+ * Removes a connection from the connection table
+ *
+ * Looks up a connection by its connection ID and removes it from the connection
+ * table. Removing the connection will call connection_Release() on the
+ * connection object.
+ *
+ * @param [in] table The allocated connection table
+ * @param [in] id The connection ID
+ */
+void connectionTable_RemoveById(ConnectionTable *table, unsigned id);
+
+/**
+ * Lookup a connection by the (local, remote) addres pair
+ *
+ * @param [in] table The allocated connection table
+ * @param [in] pair The address pair to match, based on the inner values of the
+ * local and remote addresses
+ *
+ * @retval non-null The matched conneciton
+ * @retval null No match found or error
+ */
+const Connection *connectionTable_FindByAddressPair(ConnectionTable *table,
+                                                    const AddressPair *pair);
+
+/**
+ * @function connectionTable_FindById
+ * @abstract Find a connection by its numeric id.
+ * @return NULL if not found
+ */
+const Connection *connectionTable_FindById(ConnectionTable *table, unsigned id);
+
+/**
+ * @function connectionTable_GetEntries
+ * @abstract Returns a list of connections.  They are reference counted copies
+ * from the table.
+ * @discussion
+ *   An allocated list of connections in the table.  Each list entry is a
+ * reference counted copy of the connection in the table, thus they are "live"
+ * objects.
+ */
+ConnectionList *connectionTable_GetEntries(const ConnectionTable *table);
+#endif  // connectionTable_h
diff --git a/hicn-light/src/core/dispatcher.c b/hicn-light/src/core/dispatcher.c
new file mode 100755 (executable)
index 0000000..078087c
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @header dispatcher.c
+ * @abstract Event dispatcher for hicn-light.  Uses parcEvent
+ * @discussion
+ *     Wraps the functions we use in parcEvent, along with StreamBuffer and
+ * Message. The dispatcher is the event loop, so it manages things like signals,
+ * timers, and network events.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_EventTimer.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/dispatcher.h>
+
+#ifndef INPORT_ANY
+#define INPORT_ANY 0
+#endif
+
+struct dispatcher {
+  PARCEventScheduler *Base;
+  Logger *logger;
+};
+
+// ==========================================
+// Public API
+
+PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher) {
+  return dispatcher->Base;
+}
+
+Dispatcher *dispatcher_Create(Logger *logger) {
+  Dispatcher *dispatcher = parcMemory_AllocateAndClear(sizeof(Dispatcher));
+  parcAssertNotNull(dispatcher,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Dispatcher));
+
+  dispatcher->Base = parcEventScheduler_Create();
+  dispatcher->logger = logger_Acquire(logger);
+
+  parcAssertNotNull(dispatcher->Base,
+                    "Got NULL from parcEventScheduler_Create()");
+
+  return dispatcher;
+}
+
+void dispatcher_Destroy(Dispatcher **dispatcherPtr) {
+  parcAssertNotNull(dispatcherPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*dispatcherPtr,
+                    "Parameter must dereference to non-null pointer");
+  Dispatcher *dispatcher = *dispatcherPtr;
+
+  logger_Release(&dispatcher->logger);
+  parcEventScheduler_Destroy(&(dispatcher->Base));
+  parcMemory_Deallocate((void **)&dispatcher);
+  *dispatcherPtr = NULL;
+}
+
+void dispatcher_Stop(Dispatcher *dispatcher) {
+  struct timeval delay = {0, 1000};
+
+  parcEventScheduler_Stop(dispatcher->Base, &delay);
+}
+
+void dispatcher_Run(Dispatcher *dispatcher) {
+  parcAssertNotNull(dispatcher, "Parameter must be non-null");
+
+  parcEventScheduler_Start(dispatcher->Base, 0);
+}
+
+void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(duration, "Parameter duration must be non-null");
+
+  parcEventScheduler_Stop(dispatcher->Base, duration);
+  parcEventScheduler_Start(dispatcher->Base, 0);
+}
+
+void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count) {
+  parcAssertNotNull(dispatcher, "Parameter must be non-null");
+
+  for (unsigned i = 0; i < count; i++) {
+    parcEventScheduler_Start(dispatcher->Base,
+                             PARCEventSchedulerDispatchType_LoopOnce);
+  }
+}
+
+PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
+                                           PARCEventSocket_Callback *callback,
+                                           void *user_data, int backlog,
+                                           const struct sockaddr *sa,
+                                           int socklen) {
+  PARCEventSocket *listener = parcEventSocket_Create(
+      dispatcher->Base, callback, NULL, user_data, sa, socklen);
+  if (listener == NULL) {
+    perror("Problem creating listener");
+  }
+  return listener;
+}
+
+void dispatcher_DestroyListener(Dispatcher *dispatcher,
+                                PARCEventSocket **listenerPtr) {
+  parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listenerPtr,
+                    "Parameter must dereference to non-null pointer");
+  parcEventSocket_Destroy(listenerPtr);
+}
+
+PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
+                                                        SocketType fd) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  PARCEventQueue *buffer = parcEventQueue_Create(
+      dispatcher->Base, fd,
+      PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
+  parcAssertNotNull(buffer,
+                    "Got null from parcEventBufver_Create for socket %d", fd);
+  return buffer;
+}
+
+PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
+                                       PARCEvent_Callback *callback,
+                                       void *userData) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(callback, "Parameter callback must be non-null");
+
+  PARCEventType flags = 0;
+  if (isPeriodic) {
+    flags |= PARCEventType_Persist;
+  }
+  PARCEventTimer *event =
+      parcEventTimer_Create(dispatcher->Base, flags, callback, userData);
+  return event;
+}
+
+void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
+                           struct timeval *delay) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(timerEvent, "Parameter timerEvent must be non-null");
+  int failure = parcEventTimer_Start(timerEvent, delay);
+  parcAssertFalse(failure < 0, "Error starting timer event %p: (%d) %s",
+                  (void *)timerEvent, errno, strerror(errno));
+}
+
+void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *event) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(event, "Parameter event must be non-null");
+
+  int failure = parcEventTimer_Stop(event);
+  parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+                  (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
+                                  PARCEventTimer **eventPtr) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(eventPtr,
+                    "Parameter eventPtr must be non-null double pointer");
+  parcAssertNotNull(*eventPtr,
+                    "Paramter eventPtr must dereference to non-null pointer");
+
+  parcEventTimer_Destroy(eventPtr);
+  eventPtr = NULL;
+}
+
+PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
+                                         bool isPersistent,
+                                         PARCEvent_Callback *callback,
+                                         void *userData, int fd) {
+  short flags = PARCEventType_Timeout | PARCEventType_Read;
+  if (isPersistent) {
+    flags |= PARCEventType_Persist;
+  }
+
+  PARCEvent *event =
+      parcEvent_Create(dispatcher->Base, fd, flags, callback, userData);
+  parcAssertNotNull(event, "Got null from parcEvent_Create for socket %d", fd);
+  return event;
+}
+
+void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
+                                    PARCEvent **eventPtr) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(eventPtr,
+                    "Parameter eventPtr must be non-null double pointer");
+  parcAssertNotNull(*eventPtr,
+                    "Paramter eventPtr must dereference to non-null pointer");
+
+  parcEvent_Destroy(eventPtr);
+  eventPtr = NULL;
+}
+
+void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(event, "Parameter event must be non-null");
+
+  int failure = parcEvent_Start(event);
+  parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
+                  (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(event, "Parameter event must be non-null");
+
+  int failure = parcEvent_Stop(event);
+  parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+                  (void *)event, errno, strerror(errno));
+}
+
+PARCEventSignal *dispatcher_CreateSignalEvent(
+    Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
+    int signal) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(callback, "Parameter callback must be non-null");
+
+  PARCEventSignal *event = parcEventSignal_Create(
+      dispatcher->Base, signal, PARCEventType_Signal | PARCEventType_Persist,
+      callback, userData);
+  parcAssertNotNull(event,
+                    "Got null event when creating signal catcher for signal %d",
+                    signal);
+
+  return event;
+}
+
+void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
+                                   PARCEventSignal **eventPtr) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(eventPtr,
+                    "Parameter eventPtr must be non-null double pointer");
+  parcAssertNotNull(*eventPtr,
+                    "Paramter eventPtr must dereference to non-null pointer");
+
+  parcEventSignal_Destroy(eventPtr);
+  eventPtr = NULL;
+}
+
+void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
+                                 PARCEventSignal *event) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(event, "Parameter event must be non-null");
+
+  int failure = parcEventSignal_Start(event);
+  parcAssertFalse(failure < 0, "Error starting signal event %p: (%d) %s",
+                  (void *)event, errno, strerror(errno));
+}
+
+void dispatcher_StopSignalEvent(Dispatcher *dispatcher,
+                                PARCEventSignal *event) {
+  parcAssertNotNull(dispatcher, "Parameter dispatcher must be non-null");
+  parcAssertNotNull(event, "Parameter event must be non-null");
+
+  int failure = parcEventSignal_Stop(event);
+  parcAssertFalse(failure < 0, "Error stopping signal event %p: (%d) %s",
+                  (void *)event, errno, strerror(errno));
+}
+
+/**
+ * Bind to a local address/port then connect to peer.
+ */
+static bool dispatcher_StreamBufferBindAndConnect(Dispatcher *dispatcher,
+                                                  PARCEventQueue *buffer,
+                                                  struct sockaddr *localSock,
+                                                  socklen_t localSockLength,
+                                                  struct sockaddr *remoteSock,
+                                                  socklen_t remoteSockLength) {
+  // we need to bind, then connect.  Special operation, so we make our
+  // own fd then pass it off to the buffer event
+
+  int fd = socket(localSock->sa_family, SOCK_STREAM, 0);
+  if (fd < 0) {
+    perror("socket");
+    return -1;
+  }
+
+  // Set non-blocking flag
+  int flags = fcntl(fd, F_GETFL, NULL);
+  if (flags < 0) {
+    perror("F_GETFL");
+    close(fd);
+    return -1;
+  }
+  int failure = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+  if (failure) {
+    perror("F_SETFL");
+    close(fd);
+    return -1;
+  }
+
+  failure = bind(fd, localSock, localSockLength);
+  if (failure) {
+    perror("bind");
+    close(fd);
+    return false;
+  }
+
+  parcEventQueue_SetFileDescriptor(buffer, fd);
+
+  failure = parcEventQueue_ConnectSocket(buffer, remoteSock, remoteSockLength);
+  if (failure && (errno != EINPROGRESS)) {
+    perror("connect");
+    close(fd);
+    return false;
+  }
+  return true;
+}
+
+/**
+ * Connect to an INET peer
+ * @return NULL on error, otherwise a streambuffer
+ */
+static PARCEventQueue *dispatcher_StreamBufferConnect_INET(
+    Dispatcher *dispatcher, const Address *localAddress,
+    const Address *remoteAddress) {
+  struct sockaddr_in localSock, remoteSock;
+  addressGetInet(localAddress, &localSock);
+  addressGetInet(remoteAddress, &remoteSock);
+
+  PARCEventQueue *buffer = parcEventQueue_Create(
+      dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
+  parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
+
+  bool success = dispatcher_StreamBufferBindAndConnect(
+      dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
+      (struct sockaddr *)&remoteSock, sizeof(remoteSock));
+  if (!success) {
+    parcEventQueue_Destroy(&buffer);
+    buffer = NULL;
+  }
+
+  return buffer;
+}
+
+/**
+ * Connect to an INET peer
+ * @return NULL on error, otherwise a streambuffer
+ */
+static PARCEventQueue *
+// static StreamBuffer *
+dispatcher_StreamBufferConnect_INET6(Dispatcher *dispatcher,
+                                     const Address *localAddress,
+                                     const Address *remoteAddress) {
+  struct sockaddr_in6 localSock, remoteSock;
+  addressGetInet6(localAddress, &localSock);
+  addressGetInet6(remoteAddress, &remoteSock);
+
+  PARCEventQueue *buffer = parcEventQueue_Create(
+      dispatcher->Base, -1, PARCEventQueueOption_CloseOnFree);
+  parcAssertNotNull(buffer, "got null buffer from parcEventQueue_Create()");
+
+  bool success = dispatcher_StreamBufferBindAndConnect(
+      dispatcher, buffer, (struct sockaddr *)&localSock, sizeof(localSock),
+      (struct sockaddr *)&remoteSock, sizeof(remoteSock));
+  if (!success) {
+    parcEventQueue_Destroy(&buffer);
+    buffer = NULL;
+  }
+
+  return buffer;
+}
+
+PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
+                                               const AddressPair *pair) {
+  const Address *localAddress = addressPair_GetLocal(pair);
+  const Address *remoteAddress = addressPair_GetRemote(pair);
+
+  // they must be of the same address family
+  if (addressGetType(localAddress) != addressGetType(remoteAddress)) {
+    char message[2048];
+    char *localAddressString = addressToString(localAddress);
+    char *remoteAddressString = addressToString(remoteAddress);
+    snprintf(message, 2048,
+             "Remote address not same type as local address, expected %d got "
+             "%d\nlocal %s remote %s",
+             addressGetType(localAddress), addressGetType(remoteAddress),
+             localAddressString, remoteAddressString);
+
+    parcMemory_Deallocate((void **)&localAddressString);
+    parcMemory_Deallocate((void **)&remoteAddressString);
+
+    parcAssertTrue(
+        addressGetType(localAddress) == addressGetType(remoteAddress), "%s",
+        message);
+  }
+
+  address_type type = addressGetType(localAddress);
+
+  PARCEventQueue *result = NULL;
+
+  switch (type) {
+    case ADDR_INET:
+      return dispatcher_StreamBufferConnect_INET(dispatcher, localAddress,
+                                                 remoteAddress);
+      break;
+    case ADDR_INET6:
+      return dispatcher_StreamBufferConnect_INET6(dispatcher, localAddress,
+                                                  remoteAddress);
+      break;
+    default:
+      parcTrapIllegalValue(type, "local address unsupported address type: %d",
+                           type);
+  }
+  return result;
+}
diff --git a/hicn-light/src/core/dispatcher.h b/hicn-light/src/core/dispatcher.h
new file mode 100755 (executable)
index 0000000..35d804a
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @header hicn-light Dispatcher
+ * @abstract The dispatcher is the event loop run by Forwarder.
+ * @discussion
+ *     These functions manage listeners, timers, and network events inside
+ *     the event loop.
+ *
+ *     Curently, it is a thin wrapper around an event so we don't have to
+ *     expose that implementation detail to other modules.
+ *
+ */
+
+#ifndef dispatcher_h
+#define dispatcher_h
+
+#include <stdbool.h>
+#include <sys/socket.h>
+
+struct dispatcher;
+typedef struct dispatcher Dispatcher;
+
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventQueue.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_EventSignal.h>
+#include <parc/algol/parc_EventSocket.h>
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/logger.h>
+
+PARCEventScheduler *dispatcher_GetEventScheduler(Dispatcher *dispatcher);
+/**
+ * Creates an event dispatcher
+ *
+ * Event dispatcher based on PARCEvent
+ *
+ * @return non-null Allocated event dispatcher
+ * @return null An error
+ */
+Dispatcher *dispatcher_Create(Logger *logger);
+
+/**
+ * Destroys event dispatcher
+ *
+ * Caller is responsible for destroying call events before destroying
+ * the event dispatcher.
+ */
+void dispatcher_Destroy(Dispatcher **dispatcherPtr);
+
+/**
+ * @function dispatcher_Stop
+ * @abstract Called from a different thread, tells the dispatcher to stop
+ * @discussion
+ *   Called from a user thread or from an interrupt handler.
+ *   Does not block.  Use <code>dispatcher_WaitForStopped()</code> to
+ *   block until stopped after calling this.
+ */
+void dispatcher_Stop(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_WaitForStopped
+ * @abstract Blocks until dispatcher in stopped state
+ * @discussion
+ *   Used after <code>dispatcher_Stop()</code> to wait for stop.
+ */
+void dispatcher_WaitForStopped(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_Run
+ * @abstract Runs the forwarder, blocks.
+ */
+void dispatcher_Run(Dispatcher *dispatcher);
+
+/**
+ * @function dispatcher_RunDuration
+ * @abstract Runs forwarder for at most duration, blocks.
+ * @discussion
+ *   Blocks running the forwarder for a duration.  May be called
+ *   iteratively to keep running.  Duration is a minimum, actual
+ *   runtime may be slightly longer.
+ */
+void dispatcher_RunDuration(Dispatcher *dispatcher, struct timeval *duration);
+
+/**
+ * @header dispatcher_RunCount
+ * @abstract Run the event loop for the given count cycles
+ * @discussion
+ *     Runs the event loop for the given number of cycles, blocking
+ *     until done.  May be called sequentially over and over.
+ *
+ */
+void dispatcher_RunCount(Dispatcher *dispatcher, unsigned count);
+
+typedef int SocketType;
+
+typedef struct evconnlistener Listener;
+
+/**
+ * @typedef ListenerCallback
+ * @abstract Callback function typedef for a stream listener
+ *
+ * @constant listener is the object created by <code>forwarder_NewBind()</code>
+ * that received the client connection
+ * @constant client_socket is the client socket
+ * @constant user_data is the user_data passed to
+ * <code>forwarder_NewBind()</code>
+ * @constant client_addr is the client address
+ * @constant socklen is the length of client_addr
+ * @discussion <#Discussion#>
+ */
+typedef void(ListenerCallback)(Listener *listener, SocketType client_socket,
+                               struct sockaddr *client_addr, int socklen,
+                               void *user_data);
+
+/**
+ * @header forwarder_NewBind
+ * @abstract Allocate a new stream listener
+ * @discussion
+ *     The server socket will be freed when closed and will be reusable.
+ *
+ * @param forwarder that owns the event loop
+ * @param cb is the callback for a new connection
+ * @param user_data is opaque user data passed to the callback
+ * @param backlog is the listen() depth, may use -1 for a default value
+ * @param sa is the socket address to bind to (INET, INET6, LOCAL)
+ * @param socklen is the sizeof the actual sockaddr (e.g. sizeof(sockaddr_un))
+ */
+PARCEventSocket *dispatcher_CreateListener(Dispatcher *dispatcher,
+                                           PARCEventSocket_Callback *callback,
+                                           void *user_data, int backlog,
+                                           const struct sockaddr *sa,
+                                           int socklen);
+
+void dispatcher_DestroyListener(Dispatcher *dispatcher,
+                                PARCEventSocket **listenerPtr);
+
+typedef struct event TimerEvent;
+typedef struct event NetworkEvent;
+typedef struct event SignalEvent;
+
+/**
+ * @typedef EventCallback
+ * @abstract A network event or a timer callback
+ * @constant fd The file descriptor associated with the event, may be -1 for
+ * timers
+ * @constant which_event is a bitmap of the EventType
+ * @constant user_data is the user_data passed to
+ * <code>Forwarder_CreateEvent()</code>
+ */
+typedef void(EventCallback)(SocketType fd, short which_event, void *user_data);
+
+/**
+ * @function dispatcher_CreateTimer
+ * @abstract Creates a Event for use as a timer.
+ * @discussion
+ *
+ *   When created, the timer is idle and you need to call
+ * <code>forwarder_StartTimer()</code>
+ *
+ * @param isPeriodic means the timer will fire repeatidly, otherwise it is a
+ * one-shot and needs to be set again with <code>dispatcher_StartTimer()</code>
+ */
+PARCEventTimer *dispatcher_CreateTimer(Dispatcher *dispatcher, bool isPeriodic,
+                                       PARCEvent_Callback *callback,
+                                       void *userData);
+
+/**
+ * @function dispatcher_StartTimer
+ * @abstract Starts the timer with the given delay.
+ * @discussion
+ *   If the timer is periodic, it will keep firing with the given delay
+ */
+void dispatcher_StartTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent,
+                           struct timeval *delay);
+
+void dispatcher_StopTimer(Dispatcher *dispatcher, PARCEventTimer *timerEvent);
+
+/**
+ * @function dispatcher_DestroyTimerEvent
+ * @abstract Cancels the timer and frees the event
+ */
+void dispatcher_DestroyTimerEvent(Dispatcher *dispatcher,
+                                  PARCEventTimer **eventPtr);
+
+/**
+ * @function dispatcher_CreateNetworkEvent
+ * @abstract Creates a network event callback on the socket
+ * @discussion
+ *   May be used on any sort of file descriptor or socket.  The event is edge
+ * triggered and non-reentrent. This means you need to drain the events off the
+ * socket, as the callback will not be called again until a new event arrives.
+ *
+ *   When created, the event is idle and you need to call
+ * <code>forwarder_StartNetworkEvent()</code>
+ *
+ * @param isPersistent means the callback will keep firing with new events,
+ * otherwise its a one-shot
+ * @param fd is the socket to monitor
+ */
+PARCEvent *dispatcher_CreateNetworkEvent(Dispatcher *dispatcher,
+                                         bool isPersistent,
+                                         PARCEvent_Callback *callback,
+                                         void *userData, int fd);
+
+void dispatcher_StartNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
+void dispatcher_StopNetworkEvent(Dispatcher *dispatcher, PARCEvent *event);
+
+void dispatcher_DestroyNetworkEvent(Dispatcher *dispatcher,
+                                    PARCEvent **eventPtr);
+
+/**
+ * @function dispatcher_CreateSignalEvent
+ * @abstract Creates a signal trap
+ * @discussion
+ *   May be used on catchable signals.  The event is edge triggered and
+ * non-reentrent.  Signal events are persistent.
+ *
+ *   When created, the signal trap is idle and you need to call
+ * <code>forwarder_StartSignalEvent()</code>
+ *
+ * @param signal is the system signal to monitor (e.g. SIGINT).
+ * @return <#return#>
+ */
+PARCEventSignal *dispatcher_CreateSignalEvent(
+    Dispatcher *dispatcher, PARCEventSignal_Callback *callback, void *userData,
+    int signal);
+
+void dispatcher_DestroySignalEvent(Dispatcher *dispatcher,
+                                   PARCEventSignal **eventPtr);
+
+void dispatcher_StartSignalEvent(Dispatcher *dispatcher,
+                                 PARCEventSignal *event);
+void dispatcher_StopSignalEvent(Dispatcher *dispatcher, PARCEventSignal *event);
+
+// =============
+// stream buffers
+
+#include <src/core/streamBuffer.h>
+#include <src/io/addressPair.h>
+
+/**
+ * @function dispatcher_CreateStreamBuffer
+ * @abstract Creates a high-function buffer around a stream socket
+ */
+PARCEventQueue *dispatcher_CreateStreamBufferFromSocket(Dispatcher *dispatcher,
+                                                        SocketType fd);
+
+/**
+ * @function dispatcher_StreamBufferConnect
+ * @abstract Create a TCP tunnel to a remote peer
+ * @discussion
+ *   For TCP, both address pairs need to be the same address family: both INET
+ * or both INET6.  The remote address must have the complete socket information
+ * (address, port).  The local socket could be wildcarded or may specify down to
+ * the (address, port) pair.
+ *
+ *   If the local address is IPADDR_ANY and the port is 0, then it is a normal
+ * call to "connect" that will use whatever local IP address and whatever local
+ * port for the connection.  If either the address or port is set, the local
+ * socket will first be bound (via bind(2)), and then call connect().
+ *
+ *   It is unlikely that the buffer will be connected by the time the function
+ * returns.  The eventCallback will fire once the remote system accepts the
+ * conneciton.
+ *
+ * @return NULL on error, otherwise a streambuffer.
+ */
+PARCEventQueue *dispatcher_StreamBufferConnect(Dispatcher *dispatcher,
+                                               const AddressPair *pair);
+#endif  // dispatcher_h
diff --git a/hicn-light/src/core/forwarder.c b/hicn-light/src/core/forwarder.c
new file mode 100755 (executable)
index 0000000..cb94af3
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Event based router
+ *
+ * This module is the glue around the event scheduler.
+ * Its the packet i/o module.
+ *
+ * Packet processing is done in dispatcher.c, which is the actual wrapper around
+ * the event scheduler
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+
+#include <src/core/connectionManager.h>
+#include <src/core/connectionTable.h>
+#include <src/core/dispatcher.h>
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+#include <src/config/configuration.h>
+#include <src/config/configurationFile.h>
+#include <src/config/configurationListeners.h>
+#include <src/processor/messageProcessor.h>
+
+#include <src/core/wldr.h>
+
+#include <parc/assert/parc_Assert.h>
+
+// the router's clock frequency (we now use the monotonic clock)
+#define HZ 1000
+
+// these will all be a little off because its all integer division
+#define MSEC_PER_TICK (1000 / HZ)
+#define USEC_PER_TICK (1000000 / HZ)
+#define NSEC_PER_TICK ((1000000000ULL) / HZ)
+#define MSEC_TO_TICKS(msec) \
+  ((msec < FC_MSEC_PER_TICK) ? 1 : msec / FC_MSEC_PER_TICK)
+#define NSEC_TO_TICKS(nsec) ((nsec < NSEC_PER_TICK) ? 1 : nsec / NSEC_PER_TICK)
+
+struct forwarder {
+  Dispatcher *dispatcher;
+
+  uint16_t server_port;
+
+  PARCEventSignal *signal_int;
+  PARCEventSignal *signal_term;
+  PARCEventSignal *signal_usr1;
+  PARCEventTimer *keepalive_event;
+
+  // will skew the virtual clock forward.  In normal operaiton, it is 0.
+  Ticks clockOffset;
+
+  unsigned nextConnectionid;
+  Messenger *messenger;
+  ConnectionManager *connectionManager;
+  ConnectionTable *connectionTable;
+  ListenerSet *listenerSet;
+  Configuration *config;
+
+  // we'll eventually want to setup a threadpool of these
+  MessageProcessor *processor;
+
+  Logger *logger;
+
+  PARCClock *clock;
+
+  hicn_socket_helper_t
+      *hicnSocketHelper;  // state required to manage hicn connections
+
+  // used by seed48 and nrand48
+  unsigned short seed[3];
+
+#ifdef WITH_MAPME
+  MapMe *mapme;
+#endif /* WITH_MAPME */
+};
+
+// signal traps through the event scheduler
+static void _signal_cb(int, PARCEventType, void *);
+
+// A no-op keepalive to prevent Libevent from exiting the dispatch loop
+static void _keepalive_cb(int, PARCEventType, void *);
+
+/**
+ * Reseed our pseudo-random number generator.
+ */
+static void forwarder_Seed(Forwarder *forwarder) {
+  int fd;
+  ssize_t res;
+
+  res = -1;
+  fd = open("/dev/urandom", O_RDONLY);
+  if (fd != -1) {
+    res = read(fd, forwarder->seed, sizeof(forwarder->seed));
+    close(fd);
+  }
+  if (res != sizeof(forwarder->seed)) {
+    forwarder->seed[1] = (unsigned short)getpid(); /* better than no entropy */
+    forwarder->seed[2] = (unsigned short)time(NULL);
+  }
+  /*
+   * The call to seed48 is needed by cygwin, and should be harmless
+   * on other platforms.
+   */
+  seed48(forwarder->seed);
+}
+
+Logger *forwarder_GetLogger(const Forwarder *forwarder) {
+  return forwarder->logger;
+}
+
+// ============================================================================
+// Setup and destroy section
+
+Forwarder *forwarder_Create(Logger *logger) {
+  Forwarder *forwarder = parcMemory_AllocateAndClear(sizeof(Forwarder));
+  parcAssertNotNull(forwarder, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Forwarder));
+  memset(forwarder, 0, sizeof(Forwarder));
+  forwarder_Seed(forwarder);
+
+  forwarder->clock = parcClock_Monotonic();
+  forwarder->clockOffset = 0;
+
+  if (logger) {
+    forwarder->logger = logger_Acquire(logger);
+    logger_SetClock(forwarder->logger, forwarder->clock);
+  } else {
+    PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+    forwarder->logger = logger_Create(reporter, forwarder->clock);
+    parcLogReporter_Release(&reporter);
+  }
+
+  forwarder->nextConnectionid = 1;
+  forwarder->dispatcher = dispatcher_Create(forwarder->logger);
+  forwarder->messenger = messenger_Create(forwarder->dispatcher);
+  forwarder->connectionManager = connectionManager_Create(forwarder);
+  forwarder->connectionTable = connectionTable_Create();
+  forwarder->listenerSet = listenerSet_Create();
+  forwarder->config = configuration_Create(forwarder);
+  forwarder->processor = messageProcessor_Create(forwarder);
+
+  forwarder->signal_term = dispatcher_CreateSignalEvent(
+      forwarder->dispatcher, _signal_cb, forwarder, SIGTERM);
+  dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_term);
+
+  forwarder->signal_int = dispatcher_CreateSignalEvent(
+      forwarder->dispatcher, _signal_cb, forwarder, SIGINT);
+  dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_int);
+
+  forwarder->signal_usr1 = dispatcher_CreateSignalEvent(
+      forwarder->dispatcher, _signal_cb, forwarder, SIGPIPE);
+  dispatcher_StartSignalEvent(forwarder->dispatcher, forwarder->signal_usr1);
+
+#ifndef __APPLE__
+  forwarder->hicnSocketHelper = hicn_create();
+  if (forwarder->hicnSocketHelper == NULL) return NULL;
+#endif /* __APPLE__ */
+  /* ignore child */
+  signal(SIGCHLD, SIG_IGN);
+
+  /* ignore tty signals */
+  signal(SIGTSTP, SIG_IGN);
+  signal(SIGTTOU, SIG_IGN);
+  signal(SIGTTIN, SIG_IGN);
+
+  // We no longer use this for ticks, but we need to have at least one event
+  // schedule to keep Libevent happy.
+
+  struct timeval wtnow_timeout;
+  timerclear(&wtnow_timeout);
+
+  wtnow_timeout.tv_sec = 0;
+  wtnow_timeout.tv_usec = 50000;  // 20 Hz keepalive
+
+#ifdef WITH_MAPME
+  if (!(mapMe_Init(&forwarder->mapme, forwarder))) return NULL;
+#endif /* WITH_MAPME */
+
+  PARCEventScheduler *base =
+      dispatcher_GetEventScheduler(forwarder->dispatcher);
+  forwarder->keepalive_event = parcEventTimer_Create(
+      base, PARCEventType_Persist, _keepalive_cb, (void *)forwarder);
+  parcEventTimer_Start(forwarder->keepalive_event, &wtnow_timeout);
+
+  return forwarder;
+}
+
+void forwarder_Destroy(Forwarder **ptr) {
+  parcAssertNotNull(ptr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*ptr, "Parameter must dereference to non-null pointer");
+  Forwarder *forwarder = *ptr;
+#if !defined(__APPLE__) && !defined(__ANDROID__)
+  hicn_destroy();
+#endif
+  parcEventTimer_Destroy(&(forwarder->keepalive_event));
+
+  listenerSet_Destroy(&(forwarder->listenerSet));
+  connectionManager_Destroy(&(forwarder->connectionManager));
+  connectionTable_Destroy(&(forwarder->connectionTable));
+  messageProcessor_Destroy(&(forwarder->processor));
+  configuration_Destroy(&(forwarder->config));
+
+  // the messenger is used by many of the other pieces, so destroy it last
+  messenger_Destroy(&(forwarder->messenger));
+
+  dispatcher_DestroySignalEvent(forwarder->dispatcher,
+                                &(forwarder->signal_int));
+  dispatcher_DestroySignalEvent(forwarder->dispatcher,
+                                &(forwarder->signal_term));
+  dispatcher_DestroySignalEvent(forwarder->dispatcher,
+                                &(forwarder->signal_usr1));
+
+  parcClock_Release(&forwarder->clock);
+  logger_Release(&forwarder->logger);
+
+  // do the dispatcher last
+  dispatcher_Destroy(&(forwarder->dispatcher));
+
+  parcMemory_Deallocate((void **)&forwarder);
+  *ptr = NULL;
+}
+
+void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
+                                 const char *localPath) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+
+  configurationListeners_SetupAll(forwarder->config, port, localPath);
+}
+
+void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename) {
+  ConfigurationFile *configFile = configurationFile_Create(forwarder, filename);
+  if (configFile) {
+    configurationFile_Process(configFile);
+    configurationFile_Release(&configFile);
+  }
+}
+
+Configuration *forwarder_GetConfiguration(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->config;
+}
+
+// ============================================================================
+
+unsigned forwarder_GetNextConnectionId(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->nextConnectionid++;
+}
+
+Messenger *forwarder_GetMessenger(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->messenger;
+}
+
+Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->dispatcher;
+}
+
+ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->connectionTable;
+}
+
+ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return forwarder->listenerSet;
+}
+
+void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  messageProcessor_SetCacheStoreFlag(forwarder->processor, val);
+}
+
+bool forwarder_GetChacheStoreFlag(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return messageProcessor_GetCacheStoreFlag(forwarder->processor);
+}
+
+void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  messageProcessor_SetCacheServeFlag(forwarder->processor, val);
+}
+
+bool forwarder_GetChacheServeFlag(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return messageProcessor_GetCacheServeFlag(forwarder->processor);
+}
+
+void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
+                              struct iovec *message, unsigned ingressId) {
+  configuration_ReceiveCommand(forwarder->config, command, message, ingressId);
+}
+
+void forwarder_Receive(Forwarder *forwarder, Message *message) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  // this takes ownership of the message, so we're done here
+
+  // this are the checks needed to implement WLDR. We set wldr only on the STAs
+  // and we let the AP to react according to choise of the client.
+  // if the STA enables wldr using the set command, the AP enable wldr as well
+  // otherwise, if the STA disable it the AP remove wldr
+  // WLDR should be enabled only on the STAs using the command line
+  // TODO
+  // disable WLDR command line on the AP
+  const Connection *conn = connectionTable_FindById(
+      forwarder->connectionTable, message_GetIngressConnectionId(message));
+
+  if (!conn) {
+    return;
+  }
+
+  if (message_HasWldr(message)) {
+    if (connection_HasWldr(conn)) {
+      // case 1: WLDR is enabled
+      connection_DetectLosses((Connection *)conn, message);
+    } else if (!connection_HasWldr(conn) &&
+               connection_WldrAutoStartAllowed(conn)) {
+      // case 2: We are on an AP. We enable WLDR
+      connection_EnableWldr((Connection *)conn);
+      connection_DetectLosses((Connection *)conn, message);
+    }
+    // case 3: Ignore WLDR
+  } else {
+    if (connection_HasWldr(conn) && connection_WldrAutoStartAllowed(conn)) {
+      // case 1: STA do not use WLDR, we disable it
+      connection_DisableWldr((Connection *)conn);
+    }
+  }
+
+  messageProcessor_Receive(forwarder->processor, message);
+}
+
+Ticks forwarder_GetTicks(const Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+  return parcClock_GetTime(forwarder->clock) + forwarder->clockOffset;
+}
+
+Ticks forwarder_NanosToTicks(uint64_t nanos) { return NSEC_TO_TICKS(nanos); }
+
+uint64_t forwarder_TicksToNanos(Ticks ticks) {
+  return (1000000000ULL) * ticks / HZ;
+}
+
+bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
+                                add_route_command *control, unsigned ifidx) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(control, "Parameter route must be non-null");
+
+  // we only have one message processor
+  bool res =
+      messageProcessor_AddOrUpdateRoute(forwarder->processor, control, ifidx);
+
+  return res;
+}
+
+bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
+                           unsigned ifidx) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(control, "Parameter route must be non-null");
+
+  // we only have one message processor
+  return messageProcessor_RemoveRoute(forwarder->processor, control, ifidx);
+}
+
+void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
+                                            unsigned connectionId) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  messageProcessor_RemoveConnectionIdFromRoutes(forwarder->processor,
+                                                connectionId);
+}
+
+void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
+                           strategy_type strategy) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+  // if (strategy == NULL) {
+  //     strategy = SET_STRATEGY_RANDOM;
+  // }
+
+  processor_SetStrategy(forwarder->processor, prefix, strategy);
+}
+
+FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder) {
+  return messageProcessor_GetFibEntries(forwarder->processor);
+}
+
+void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
+                                         size_t maximumContentStoreSize) {
+  messageProcessor_SetContentObjectStoreSize(forwarder->processor,
+                                             maximumContentStoreSize);
+}
+
+void forwarder_ClearCache(Forwarder *forwarder) {
+  messageProcessor_ClearCache(forwarder->processor);
+}
+
+PARCClock *forwarder_GetClock(const Forwarder *forwarder) {
+  return forwarder->clock;
+}
+
+hicn_socket_helper_t *forwarder_GetHIcnSocketHelper(Forwarder *forwarder) {
+  return forwarder->hicnSocketHelper;
+}
+
+// =======================================================
+
+static void _signal_cb(int sig, PARCEventType events, void *user_data) {
+  Forwarder *forwarder = (Forwarder *)user_data;
+
+  logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+             __func__, "signal %d events %d", sig, events);
+
+  switch ((int)sig) {
+    case SIGTERM:
+      logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+                 __func__, "Caught an terminate signal; exiting cleanly.");
+      dispatcher_Stop(forwarder->dispatcher);
+      break;
+
+    case SIGINT:
+      logger_Log(forwarder->logger, LoggerFacility_Core, PARCLogLevel_Warning,
+                 __func__, "Caught an interrupt signal; exiting cleanly.");
+      dispatcher_Stop(forwarder->dispatcher);
+      break;
+
+    case SIGUSR1:
+      // dump stats
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void _keepalive_cb(int fd, PARCEventType what, void *user_data) {
+  parcAssertTrue(what & PARCEventType_Timeout, "Got unexpected tick_cb: %d",
+                 what);
+  // function is just a keepalive for hicn-light, does not do anything
+}
+
+#ifdef WITH_MAPME
+FIB *forwarder_getFib(Forwarder *forwarder) {
+  return messageProcessor_getFib(forwarder->processor);
+}
+
+void forwarder_onConnectionAdded(Forwarder *forwarder, const Connection *conn) {
+  mapMe_onConnectionAdded(forwarder->mapme, conn);
+}
+
+void forwarder_onConnectionRemoved(Forwarder *forwarder,
+                                   const Connection *conn) {}
+
+void forwarder_ProcessMapMe(Forwarder *forwarder, uint8_t *msgBuffer,
+                            unsigned conn_id) {
+  mapMe_Process(forwarder->mapme, msgBuffer, conn_id);
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/core/forwarder.h b/hicn-light/src/core/forwarder.h
new file mode 100755 (executable)
index 0000000..ad3f975
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * The methods in this header are for the non-threaded forwarder.  They should
+ * only be called within the forwarders thread of execution.
+ */
+
+#ifndef forwarder_h
+#define forwarder_h
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include <src/core/connectionTable.h>
+#include <src/core/dispatcher.h>
+#include <src/messenger/messenger.h>
+
+#include <src/core/message.h>
+
+#include <src/config/configuration.h>
+
+#ifdef WITH_MAPME
+#include <src/processor/fib.h>
+#endif /* WITH_MAPME */
+
+#include <src/core/logger.h>
+#include <src/core/ticks.h>
+#include <src/io/listenerSet.h>
+
+#include <src/processor/fibEntryList.h>
+
+#include <parc/algol/parc_Clock.h>
+
+#include <src/socket/api.h>
+
+#define PORT_NUMBER 9695
+#define PORT_NUMBER_AS_STRING "9695"
+
+#include <src/utils/commands.h>
+
+// ==============================================
+
+struct forwarder;
+typedef struct forwarder Forwarder;
+
+
+/**
+ * @function forwarder_Create
+ * @abstract Create the forwarder and use the provided logger for diagnostic
+ * output
+ * @discussion
+ *   If the logger is null, hicn-light will create a STDOUT logger.
+ *
+ * @param logger may be NULL
+ */
+Forwarder *forwarder_Create(Logger *logger);
+
+/**
+ * @function forwarder_Destroy
+ * @abstract Destroys the forwarder, stopping all traffic and freeing all memory
+ */
+void forwarder_Destroy(Forwarder **ptr);
+
+/**
+ * @function forwarder_SetupAllListeners
+ * @abstract Setup all listeners (tcp, udp, local, ether, ip multicast) on all
+ * interfaces
+ * @discussion
+ *   Sets up all listeners on all running interfaces.  This provides a quick and
+ * easy startup, rather than providing a configuration file or programmatic
+ * commands.
+ *
+ * @param port is used by TCP and UDP listeners, in host byte order
+ * @param localPath is the AF_UNIX path to use, if NULL no AF_UNIX listener is
+ * setup
+ */
+void forwarder_SetupAllListeners(Forwarder *forwarder, uint16_t port,
+                                 const char *localPath);
+
+/**
+ * Configure hicn-light via a configuration file
+ *
+ * The configuration file is a set of lines, just like used in hicnLightControl.
+ * You need to have "add listener" lines in the file to receive connections.  No
+ * default listeners are configured.
+ *
+ * @param [in] forwarder An alloated Forwarder
+ * @param [in] filename The path to the configuration file
+ */
+void forwarder_SetupFromConfigFile(Forwarder *forwarder, const char *filename);
+
+/**
+ * Returns the logger used by this forwarder
+ *
+ * If you will store the logger, you should acquire a reference to it.
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The logger used by hicn-light
+ * @retval null An error
+ */
+Logger *forwarder_GetLogger(const Forwarder *forwarder);
+
+/**
+ * @function forwarder_SetLogLevel
+ * @abstract Sets the minimum level to log
+ */
+void forwarder_SetLogLevel(Forwarder *forwarder, PARCLogLevel level);
+
+/**
+ * @function forwarder_GetNextConnectionId
+ * @abstract Get the next identifier for a new connection
+ */
+unsigned forwarder_GetNextConnectionId(Forwarder *forwarder);
+
+Messenger *forwarder_GetMessenger(Forwarder *forwarder);
+
+Dispatcher *forwarder_GetDispatcher(Forwarder *forwarder);
+
+/**
+ * Returns the set of currently active listeners
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The set of active listeners
+ * @retval null An error
+ */
+ListenerSet *forwarder_GetListenerSet(Forwarder *forwarder);
+
+/**
+ * Returns the forwrder's connection table
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null The connection tabler
+ * @retval null An error
+ *
+ */
+ConnectionTable *forwarder_GetConnectionTable(Forwarder *forwarder);
+
+/**
+ * Returns a Tick-based clock
+ *
+ * Runs at approximately 1 msec per tick (see HZ in forwarder.c).
+ * Do not Release this clock.  If you save a copy of it, create your own
+ * reference to it with parcClock_Acquire().
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ *
+ * @retval non-null An allocated hicn-light Clock based on the Tick counter
+ * @retval null An error
+ */
+PARCClock *forwarder_GetClock(const Forwarder *forwarder);
+
+/**
+ * Direct call to get the Tick clock
+ *
+ * Runs at approximately 1 msec per tick (see HZ in forwarder.c)
+ *
+ * @param [in] forwarder An allocated hicn-light forwarder
+ */
+Ticks forwarder_GetTicks(const Forwarder *forwarder);
+
+/**
+ * Convert nano seconds to Ticks
+ *
+ * Converts nano seconds to Ticks, based on HZ (in forwarder.c)
+ */
+Ticks forwarder_NanosToTicks(uint64_t nanos);
+
+uint64_t forwarder_TicksToNanos(Ticks ticks);
+
+void forwarder_ReceiveCommand(Forwarder *forwarder, command_id command,
+                              struct iovec *message, unsigned ingressId);
+
+void forwarder_Receive(Forwarder *forwarder, Message *mesage);
+
+/**
+ * @function forwarder_AddOrUpdateRoute
+ * @abstract Adds or updates a route on all the message processors
+ */
+bool forwarder_AddOrUpdateRoute(Forwarder *forwarder,
+                                add_route_command *control, unsigned ifidx);
+
+/**
+ * @function forwarder_RemoveRoute
+ * @abstract Removes a route from all the message processors
+ */
+bool forwarder_RemoveRoute(Forwarder *forwarder, remove_route_command *control,
+                           unsigned ifidx);
+
+/**
+ * Removes a connection id from all routes
+ */
+void forwarder_RemoveConnectionIdFromRoutes(Forwarder *forwarder,
+                                            unsigned connectionId);
+
+/**
+ * @function forwarder_GetConfiguration
+ * @abstract The configuration object
+ * @discussion
+ *   The configuration contains all user-issued commands.  It does not include
+ * dynamic state.
+ */
+Configuration *forwarder_GetConfiguration(Forwarder *forwarder);
+
+FibEntryList *forwarder_GetFibEntries(Forwarder *forwarder);
+
+/**
+ * Sets the maximum number of content objects in the content store
+ *
+ * Implementation dependent - may wipe the cache.
+ */
+void forwarder_SetContentObjectStoreSize(Forwarder *forwarder,
+                                         size_t maximumContentStoreSize);
+
+void forwarder_SetChacheStoreFlag(Forwarder *forwarder, bool val);
+
+bool forwarder_GetChacheStoreFlag(Forwarder *forwarder);
+
+void forwarder_SetChacheServeFlag(Forwarder *forwarder, bool val);
+
+bool forwarder_GetChacheServeFlag(Forwarder *forwarder);
+
+void forwarder_ClearCache(Forwarder *forwarder);
+
+void forwarder_SetStrategy(Forwarder *forwarder, Name *prefix,
+                           strategy_type strategy);
+
+hicn_socket_helper_t *forwarder_GetHIcnSocketHelper(Forwarder *forwarder);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function forwarder_getFib
+ * @abstract Returns the hICN forwarder's FIB.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @returns Pointer to the hICN FIB.
+ */
+FIB *forwarder_getFib(Forwarder *forwarder);
+
+/**
+ * @function forwarder_onConnectionAdded
+ * @abstract Callback fired upon addition of a new connection through the
+ *   control protocol.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] conn - Pointer to the newly added connection.
+ */
+void forwarder_onConnectionAdded(Forwarder *forwarder, const Connection *conn);
+
+/**
+ * @function forwarder_onConnectionRemoved
+ * @abstract Callback fired upon removal of a connection through the control
+ *   protocol.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] conn - Pointer to the removed connection.
+ */
+void forwarder_onConnectionRemoved(Forwarder *forwarder,
+                                   const Connection *conn);
+
+/**
+ * @function forwarder_ProcessMapMe
+ * @abstract Callback fired by an hICN listener upon reception of a MAP-Me
+ *      message.
+ * @param [in] forwarder - Pointer to the hICN forwarder.
+ * @param [in] msgBuffer - MAP-Me buffer
+ * @param [in] conn_id - Ingress connection id
+ */
+void forwarder_ProcessMapMe(Forwarder *forwarder, uint8_t *msgBuffer,
+                            unsigned conn_id);
+
+#endif /* WITH_MAPME */
+
+#endif  // forwarder_h
diff --git a/hicn-light/src/core/logger.c b/hicn-light/src/core/logger.c
new file mode 100755 (executable)
index 0000000..cac3000
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/logging/parc_Log.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/logger.h>
+
+struct logger {
+  PARCClock *clock;
+
+  PARCLogReporter *reporter;
+  PARCLog *loggerArray[LoggerFacility_END];
+};
+
+static const struct facility_to_string {
+  LoggerFacility facility;
+  const char *string;
+} _facilityToString[] = {
+    {.facility = LoggerFacility_Config, .string = "Config"},
+    {.facility = LoggerFacility_Core, .string = "Core"},
+    {.facility = LoggerFacility_IO, .string = "IO"},
+    {.facility = LoggerFacility_Message, .string = "Message"},
+    {.facility = LoggerFacility_Processor, .string = "Processor"},
+    {.facility = 0, .string = NULL}};
+
+const char *logger_FacilityString(LoggerFacility facility) {
+  for (int i = 0; _facilityToString[i].string != NULL; i++) {
+    if (_facilityToString[i].facility == facility) {
+      return _facilityToString[i].string;
+    }
+  }
+  return "Unknown";
+}
+
+static void _allocateLoggers(Logger *logger, PARCLogReporter *reporter) {
+  parcTrapUnexpectedStateIf(
+      logger->reporter != NULL,
+      "Trying to allocate a reporter when the previous one is not null");
+  logger->reporter = parcLogReporter_Acquire(reporter);
+
+  char hostname[255];
+  int gotHostName = gethostname(hostname, 255);
+  if (gotHostName < 0) {
+    snprintf(hostname, 255, "unknown");
+  }
+
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    logger->loggerArray[i] = parcLog_Create(hostname, logger_FacilityString(i),
+                                            "forwarder", logger->reporter);
+    parcLog_SetLevel(logger->loggerArray[i], PARCLogLevel_Error);
+  }
+}
+
+static void _releaseLoggers(Logger *logger) {
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    parcLog_Release(&logger->loggerArray[i]);
+  }
+  parcLogReporter_Release(&logger->reporter);
+}
+
+static void _destroyer(Logger **loggerPtr) {
+  Logger *logger = *loggerPtr;
+  _releaseLoggers(logger);
+  parcClock_Release(&(*loggerPtr)->clock);
+}
+
+parcObject_ExtendPARCObject(Logger, _destroyer, NULL, NULL, NULL, NULL, NULL,
+                            NULL);
+
+parcObject_ImplementAcquire(logger, Logger);
+
+parcObject_ImplementRelease(logger, Logger);
+
+Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock) {
+  parcAssertNotNull(reporter, "Parameter reporter must be non-null");
+  parcAssertNotNull(clock, "Parameter clock must be non-null");
+
+  Logger *logger = parcObject_CreateAndClearInstance(Logger);
+  if (logger) {
+    logger->clock = parcClock_Acquire(clock);
+    _allocateLoggers(logger, reporter);
+  }
+
+  return logger;
+}
+
+void logger_SetReporter(Logger *logger, PARCLogReporter *reporter) {
+  parcAssertNotNull(logger, "Parameter logger must be non-null");
+
+  // save the log level state
+  PARCLogLevel savedLevels[LoggerFacility_END];
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    savedLevels[i] = parcLog_GetLevel(logger->loggerArray[i]);
+  }
+
+  _releaseLoggers(logger);
+
+  _allocateLoggers(logger, reporter);
+
+  // restore log level state
+  for (int i = 0; i < LoggerFacility_END; i++) {
+    parcLog_SetLevel(logger->loggerArray[i], savedLevels[i]);
+  }
+}
+
+void logger_SetClock(Logger *logger, PARCClock *clock) {
+  parcAssertNotNull(logger, "Parameter logger must be non-null");
+  parcClock_Release(&logger->clock);
+  logger->clock = parcClock_Acquire(clock);
+}
+
+static void _assertInvariants(const Logger *logger, LoggerFacility facility) {
+  parcAssertNotNull(logger, "Parameter logger must be non-null");
+  parcTrapOutOfBoundsIf(facility >= LoggerFacility_END, "Invalid facility %d",
+                        facility);
+}
+
+void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
+                        PARCLogLevel minimumLevel) {
+  _assertInvariants(logger, facility);
+  PARCLog *log = logger->loggerArray[facility];
+  parcLog_SetLevel(log, minimumLevel);
+}
+
+bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
+                       PARCLogLevel level) {
+  _assertInvariants(logger, facility);
+  PARCLog *log = logger->loggerArray[facility];
+  return parcLog_IsLoggable(log, level);
+}
+
+void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
+                const char *module, const char *format, ...) {
+  if (logger_IsLoggable(logger, facility, level)) {
+    // this is logged as the messageid
+    uint64_t logtime = parcClock_GetTime(logger->clock);
+
+    // logger_IsLoggable asserted invariants so we know facility is in bounds
+    PARCLog *log = logger->loggerArray[facility];
+
+    va_list va;
+    va_start(va, format);
+
+    parcLog_MessageVaList(log, level, logtime, format, va);
+
+    va_end(va);
+  }
+}
diff --git a/hicn-light/src/core/logger.h b/hicn-light/src/core/logger.h
new file mode 100755 (executable)
index 0000000..e2ab7e1
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file logger.h
+ * @brief Logger for the hicn-light forwarder
+ *
+ * A facility based logger to allow selective logging from different parts of
+ * hicn-light
+ *
+ */
+
+#ifndef logger_h
+#define logger_h
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporter.h>
+#include <stdarg.h>
+#include <sys/time.h>
+
+#include <parc/algol/parc_Clock.h>
+
+struct logger;
+typedef struct logger Logger;
+
+/**
+ * CONFIG faciilty concerns anything in the /config directory
+ * CORE concerns anything in the /core directory
+ * IO concerns anything in the /io directory (listeners, connectors, tcp,
+ * ethernet, etc.) PROCESSOR concerns FIB, PIT, CS MESSAGE concerns message
+ * events, like parsing
+ */
+typedef enum {
+  LoggerFacility_Config,
+  LoggerFacility_Core,
+  LoggerFacility_IO,
+  LoggerFacility_Processor,
+  LoggerFacility_Message,
+  LoggerFacility_END  // sentinel value
+} LoggerFacility;
+
+/**
+ * Returns a string representation of a facility
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] facility The facility to change to a string
+ *
+ * @retval string A string representation of the facility
+ */
+const char *logger_FacilityString(LoggerFacility facility);
+
+/**
+ * Returns a string representation of a log level
+ *
+ * Do not free the returned value.
+ *
+ * @param [in] level The level to change to a string
+ *
+ * @retval string A string representation of the level
+ */
+const char *logger_LevelString(PARCLogLevel level);
+
+/**
+ * Create a logger that uses a given writer and clock
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] writer The output writer
+ * @param [in] clock The clock to use for log messages
+ *
+ * @retval non-null An allocated logger
+ * @retval null An error
+ */
+Logger *logger_Create(PARCLogReporter *reporter, const PARCClock *clock);
+
+/**
+ * Release logger
+ */
+void logger_Release(Logger **loggerPtr);
+
+/**
+ * Acquire logger
+ */
+Logger *logger_Acquire(const Logger *logger);
+
+/**
+ * Sets the minimum log level for a facility
+ *
+ * The default log level is ERROR.  For a message to be logged, it must be of
+ * equal or higher log level.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to set the log level for
+ * @param [in] The minimum level to log
+ *
+ */
+void logger_SetLogLevel(Logger *logger, LoggerFacility facility,
+                        PARCLogLevel minimumLevel);
+
+/**
+ * Tests if the log level would be logged
+ *
+ * If the facility would log the given level, returns true.  May be used as a
+ * guard around expensive logging functions.
+ *
+ * @param [in] logger An allocated logger
+ * @param [in] facility The facility to test
+ * @param [in] The level to test
+ *
+ * @retval true The given facility would log the given level
+ * @retval false A message of the given level would not be logged
+ *
+ */
+bool logger_IsLoggable(const Logger *logger, LoggerFacility facility,
+                       PARCLogLevel level);
+
+/**
+ * Log a message
+ *
+ * The message will only be logged if it is loggable (logger_IsLoggable returns
+ * true).
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] facility The facility to log under
+ * @param [in] level The log level of the message
+ * @param [in] module The specific module logging the message
+ * @param [in] format The message with varargs
+ *
+ */
+void logger_Log(Logger *logger, LoggerFacility facility, PARCLogLevel level,
+                const char *module, const char *format, ...);
+
+/**
+ * Switch the logger to a new reporter
+ *
+ * Will close the old reporter and re-setup the internal loggers to use the new
+ * reporter. All current log level settings are preserved.
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] reporter An allocated PARCLogReporter
+ */
+void logger_SetReporter(Logger *logger, PARCLogReporter *reporter);
+
+/**
+ * Set a new clock to use with the logger
+ *
+ * The logger will start getting the time (logged as the messageid) from the
+ * specified clock
+ *
+ * @param [in] logger An allocated Logger
+ * @param [in] clock An allocated PARCClock
+ */
+void logger_SetClock(Logger *logger, PARCClock *clock);
+#endif  // logger_h
diff --git a/hicn-light/src/core/mapMe.c b/hicn-light/src/core/mapMe.c
new file mode 100755 (executable)
index 0000000..4444bcf
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file mapMe.c
+ * @brief MAP-Me : AnchorLess Producer Mobility Management.
+ */
+
+#ifdef WITH_MAPME
+
+#include <hicn/hicn.h>
+#include <src/core/mapMe.h>
+#include <stdio.h>  // printf
+
+#include <src/core/connectionList.h>
+#include <src/core/forwarder.h>
+#include <src/core/logger.h>
+#include <src/core/message.h>
+#include <src/core/messagePacketType.h>  // packet types
+#include <src/core/ticks.h>
+#include <src/processor/fibEntry.h>
+#include <src/processor/pitEntry.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Iterator.h>
+#include <parc/algol/parc_Unsigned.h>
+#include <parc/assert/parc_Assert.h>
+
+#define MS2NS(x) x * 1000000
+#define T2NS(x) forwarder_TicksToNanos(x)
+
+#define MAPME_DEFAULT_TU 5000  /* ms */
+#define MAPME_DEFAULT_RETX 500 /* ms */
+#define MAX_RETX 3
+
+#define NOT_A_NOTIFICATION false
+#define NO_INGRESS 0
+#define TIMER_NO_REPEAT false
+
+#define DO_DISCOVERY 1
+#define MAPME_INVALID_DICOVERY_SEQ -1
+
+#define LOG_FACILITY LoggerFacility_Core
+
+#define LOG(mapme, log_level, fmt, ...)                          \
+  do {                                                           \
+    Logger *logger = forwarder_GetLogger(mapme->forwarder);      \
+    if (logger_IsLoggable(logger, LOG_FACILITY, log_level)) {    \
+      logger_Log(logger, LOG_FACILITY, log_level, __func__, fmt, \
+                 ##__VA_ARGS__);                                 \
+    }                                                            \
+  } while (0)
+
+#define WARN(mapme, fmt, ...) \
+  LOG(mapme, PARCLogLevel_Warning, fmt, ##__VA_ARGS__)
+#define ERROR(mapme, fmt, ...) \
+  LOG(mapme, PARCLogLevel_Error, fmt, ##__VA_ARGS__)
+#define INFO(mapme, fmt, ...) LOG(mapme, PARCLogLevel_Info, fmt, ##__VA_ARGS__)
+#define DEBUG(mapme, fmt, ...) \
+  LOG(mapme, PARCLogLevel_Debug, fmt, ##__VA_ARGS__)
+
+/**
+ * MAP-Me state data structure
+ */
+struct mapme {
+  uint32_t retx; /* ms */
+  uint32_t Tu;   /* ms */
+  bool removeFibEntries;
+
+  Forwarder *forwarder;
+};
+
+static MapMe MapMeDefault = {.retx = MAPME_DEFAULT_RETX,
+                             .Tu = MAPME_DEFAULT_TU,
+                             .removeFibEntries = false};
+
+/******************************************************************************/
+
+#include <src/core/connection.h>
+
+bool mapMe_Init(MapMe **mapme, Forwarder *forwarder) {
+  *mapme = malloc(sizeof(MapMe));
+  if (!mapme) goto ERR_MALLOC;
+
+  /* Internal state : set default values */
+  memcpy(*mapme, &MapMeDefault, sizeof(MapMe));
+
+  (*mapme)->forwarder = forwarder;
+
+  /* Install hook on Face events to onConnectionAdded */
+  // see. config/configuration.c
+
+  /* Install hook for signalization processing. See :
+   *  - io/hicnListener.c
+   *  - src/core/connection.{c,h}
+   */
+
+  ERROR((*mapme), "MapMe");
+
+  return true;
+
+ERR_MALLOC:
+  return false;
+}
+
+/******************************************************************************
+ * TFIB
+ ******************************************************************************/
+
+#define INVALID_SEQ 0
+#define INIT_SEQ 1
+
+typedef struct {
+  uint32_t seq;
+  PARCHashMap *nexthops;
+  /* Update/Notification heuristic */
+  Ticks lastAckedUpdate;  // XXX This is only for producer !!!
+} MapMeTFIB;
+
+static MapMeTFIB *mapMeTFIB_Create() {
+  MapMeTFIB *tfib;
+  tfib = malloc(sizeof(MapMeTFIB));
+  if (!tfib) goto ERR_MALLOC;
+  tfib->seq = 0;
+  tfib->lastAckedUpdate = 0;
+  tfib->nexthops = parcHashMap_Create();
+  if (!tfib->nexthops) goto ERR_HASHMAP;
+
+  return tfib;
+
+ERR_HASHMAP:
+  free(tfib);
+ERR_MALLOC:
+  return NULL;
+}
+
+void mapMeTFIB_Release(MapMeTFIB **tfibPtr) {
+  MapMeTFIB *tfib = *tfibPtr;
+  parcHashMap_Release(&tfib->nexthops);
+  free(tfib);
+  *tfibPtr = NULL;
+}
+
+/**
+ * @function mapMe_CreateTFIB
+ * @abstract Associate a new TFIB entry to a FIB entry.
+ * @param [in] - Pointer to the FIB entry.
+ * @return Boolean indicating the success of the operation.
+ */
+static void mapMe_CreateTFIB(FibEntry *fibEntry) {
+  MapMeTFIB *tfib;
+
+  /* Make sure we don't already have an associated TFIB entry */
+  tfib = fibEntry_getUserData(fibEntry);
+  // assertNull(tfib);
+
+  tfib = mapMeTFIB_Create();
+  fibEntry_setUserData(fibEntry, tfib, (void (*)(void **))mapMeTFIB_Release);
+}
+
+#define TFIB(fibEntry) ((MapMeTFIB *)fibEntry_getUserData(fibEntry))
+
+static const PARCEventTimer *mapMeTFIB_Get(const MapMeTFIB *tfib,
+                                           unsigned conn_id) {
+  const PARCEventTimer *timer;
+  const PARCBuffer *buffer;
+  PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+  buffer = parcHashMap_Get(tfib->nexthops, cid);
+  if (!buffer) return NULL;
+  PARCByteArray *array = parcBuffer_Array(buffer);
+  timer = *((PARCEventTimer **)parcByteArray_Array(array));
+  parcUnsigned_Release(&cid);
+  return timer;
+}
+
+static void mapMeTFIB_Put(MapMeTFIB *tfib, unsigned conn_id,
+                          const PARCEventTimer *timer) {
+  /* NOTE: Timers are not objects (the only class not being an object in
+   * fact), and as such, we cannot use them as values for the HashMap.
+   * Just like for unsigned we needed the PARC wrapper.
+   * There is no wrapper for pointers, so we use Arrays, which has an ubly
+   * syntax...
+   */
+  PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+  PARCBuffer *buffer =
+      parcBuffer_CreateFromArray(&timer, sizeof(PARCEventTimer *));
+  parcHashMap_Put(tfib->nexthops, cid, buffer);
+  parcUnsigned_Release(&cid);
+  parcBuffer_Release(&buffer);
+}
+
+static void mapMeTFIB_Remove(MapMeTFIB *tfib, unsigned conn_id) {
+  // Who releases the timer ?
+  PARCUnsigned *cid = parcUnsigned_Create(conn_id);
+  parcHashMap_Remove(tfib->nexthops, cid);
+  parcUnsigned_Release(&cid);
+}
+
+static PARCIterator *mapMeTFIB_CreateKeyIterator(const MapMeTFIB *tfib) {
+  return parcHashMap_CreateKeyIterator(tfib->nexthops);
+}
+
+int hicn_prefix_from_name(const Name *name, hicn_prefix_t *prefix) {
+  NameBitvector *bv = name_GetContentName(name);
+  ip_address_t ip_address;
+  nameBitvector_ToIPAddress(bv, &ip_address);
+
+  /* The name length will be equal to ip address' prefix length */
+  return hicn_prefix_create_from_ip_address(&ip_address, prefix);
+}
+
+static Message *mapMe_createMessage(const MapMe *mapme, const Name *name,
+                                    mapme_params_t *params) {
+  Ticks now = forwarder_GetTicks(mapme->forwarder);
+  Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
+
+  INFO(mapme, "[MAP-Me] CreateMessage type=%d seq=%d", params->type,
+       params->seq);
+
+  size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
+                                                   : HICN_MAPME_V4_HDRLEN;
+  uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
+
+  hicn_prefix_t prefix;
+  int rc = hicn_prefix_from_name(name, &prefix);
+  if (rc < 0) {
+    ERROR(mapme, "[MAP-Me] Failed to create lib's name");
+    goto ERR_NAME;
+  }
+
+  INFO(mapme, "[MAP-Me] Creating MAP-Me packet");
+  size_t len = hicn_mapme_create_packet(icmp_pkt, &prefix, params);
+  if (len != 0) {
+    ERROR(mapme, "[MAP-Me] Failed to create mapme packet through lib");
+    goto ERR_CREATE;
+  }
+
+  // hicn_packet_dump(icmp_pkt, MAPME_HDRLEN);
+
+  return message_CreateFromByteArray(NO_INGRESS, icmp_pkt,
+                                     MessagePacketType_Interest, now, logger);
+
+ERR_CREATE:
+ERR_NAME:
+  return NULL;
+}
+
+static Message *mapMe_createAckMessage(const MapMe *mapme,
+                                       const uint8_t *msgBuffer,
+                                       const mapme_params_t *params) {
+  Ticks now = forwarder_GetTicks(mapme->forwarder);
+  Logger *logger = logger_Acquire(forwarder_GetLogger(mapme->forwarder));
+
+  size_t size = (params->protocol == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN
+                                                   : HICN_MAPME_V4_HDRLEN;
+  uint8_t *icmp_pkt = parcMemory_AllocateAndClear(size);
+  memcpy(icmp_pkt, msgBuffer, size);
+
+  size_t len = hicn_mapme_create_ack(icmp_pkt, params);
+  if (len != size) {
+    ERROR(mapme, "[MAP-Me] Failed to create mapme ack packet through lib");
+    return NULL;
+  }
+
+  return message_CreateFromByteArray(
+      NO_INGRESS, icmp_pkt, MessagePacketType_ContentObject, now, logger);
+}
+
+struct setFacePendingArgs {
+  const MapMe *mapme;
+  const Name *name;
+  FibEntry *fibEntry;
+  unsigned conn_id;
+  bool send;
+  bool is_first;
+  uint32_t num_retx;
+};
+
+static bool mapMe_setFacePending(const MapMe *mapme, const Name *name,
+                                 FibEntry *fibEntry, unsigned conn_id,
+                                 bool send, bool is_first, uint32_t num_retx);
+
+static void mapMe_setFacePendingCallback(int fd, PARCEventType which_event,
+                                         void *data) {
+  struct setFacePendingArgs *args = (struct setFacePendingArgs *)data;
+
+  parcAssertTrue(which_event & PARCEventType_Timeout,
+                 "Event incorrect, expecting %X set, got %X",
+                 PARCEventType_Timeout, which_event);
+
+  INFO(args->mapme, "Timeout during retransmission. Re-sending");
+  mapMe_setFacePending(args->mapme, args->name, args->fibEntry, args->conn_id,
+                       args->send, args->is_first, args->num_retx);
+}
+
+/**
+ * @brief Update/Notification heuristic:
+ *
+ * NOTE: IN are currently disabled until the proper placeholder is agreed in the
+ * interest header.
+ */
+static hicn_mapme_type_t mapMe_getTypeFromHeuristic(const MapMe *mapme,
+                                                    FibEntry *fibEntry) {
+#if 0 /* interplay of IU/IN */
+    if (TFIB(fibEntry)->lastAckedUpdate == 0) {
+        return UPDATE;
+    } else {
+        Ticks interval = now - TFIB(fibEntry)->lastAckedUpdate;
+        return (T2NS(interval) > MS2NS(mapme->Tu)) ? UPDATE : NOTIFICATION;
+    }
+#else /* Always send IU */
+  return UPDATE;
+#endif
+}
+
+static bool mapMe_setFacePending(const MapMe *mapme, const Name *name,
+                                 FibEntry *fibEntry, unsigned conn_id,
+                                 bool send, bool is_first, uint32_t num_retx) {
+  int rc;
+
+  INFO(mapme, "[MAP-Me] SetFacePending connection=%d prefix=XX retx=%d",
+       conn_id, num_retx);
+
+  /* NOTE: if the face is pending an we receive an IN, maybe we should not
+   * cancel the timer
+   */
+  Dispatcher *dispatcher = forwarder_GetDispatcher(mapme->forwarder);
+  PARCEventTimer *timer;
+
+  // NOTE
+  // - at producer, send always true, we always send something reliably so we
+  // set the timer.
+  // - in the network, we always forward an IU, and never an IN
+  if (is_first || send) {
+    // XXX
+    mapme_params_t params = {
+        .protocol = IPPROTO_IPV6,
+        .type = is_first ? mapMe_getTypeFromHeuristic(mapme, fibEntry) : UPDATE,
+        .seq = TFIB(fibEntry)->seq};
+    Message *special_interest = mapMe_createMessage(mapme, name, &params);
+    if (!special_interest) {
+      INFO(mapme, "[MAP-Me] Could not create special interest");
+      return false;
+    }
+
+    const ConnectionTable *table =
+        forwarder_GetConnectionTable(mapme->forwarder);
+    const Connection *conn =
+        connectionTable_FindById((ConnectionTable *)table, conn_id);
+    if (conn) {
+      INFO(mapme, "[MAP-Me] Sending MAP-Me packet");
+      connection_ReSend(conn, special_interest, NOT_A_NOTIFICATION);
+    } else {
+      INFO(mapme, "[MAP-Me] Stopped retransmissions as face went down");
+    }
+
+    if (num_retx < MAX_RETX) {
+      INFO(mapme, "[MAP-Me]   - Scheduling retransmission\n");
+      /* Schedule retransmission */
+      struct setFacePendingArgs *args =
+          malloc(sizeof(struct setFacePendingArgs));
+      if (!args) goto ERR_MALLOC;
+      args->mapme = mapme;
+      args->name = name;
+      args->fibEntry = fibEntry;
+      args->conn_id = conn_id;
+      args->send = send;
+      args->is_first = is_first;
+      args->num_retx = num_retx + 1;
+
+      timer = dispatcher_CreateTimer(dispatcher, TIMER_NO_REPEAT,
+                                     mapMe_setFacePendingCallback, args);
+      struct timeval timeout = {mapme->retx / 1000,
+                                (mapme->retx % 1000) * 1000};
+      rc = parcEventTimer_Start(timer, &timeout);
+      if (rc < 0) goto ERR_TIMER;
+    } else {
+      INFO(mapme, "[MAP-Me] Last retransmission.");
+      timer = NULL;
+    }
+  } else {
+    INFO(mapme, "[MAP-Me]  - not forwarding as send is False");
+    timer = NULL;
+  }
+
+  PARCEventTimer *oldTimer =
+      (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_id);
+  if (oldTimer) {
+    INFO(mapme, "[MAP-Me]   - Found old timer, would need to cancel !");
+    // parcEventTimer_Stop(oldTimer);
+  }
+  INFO(mapme, "[MAP-Me]   - Putting new timer in TFIB");
+  if (timer) mapMeTFIB_Put(TFIB(fibEntry), conn_id, timer);
+
+  return true;
+
+ERR_MALLOC:
+ERR_TIMER:
+  return false;
+}
+
+/*------------------------------------------------------------------------------
+ * Event handling
+ *----------------------------------------------------------------------------*/
+
+/*
+ * Return true if we have at least one local connection as next hop
+ */
+static bool mapMe_hasLocalNextHops(const MapMe *mapme,
+                                   const FibEntry *fibEntry) {
+  const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry);
+  const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
+
+  for (size_t j = 0; j < fibEntry_NexthopCount(fibEntry); j++) {
+    /* Retrieve Nexthop #j */
+    unsigned conn_id = numberSet_GetItem(nexthops, j);
+    const Connection *conn =
+        connectionTable_FindById((ConnectionTable *)table, conn_id);
+
+    /* Ignore non-local connections */
+    if (!connection_IsLocal(conn)) continue;
+    /* We don't need to test against conn_added since we don't
+     * expect it to have any entry in the FIB */
+
+    return true;
+  }
+  return false;
+}
+
+/*
+ * Callback called everytime a new connection is created by the control protocol
+ */
+void mapMe_onConnectionAdded(const MapMe *mapme, const Connection *conn_added) {
+  /* bool ret; */
+  FibEntryList *fiblist;
+
+  /* Ignore local connections corresponding to applications for now */
+  if (connection_IsLocal(conn_added)) return;
+
+  unsigned conn_added_id = connection_GetConnectionId(conn_added);
+  INFO(mapme, "[MAP-Me] New connection %d", conn_added_id);
+
+  /*
+   * Iterate on FIB to find locally served prefix
+   * Ideally, we want to avoid a FIB scan everytime a face is added/removed
+   */
+  fiblist = forwarder_GetFibEntries(mapme->forwarder);
+  for (size_t i = 0; i < fibEntryList_Length(fiblist); i++) {
+    FibEntry *fibEntry = (FibEntry *)fibEntryList_Get(fiblist, i);
+    const Name *name = fibEntry_GetPrefix(fibEntry);
+
+    /* Skip entries that have no local connection as next hop */
+    if (!mapMe_hasLocalNextHops(mapme, fibEntry)) continue;
+
+    /* This entry corresponds to a locally served prefix, set
+     * Special Interest */
+    if (!TFIB(fibEntry)) /* Create TFIB associated to FIB entry */
+      mapMe_CreateTFIB(fibEntry);
+    TFIB(fibEntry)->seq++;
+
+    char *name_str = name_ToString(name);
+    INFO(mapme, "[MAP-Me] sending IU/IN for name %s on connection %d", name_str,
+         conn_added_id);
+    free(name_str);
+
+    mapMe_setFacePending(mapme, name, fibEntry, conn_added_id, true, true, 0);
+  }
+}
+
+/*------------------------------------------------------------------------------
+ * Special Interest handling
+ *----------------------------------------------------------------------------*/
+
+/**
+ * @discussion This function is way too long and should be cut out
+ */
+static bool mapMe_onSpecialInterest(const MapMe *mapme,
+                                    const uint8_t *msgBuffer,
+                                    unsigned conn_in_id, hicn_prefix_t *prefix,
+                                    mapme_params_t *params) {
+  const ConnectionTable *table = forwarder_GetConnectionTable(mapme->forwarder);
+  /* The cast is needed since connectionTable_FindById miss the
+   * const qualifier for the first parameter */
+  const Connection *conn_in =
+      connectionTable_FindById((ConnectionTable *)table, conn_in_id);
+  seq_t fibSeq, seq = params->seq;
+  bool send = (params->type == UPDATE);
+  bool rv;
+
+  Name *name = name_CreateFromPacket(msgBuffer, MessagePacketType_Interest);
+  char *name_str = name_ToString(name);
+  INFO(mapme,
+       "[MAP-Me] Ack'ed Special Interest on connection %d - prefix=%s type=XX "
+       "seq=%d",
+       conn_in_id, name_str, seq);
+  free(name_str);
+
+  /*
+   * Immediately send an acknowledgement back on the ingress connection
+   * We always ack, even duplicates.
+   */
+  Message *ack = mapMe_createAckMessage(mapme, msgBuffer, params);
+  if (!ack) goto ERR_ACK_CREATE;
+  rv = connection_ReSend(conn_in, ack, NOT_A_NOTIFICATION);
+  if (!rv) goto ERR_ACK_SEND;
+  message_Release(&ack);
+
+  /* EPM on FIB */
+  /* only the processor has access to the FIB */
+  FIB *fib = forwarder_getFib(mapme->forwarder);
+
+  FibEntry *fibEntry = fib_Contains(fib, name);
+  if (!fibEntry) {
+    INFO(mapme,
+         "[MAP-Me]   - Re-creating FIB entry with next hop on connection %d",
+         conn_in_id);
+    /*
+     * This might happen for a node hosting a producer which has moved.
+     * Destroying the face has led to removing all corresponding FIB
+     * entries. In that case, we need to correctly restore the FIB entries.
+     */
+    strategy_type fwdStrategy = LAST_STRATEGY_VALUE;
+
+    fibEntry = fibEntry_Create(name, fwdStrategy);
+    fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+    mapMe_CreateTFIB(fibEntry);
+    TFIB(fibEntry)->seq = seq;  // INIT_SEQ;
+    fib_Add(fib, fibEntry);
+    return true;  // with proper seq, we are done
+
+  } else if (!TFIB(fibEntry)) {
+    /* Create TFIB associated to FIB entry */
+    INFO(mapme,
+         "[MAP-Me]   - Creating TFIB entry with default sequence number");
+    mapMe_CreateTFIB(fibEntry);
+  }
+
+  fibSeq = TFIB(fibEntry)->seq;
+  if (seq > fibSeq) {
+    INFO(mapme,
+         "[MAP-Me]   - Higher sequence number than FIB %d, updating seq and "
+         "next hops",
+         fibSeq);
+    /* This has to be done first to allow processing SpecialInterestAck's */
+    TFIB(fibEntry)->seq = seq;
+
+    /* Reliably forward the IU on all prevHops */
+    INFO(mapme, "[MAP-Me]   - (1/3) processing prev hops");
+    if (params->type == UPDATE) {
+      PARCIterator *iterator = mapMeTFIB_CreateKeyIterator(TFIB(fibEntry));
+      while (parcIterator_HasNext(iterator)) {
+        PARCUnsigned *cid = parcIterator_Next(iterator);
+        unsigned conn_id = parcUnsigned_GetUnsigned(cid);
+        INFO(mapme, "[MAP-Me]   - Re-sending IU to pending connection %d",
+             conn_id);
+        mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+                             conn_id, false, false, 0);
+      }
+      parcIterator_Release(&iterator);
+    }
+
+    /* nextHops -> prevHops
+     *
+     * We add to the list of pendingUpdates the current next hops, and
+     * eventually forward them an IU too.
+     *
+     * Exception: nextHops -> nextHops
+     *   Because of retransmission issues, it is possible that a second interest
+     *   (with same of higher sequence number) is receive from a next-hop
+     *   interface. In that case, the face remains a next hop.
+     */
+    const NumberSet *nexthops_old = fibEntry_GetNexthops(fibEntry);
+
+    /* We make a copy to be able to send IU _after_ updating next hops */
+    NumberSet *nexthops = numberSet_Create();
+    numberSet_AddSet(nexthops, nexthops_old);
+
+    /* We are considering : * -> nextHops
+     *
+     * If inFace was a previous hop, we need to cancel the timer and remove
+     * the entry. Also, the face should be added to next hops.
+     *
+     * Optimization : nextHops -> nextHops
+     *  - no next hop to add
+     *  - we know that inFace was not a previous hop since it was a next hop and
+     *  this forms a partition. No need for a search
+     */
+
+    INFO(mapme, "[MAP-Me]   - (3/3) next hops ~~> prev hops");
+    PARCEventTimer *oldTimer =
+        (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id);
+    if (oldTimer) {
+      /* This happens if we receive an IU while we are still sending
+       * one in the other direction
+       */
+      INFO(mapme, "[MAP-Me]   - Canceled pending timer");
+      parcEventTimer_Stop(oldTimer);
+      mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id);
+    }
+
+    /* Remove all next hops */
+    for (size_t k = 0; k < numberSet_Length(nexthops_old); k++) {
+      unsigned conn_id = numberSet_GetItem(nexthops_old, k);
+      INFO(mapme, "[MAP-Me]   - Replaced next hops by connection %d", conn_id);
+      fibEntry_RemoveNexthopByConnectionId(fibEntry, conn_id);
+    }
+    fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+
+    INFO(mapme, "[MAP-Me]   - (2/3) processing next hops");
+    bool complete = true;
+    for (size_t k = 0; k < numberSet_Length(nexthops); k++) {
+      unsigned conn_id = numberSet_GetItem(nexthops, k);
+      INFO(mapme, " - Next hop connection %d", conn_id);
+      if (conn_id == conn_in_id) {
+        INFO(mapme, "   . Ignored this next hop since equal to ingress face");
+        continue;
+      }
+
+      INFO(mapme, "[MAP-Me]   - Sending IU on current next hop connection %d",
+           conn_id);
+      mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+                           conn_id, send, false, 0);
+      complete = false;
+    }
+
+    /*
+     * The update is completed when the IU could not be sent to any
+     * other next hop.
+     */
+    if (complete) INFO(mapme, "[MAP-Me]   - Update completed !");
+
+    numberSet_Release(&nexthops);
+
+  } else if (seq == fibSeq) {
+    /*
+     * Multipath, multihoming, multiple producers or duplicate interest
+     *
+     * In all cases, we assume the propagation was already done when the first
+     * interest with the same sequence number was received, so we stop here
+     *
+     * It might happen that the previous AP has still a connection to the
+     * producer and that we received back our own IU. In that case, we just
+     * need to Ack and ignore it.
+     */
+    if (mapMe_hasLocalNextHops(mapme, fibEntry)) {
+      INFO(mapme, "[MAP-Me]   - Received original interest... Update complete");
+      return true;
+    }
+
+    INFO(mapme, "[MAP-Me]   - Adding multipath next hop on connection %d",
+         conn_in_id);
+    fibEntry_AddNexthopByConnectionId(fibEntry, conn_in_id);
+
+  } else {  // seq < fibSeq
+    /*
+     * Face is propagating outdated information, we can just
+     * consider it as a prevHops. Send the special interest backwards with
+     * the new sequence number to reconciliate this outdated part of the
+     * arborescence.
+     */
+    INFO(
+        mapme,
+        "[MAP-Me]   - Update interest %d -> %d sent backwards on connection %d",
+        seq, fibSeq, conn_in_id);
+    mapMe_setFacePending(mapme, fibEntry_GetPrefix(fibEntry), fibEntry,
+                         conn_in_id, send, false, 0);
+  }
+
+  return true;
+
+ERR_ACK_SEND:
+  message_Release(&ack);
+ERR_ACK_CREATE:
+  return false;
+}
+
+void mapMe_onSpecialInterestAck(const MapMe *mapme, const uint8_t *msgBuffer,
+                                unsigned conn_in_id, hicn_prefix_t *prefix,
+                                mapme_params_t *params) {
+  INFO(mapme, "[MAP-Me] Receive IU/IN Ack on connection %d", conn_in_id);
+
+  const Name *name =
+      name_CreateFromPacket(msgBuffer, MessagePacketType_Interest);
+
+  FIB *fib = forwarder_getFib(mapme->forwarder);
+  FibEntry *fibEntry = fib_Contains(fib, name);
+  parcAssertNotNull(fibEntry,
+                    "No corresponding FIB entry for name contained in IU Ack");
+
+  /* Test if the latest pending update has been ack'ed, otherwise just ignore */
+  seq_t seq = params->seq;
+  if (seq != INVALID_SEQ) {
+    seq_t fibSeq = TFIB(fibEntry)->seq;
+
+    if (seq < fibSeq) {
+      INFO(mapme,
+           "[MAP-Me]   - Ignored special interest Ack with seq=%u, expected %u",
+           seq, fibSeq);
+      return;
+    }
+  }
+
+  /*
+   * Ignore the Ack if no TFIB is present, or it has no corresponding entry
+   * with the ingress face.
+   * Note: previously, we were creating the TFIB entry
+   */
+  if (!TFIB(fibEntry)) {
+    INFO(mapme, "[MAP-Me]   - Ignored ACK for prefix with no TFIB entry");
+    return;
+  }
+
+  PARCEventTimer *timer =
+      (PARCEventTimer *)mapMeTFIB_Get(TFIB(fibEntry), conn_in_id);
+  if (!timer) {
+    INFO(mapme,
+         "[MAP-Me]   - Ignored ACK for prefix not having the Connection in "
+         "TFIB entry. Possible duplicate ?");
+    return;
+  }
+
+  /* Stop timer and remove entry from TFIB */
+  parcEventTimer_Stop(timer);
+  mapMeTFIB_Remove(TFIB(fibEntry), conn_in_id);
+
+  INFO(mapme, "[MAP-Me]   - Removing TFIB entry for ack on connection %d",
+       conn_in_id);
+
+  /* We need to update the timestamp only for IU Acks, not for IN Acks */
+  if (params->type == UPDATE_ACK) {
+    INFO(mapme, "[MAP-Me]   - Updating LastAckedUpdate");
+    TFIB(fibEntry)->lastAckedUpdate = forwarder_GetTicks(mapme->forwarder);
+  }
+}
+
+/*-----------------------------------------------------------------------------
+ * Overloaded functions
+ *----------------------------------------------------------------------------*/
+
+/*
+ * @abstract returns where to forward a normal interests(nexthops) defined by
+ * mapme, it also set the sequnence number properly if needed
+ */
+
+/******************************************************************************
+ * Public functions (exposed in the .h)
+ ******************************************************************************/
+
+/*
+ * Returns true iif the message corresponds to a MAP-Me packet
+ */
+bool mapMe_isMapMe(const uint8_t *msgBuffer) {
+  uint8_t next_header = messageHandler_NextHeaderType(msgBuffer);
+
+  const uint8_t *icmp_ptr;
+  if (next_header == IPPROTO_ICMP) {
+    icmp_ptr = msgBuffer + IPV4_HDRLEN;
+  } else if (next_header == IPPROTO_ICMPV6) {
+    icmp_ptr = msgBuffer + IPV6_HDRLEN;
+  } else {
+    return false;
+  }
+
+  uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+  uint8_t code = ((_icmp_header_t *)icmp_ptr)->code;
+  if (HICN_IS_MAPME(type, code)) return true;
+
+  return false;
+}
+
+/**
+ * @discussion The exact type of the MapMe message is determined after
+ * reception. In hICN, Interest Update and Notifications look like regular
+ * Interest packets, and are first punted from the normal path by the forwarder,
+ * then treated as such in the Listener to reach this function. Acknowledgements
+ * are received as Content (Data) packets and will land here too.
+ *
+ * This function is in charge of abstracting the low-level implementation of
+ * MAP-Me (eg. ICMP packets) and return higher level messages that can be
+ * processed by MAP-Me core.
+ */
+void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer,
+                   unsigned conn_id) {
+  hicn_prefix_t prefix;
+  mapme_params_t params;
+  hicn_mapme_parse_packet(msgBuffer, &prefix, &params);
+
+  // XXX Dispatch message dependenging on type
+  switch (params.type) {
+    case UPDATE:
+    case NOTIFICATION:
+      mapMe_onSpecialInterest(mapme, msgBuffer, conn_id, &prefix, &params);
+      break;
+    case UPDATE_ACK:
+    case NOTIFICATION_ACK:
+      mapMe_onSpecialInterestAck(mapme, msgBuffer, conn_id, &prefix, &params);
+      break;
+    default:
+      printf("E:Unknown message\n");
+      break;
+  }
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/core/mapMe.h b/hicn-light/src/core/mapMe.h
new file mode 100755 (executable)
index 0000000..39edd0b
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file mapMe.h
+ * @brief MAP-Me : AnchorLess Producer Mobility Management
+ */
+
+#ifndef mapMe_h
+#define mapMe_h
+
+#ifdef WITH_MAPME
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <src/io/hicnListener.h>
+
+#include <hicn/hicn.h>
+#include <src/utils/commands.h>
+
+struct mapme;
+typedef struct mapme MapMe;
+
+/**
+ * @function MapMe_Init
+ * @abstract Initializes MAP-Me state in the forwarder.
+ * @return bool - Boolean informing about the success of MAP-Me initialization.
+ */
+bool mapMe_Init(MapMe **mapme, Forwarder *Forwarder);
+
+/**
+ * @function messageHandler_isMapMe
+ * @abstract Identifies MAP-Me messages
+ * @discussion This function can be used by the forwarder to dispatch MAP-Me
+ *     message to the appropriate processing function. Ideally this would be
+ *      done through hooks defined in the Init function.
+ * @param [in] msgBuffer - The buffer to match
+ * @return A boolean indicating whether message is a MAP-Me control message.
+ */
+bool mapMe_isMapMe(const uint8_t *msgBuffer);
+
+/**
+ * @function mapMe_handleMapMeMessage
+ * @abstract Process a MAP-Me message.
+ * @param [in] mapme - Pointer to the MAP-Me data structure.
+ * @param [in] message - MAP-Me buffer
+ * @param [in] conn_id - Ingress connection id
+ */
+void mapMe_Process(const MapMe *mapme, const uint8_t *msgBuffer,
+                   unsigned conn_id);
+
+/**
+ * @function mapMe_onConnectionAdded
+ * @abstract Callback following the addition of the face though the control
+ * protocol.
+ * @discussion This callback triggers the sending of control packets by MAP-Me.
+ * @param [in] mapme - Pointer to the MAP-Me data structure.
+ * @param [in] conn - The newly added connection.
+ */
+void mapMe_onConnectionAdded(const MapMe *mapme, const Connection *conn);
+
+/**
+ * @function mapMe_getNextHops
+ * @abstract return the nexthops to forward interests defined by mapme, it
+ *   covers also the case where local discovery mechanisms are trriggered.
+ */
+NumberSet *mapMe_getNextHops(const MapMe *mapme, FibEntry *fibEntry,
+                             const Message *interest);
+
+hicn_mapme_type_t mapMe_PktType_To_LibHicnPktType(MessagePacketType type);
+
+MessagePacketType mapMe_LibHicnPktType_To_PktType(hicn_mapme_type_t type);
+
+#endif /* WITH_MAPME */
+
+#endif  // mapMe_h
diff --git a/hicn-light/src/core/message.c b/hicn-light/src/core/message.c
new file mode 100755 (executable)
index 0000000..6c0e916
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/core/wldr.h>
+
+#include <src/core/messageHandler.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/core/messagePacketType.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+
+struct message {
+  Logger *logger;
+
+  Ticks receiveTime;
+  unsigned ingressConnectionId;
+
+  Name *name;
+
+  uint8_t *messageHead;
+
+  unsigned length;
+
+  uint8_t packetType;
+
+  unsigned refcount;
+};
+
+Message *message_Acquire(const Message *message) {
+  Message *copy = (Message *)message;
+  copy->refcount++;
+  return copy;
+}
+
+Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
+                                       unsigned ingressConnectionId,
+                                       Ticks receiveTime, Logger *logger) {
+  // used by applications, we can get only interest or data packets
+  Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+  parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Message));
+
+  message->logger = logger_Acquire(logger);
+  message->receiveTime = receiveTime;
+  message->ingressConnectionId = ingressConnectionId;
+  message->length = dataLength;
+
+  message->messageHead = parcMemory_AllocateAndClear(dataLength);
+  parcAssertNotNull(message->messageHead,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    dataLength);
+
+  // copy the data because *data is destroyed in the connection.
+  int res = parcEventBuffer_Read(data, message->messageHead, dataLength);
+  if (res == -1) {
+    return NULL;
+  }
+
+  if (messageHandler_IsInterest(message->messageHead)) {
+    message->packetType = MessagePacketType_Interest;
+  } else if (messageHandler_IsData(message->messageHead)) {
+    message->packetType = MessagePacketType_ContentObject;
+  } else {
+    printf("Got a packet that is not a data nor an interest, drop it!\n");
+    return NULL;
+  }
+  message->name =
+      name_CreateFromPacket(message->messageHead, message->packetType);
+
+  message->refcount = 1;
+
+  return message;
+}
+
+Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
+                                     MessagePacketType type, Ticks receiveTime,
+                                     Logger *logger) {
+  Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+  parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Message));
+
+  message->logger = logger_Acquire(logger);
+  message->receiveTime = receiveTime;
+  message->ingressConnectionId = connid;
+  message->messageHead = pckt;
+  message->length = messageHandler_GetTotalPacketLength(pckt);
+  message->packetType = type;
+
+  if (messageHandler_IsWldrNotification(pckt)) {
+    message->name = NULL;
+  } else {
+    message->name =
+        name_CreateFromPacket(message->messageHead, message->packetType);
+  }
+
+  message->refcount = 1;
+
+  return message;
+}
+
+void message_Release(Message **messagePtr) {
+  parcAssertNotNull(messagePtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*messagePtr,
+                    "Parameter must dereference to non-null pointer");
+
+  Message *message = *messagePtr;
+  parcAssertTrue(
+      message->refcount > 0,
+      "Invalid state: message_Release called on message with 0 references %p",
+      (void *)message);
+
+  message->refcount--;
+  if (message->refcount == 0) {
+    if (logger_IsLoggable(message->logger, LoggerFacility_Message,
+                          PARCLogLevel_Debug)) {
+      logger_Log(message->logger, LoggerFacility_Message, PARCLogLevel_Debug,
+                 __func__, "Message %p destroyed", (void *)message);
+    }
+
+    logger_Release(&message->logger);
+    if (message->name != NULL) name_Release(&message->name);
+    parcMemory_Deallocate((void **)&message->messageHead);
+    parcMemory_Deallocate((void **)&message);
+  }
+  *messagePtr = NULL;
+}
+
+bool message_Write(PARCEventQueue *parcEventQueue, const Message *message) {
+  parcAssertNotNull(message, "Message parameter must be non-null");
+  parcAssertNotNull(parcEventQueue, "Buffer parameter must be non-null");
+
+  return parcEventQueue_Write(parcEventQueue, message->messageHead,
+                              message_Length(message));
+}
+
+size_t message_Length(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return message->length;
+}
+
+bool message_HasWldr(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_HasWldr(message->messageHead);
+}
+
+bool message_IsWldrNotification(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_IsWldrNotification(message->messageHead);
+}
+
+void message_ResetWldrLabel(Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_ResetWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrLabel(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_GetWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrExpectedLabel(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_GetExpectedWldrLabel(message->messageHead);
+}
+
+unsigned message_GetWldrLastReceived(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_GetWldrLastReceived(message->messageHead);
+}
+
+void message_SetWldrLabel(Message *message, uint16_t label) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  messageHandler_SetWldrLabel(message->messageHead, label);
+}
+
+Message *message_CreateWldrNotification(Message *original, uint16_t expected,
+                                        uint16_t lastReceived) {
+  parcAssertNotNull(original, "Parameter original must be non-null");
+  Message *message = parcMemory_AllocateAndClear(sizeof(Message));
+  parcAssertNotNull(message, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Message));
+  message->receiveTime = original->receiveTime;
+  message->ingressConnectionId = original->ingressConnectionId;
+  message->refcount = 1;
+  message->logger = logger_Acquire(original->logger);
+
+  message->length = messageHandler_GetICMPPacketSize(
+      messageHandler_GetIPPacketType(original->messageHead));
+  message->messageHead = parcMemory_AllocateAndClear(message->length);
+  parcAssertNotNull(message->messageHead,
+                    "parcMemory_AllocateAndClear returned NULL");
+
+  message->packetType = MessagePacketType_WldrNotification;
+  message->name = NULL;  // nobody will use the name in a notification packet,
+                         // so we can simply set it to NULL
+
+  // set notification stuff.
+  messageHandler_SetWldrNotification(
+      message->messageHead, original->messageHead, expected, lastReceived);
+  // XXX: what about the checksum?
+  return message;
+}
+
+unsigned message_GetIngressConnectionId(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return message->ingressConnectionId;
+}
+
+void message_SetIngressConnectionId(Message *message, unsigned conn) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  message->ingressConnectionId = conn;
+}
+
+Ticks message_GetReceiveTime(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return message->receiveTime;
+}
+
+uint32_t message_GetPathLabel(const Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_GetPathLabel(message->messageHead);
+}
+
+void message_SetPathLabel(Message *message, uint32_t label) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  return messageHandler_SetPathLabel(message->messageHead, label);
+}
+
+void message_UpdatePathLabel(Message *message, uint8_t outFace) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  messageHandler_UpdatePathLabel(message->messageHead, outFace);
+}
+
+void message_ResetPathLabel(Message *message) {
+  parcAssertNotNull(message, "Parameter must be non-null");
+  messageHandler_ResetPathLabel(message->messageHead);
+}
+
+MessagePacketType message_GetType(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  return message->packetType;
+}
+
+Name *message_GetName(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  return message->name;
+}
+
+bool message_HasInterestLifetime(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  return messageHandler_HasInterestLifetime(message->messageHead);
+}
+
+uint64_t message_GetInterestLifetimeTicks(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  uint64_t lifetime = messageHandler_GetInterestLifetime(message->messageHead);
+  return forwarder_NanosToTicks(lifetime * 1000000ULL);
+}
+
+bool message_HasContentExpiryTime(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  return messageHandler_HasContentExpiryTime(message->messageHead);
+}
+
+uint64_t message_GetContentExpiryTimeTicks(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  uint64_t expire = messageHandler_GetContentExpiryTime(message->messageHead);
+  return message->receiveTime + forwarder_NanosToTicks(expire * 1000000ULL);
+}
+
+const uint8_t *message_FixedHeader(const Message *message) {
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  return message->messageHead;
+}
diff --git a/hicn-light/src/core/message.h b/hicn-light/src/core/message.h
new file mode 100755 (executable)
index 0000000..88aa324
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file message.h
+ * @brief Message is the unit of forwarding, i.e. the packets being switched
+ *
+ */
+#ifndef message_h
+#define message_h
+
+#include <src/config.h>
+#include <src/core/logger.h>
+#include <src/core/messagePacketType.h>
+#include <src/core/streamBuffer.h>
+
+#include <src/core/name.h>
+
+#include <parc/algol/parc_EventBuffer.h>
+#include <parc/algol/parc_EventQueue.h>
+
+#include <src/utils/address.h>
+
+#include <src/core/ticks.h>
+
+struct message;
+typedef struct message Message;
+
+/**
+ * @function message_CreateFromBuffer
+ * @abstract Takes ownership of the input buffer, which comprises one complete
+ * message
+ */
+
+Message *message_CreateFromEventBuffer(PARCEventBuffer *data, size_t dataLength,
+                                       unsigned ingressConnectionId,
+                                       Ticks receiveTime, Logger *logger);
+
+/**
+ * @function message_CreateFromByteArray
+ * @abstract create a message from a byte array
+ */
+
+Message *message_CreateFromByteArray(unsigned connid, uint8_t *pckt,
+                                     MessagePacketType type, Ticks receiveTime,
+                                     Logger *logger);
+
+/**
+ * @function message_Copy
+ * @abstract Get a reference counted copy
+ */
+
+Message *message_Acquire(const Message *message);
+
+/**
+ * Releases the message and frees the memory
+ */
+void message_Release(Message **messagePtr);
+
+/**
+ * Writes the message to the queue
+ */
+
+bool message_Write(PARCEventQueue *parcEventQueue, const Message *message);
+
+/**
+ * Returns the total byte length of the message
+ */
+size_t message_Length(const Message *message);
+
+bool message_HasWldr(const Message *message);
+
+bool message_IsWldrNotification(const Message *message);
+
+void message_ResetWldrLabel(Message *message);
+
+unsigned message_GetWldrLabel(const Message *message);
+
+unsigned message_GetWldrExpectedLabel(const Message *message);
+
+unsigned message_GetWldrLastReceived(const Message *message);
+
+void message_SetWldrLabel(Message *message, uint16_t label);
+
+Message *message_CreateWldrNotification(Message *original, uint16_t expected,
+                                        uint16_t lastReceived);
+/**
+ * Returns the connection id of the packet input
+ */
+unsigned message_GetIngressConnectionId(const Message *message);
+
+void message_SetIngressConnectionId(Message *message, unsigned conn);
+
+/**
+ * Returns the receive time (in router ticks) of the message
+ */
+Ticks message_GetReceiveTime(const Message *message);
+
+/**
+ * Returns the PacketType
+ */
+MessagePacketType message_GetType(const Message *message);
+
+uint32_t message_GetPathLabel(const Message *message);
+void message_SetPathLabel(Message *message, uint32_t label);
+void message_UpdatePathLabel(Message *message, uint8_t outFace);
+void message_ResetPathLabel(Message *message);
+
+// ===========================================================
+// Accessors used to index and compare messages
+
+/**
+ * @function message_GetName
+ * @abstract The name in the message
+ * @discussion
+ *   The name of the Interest or Content Object.  If the caller will store the
+ *   name, he should make a reference counted copy.
+ * @return The name as stored in the message object.
+ */
+
+Name *message_GetName(const Message *message);
+
+/**
+ * Determines if the message has an Interest Lifetime parameter
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @retval true If an Intrerest Lifetime field exists
+ * @retval false If no Interest Lifetime exists
+ */
+
+bool message_HasInterestLifetime(const Message *message);
+
+/**
+ * Returns the Interest lifetime in hicn-light Ticks
+ *
+ * the interest expires after now + returned ticks
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @retval integer Lifetime in forwarder Ticks
+ *
+ */
+
+uint64_t message_GetInterestLifetimeTicks(const Message *message);
+
+/**
+ * checks if the expiry time is set inside the content object
+ */
+bool message_HasContentExpiryTime(const Message *message);
+
+/**
+ * returns the moment (in hicn-light ticks) when the content object will expire
+ */
+uint64_t message_GetContentExpiryTimeTicks(const Message *message);
+
+/**
+ * Returns a pointer to the beginning of the FixedHeader
+ *
+ * @param [in] message An allocated and parsed Message
+ *
+ * @return non-null The fixed header memory
+ * @return null No fixed header or an error
+ */
+
+const uint8_t *message_FixedHeader(const Message *message);
+
+#endif  // message_h
diff --git a/hicn-light/src/core/messageHandler.h b/hicn-light/src/core/messageHandler.h
new file mode 100755 (executable)
index 0000000..d636564
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2017-2019 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 messageHandler
+#define messageHandler
+
+#include <stdlib.h>
+
+#include <hicn/hicn.h>
+#include <src/core/messagePacketType.h>
+
+#define H(packet) ((hicn_header_t *)packet)
+#define H6(packet) (H(packet)->v6.ip)
+#define H6T(packet) (H(packet)->v6.tcp)
+#define H4(packet) (H(packet)->v4.ip)
+#define H4T(packet) (H(packet)->v4.tcp)
+
+#define HICN_V6_LEN(packet) (H6(packet).len)
+#define HICN_V4_LEN(packet) (H4(packet).len)
+
+/*** codes and types ***/
+#define IPv6_TYPE 6
+#define IPv4_TYPE 4
+#define ICMP_WLDR_TYPE 42
+#define ICMP_WLDR_CODE 0
+#define ICMP_LB_TYPE 43
+
+/*** masks and constants ***/
+#define PATH_LABEL_MASK 0x8000      // 1000 0000 0000 0000
+#define NOT_PATH_LABEL_MASK 0x7fff  // 0111 0000 0000 0000
+#define UINT16_T_MASK 0x0000ffff    // 1111 1111 1111 1111
+#define NEVER_EXPIRE \
+  16777216  // 2^16 (max urgent pointer) * 2^8 (max reserved + NS bits)
+
+/*** HICN ALLOWED PORTS ***/
+#define CONTROL_PORT 9695
+#define HTTP_PORT 8080
+
+#define IPV6_DEFAULT_VERSION 6
+#define IPV6_DEFAULT_TRAFFIC_CLASS 0
+#define IPV6_DEFAULT_FLOW_LABEL 0
+
+#define expected_lbl wldr_notification_lbl.expected_lbl
+#define received_lbl wldr_notification_lbl.received_lbl
+
+static inline uint8_t messageHandler_GetIPPacketType(const uint8_t *message) {
+  return HICN_IP_VERSION(message);
+}
+
+static inline void messageHandler_UpdateTCPCheckSum(uint8_t *message,
+                                                    uint16_t *old_val,
+                                                    uint16_t *new_val,
+                                                    uint8_t size) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv4_TYPE:
+      for (uint8_t i = 0; i < size; i++) {
+        uint16_t old_csum = ~(H4T(message).csum);
+        uint16_t not_old_val = ~(*old_val);
+        uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+        while (sum >> 16) {
+          sum = (sum >> 16) + (sum & UINT16_T_MASK);
+        }
+
+        H4T(message).csum = ~sum;
+        ++old_val;
+        ++new_val;
+      }
+      break;
+    case IPv6_TYPE:
+      for (uint8_t i = 0; i < size; i++) {
+        uint16_t old_csum = ~(H6T(message).csum);
+        uint16_t not_old_val = ~(*old_val);
+        uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+        while (sum >> 16) {
+          sum = (sum >> 16) + (sum & UINT16_T_MASK);
+        }
+
+        H6T(message).csum = ~sum;
+        ++old_val;
+        ++new_val;
+      }
+      break;
+    default:
+      return;
+  }
+}
+
+static inline void messageHandler_UpdateIPv4CheckSum(uint8_t *message,
+                                                     uint16_t *old_val,
+                                                     uint16_t *new_val,
+                                                     uint8_t size) {
+  for (uint8_t i = 0; i < size; i++) {
+    uint16_t old_csum = ~(H4(message).csum);
+    uint16_t not_old_val = ~(*old_val);
+    uint32_t sum = (uint32_t)old_csum + not_old_val + *new_val;
+
+    while (sum >> 16) {
+      sum = (sum >> 16) + (sum & UINT16_T_MASK);
+    }
+
+    H4(message).csum = ~sum;
+    ++old_val;
+    ++new_val;
+  }
+}
+
+static inline size_t messageHandler_GetEmptyTCPPacketSize(unsigned ipVersion) {
+  if (ipVersion == IPv4_TYPE)
+    return IPV4_HDRLEN + TCP_HDRLEN;
+  else if (ipVersion == IPv6_TYPE)
+    return IPV6_HDRLEN + TCP_HDRLEN;
+  else
+    return 0;
+}
+
+static inline size_t messageHandler_GetICMPPacketSize(unsigned ipVersion) {
+  if (ipVersion == IPv4_TYPE)
+    return IPV4_HDRLEN + ICMP_HDRLEN;
+  else if (ipVersion == IPv6_TYPE)
+    return IPV6_HDRLEN + ICMP_HDRLEN;
+  else
+    return 0;
+}
+
+static inline size_t messageHandler_GetIPHeaderLength(unsigned ipVersion) {
+  if (ipVersion == IPv4_TYPE)
+    return IPV4_HDRLEN;
+  else if (ipVersion == IPv6_TYPE)
+    return IPV6_HDRLEN;
+  else
+    return 0;
+}
+
+static inline bool messageHandler_IsValidHIcnPacket(const uint8_t *message) {
+  uint8_t version = messageHandler_GetIPPacketType(message);
+  if (version == IPv6_TYPE || version == IPv4_TYPE) {
+    return true;
+  }
+  return false;
+}
+
+static inline uint8_t messageHandler_NextHeaderType(const uint8_t *message) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return (uint8_t)H6(message).nxt;
+    case IPv4_TYPE:
+      return (uint8_t)H4(message).protocol;
+    default:
+      return 0;
+  }
+}
+
+static inline bool messageHandler_IsTCP(const uint8_t *message) {
+  if (messageHandler_NextHeaderType(message) != IPPROTO_TCP) return false;
+  return true;
+}
+
+static inline bool messageHandler_IsInterest(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return false;
+
+  bool flag;
+  hicn_packet_test_ece((hicn_header_t *)message,
+                       &flag);  // ECE flag is set to 0 in interest packets
+  if (flag == false) return true;
+  return false;
+}
+
+static inline bool messageHandler_IsData(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return false;
+
+  bool flag;
+  hicn_packet_test_ece((hicn_header_t *)message,
+                       &flag);  // ECE flag is set to 1 in data packets
+  if (flag == true) return true;
+  return false;
+}
+
+static inline bool messageHandler_IsWldrNotification(const uint8_t *message) {
+  // this function returns true only if the packet is an ICMP packet in Wldr
+  // form. type must be equal to ICMP_WLDR_TYPE and code equal to ICMP_WLDR_CODE
+  uint8_t next_header = messageHandler_NextHeaderType(message);
+
+  const uint8_t *icmp_ptr;
+  if (next_header == IPPROTO_ICMP) {
+    icmp_ptr = message + IPV4_HDRLEN;
+  } else if (next_header == IPPROTO_ICMPV6) {
+    icmp_ptr = message + IPV6_HDRLEN;
+  } else {
+    return false;
+  }
+
+  uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+  uint8_t code = ((_icmp_header_t *)icmp_ptr)->code;
+  if (type == ICMP_WLDR_TYPE && code == ICMP_WLDR_CODE) {
+    return true;
+  }
+
+  return false;
+}
+
+static inline bool messageHandler_IsLoadBalancerProbe(const uint8_t *message) {
+  uint8_t next_header = messageHandler_NextHeaderType(message);
+
+  const uint8_t *icmp_ptr;
+  if (next_header == IPPROTO_ICMP) {
+    icmp_ptr = message + IPV4_HDRLEN;
+  } else if (next_header == IPPROTO_ICMPV6) {
+    icmp_ptr = message + IPV6_HDRLEN;
+  } else {
+    return false;
+  }
+
+  uint8_t type = ((_icmp_header_t *)icmp_ptr)->type;
+  if (type == ICMP_LB_TYPE) {
+    return true;
+  }
+
+  return false;
+}
+
+static inline uint16_t messageHandler_GetTotalPacketLength(
+    const uint8_t *message) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return ntohs((uint16_t)HICN_V6_LEN(message)) + IPV6_HDRLEN;
+    case IPv4_TYPE:
+      return ntohs((uint16_t)HICN_V4_LEN(message));
+    default:
+      return 0;
+  }
+}
+
+static inline uint32_t messageHandler_GetSegment(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return 0;
+
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return ntohl((uint32_t)H6T(message).seq);
+    case IPv4_TYPE:
+      return ntohl((uint32_t)H4T(message).seq);
+    default:
+      return 0;
+  }
+}
+
+static inline uint16_t messageHandler_GetExpectedWldrLabel(
+    const uint8_t *message) {
+  const uint8_t *icmp_ptr;
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      icmp_ptr = message + IPV6_HDRLEN;
+      break;
+    case IPv4_TYPE:
+      icmp_ptr = message + IPV4_HDRLEN;
+      break;
+    default:
+      return 0;
+  }
+
+  return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->expected_lbl);
+}
+
+static inline uint16_t messageHandler_GetWldrLastReceived(
+    const uint8_t *message) {
+  const uint8_t *icmp_ptr;
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      icmp_ptr = message + IPV6_HDRLEN;
+      break;
+    case IPv4_TYPE:
+      icmp_ptr = message + IPV4_HDRLEN;
+      break;
+    default:
+      return 0;
+  }
+
+  return ntohs(((_icmp_wldr_header_t *)icmp_ptr)->received_lbl);
+}
+
+static inline uint16_t messageHandler_GetWldrLabel(const uint8_t *message) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return ntohs((uint16_t)H6T(message).window);
+    case IPv4_TYPE:
+      return ntohs((uint16_t)H4T(message).window);
+    default:
+      return 0;
+  }
+}
+
+static inline void messageHandler_SetWldrLabel(uint8_t *message,
+                                               uint16_t label) {
+  uint16_t old_val = messageHandler_GetWldrLabel(message);
+
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      H6T(message).window = htons(label);
+      break;
+    case IPv4_TYPE:
+      H4T(message).window = htons(label);
+      break;
+    default:
+      break;
+  }
+
+  messageHandler_UpdateTCPCheckSum(message, &old_val, &label, 1);
+}
+
+static inline void messageHandler_ResetWldrLabel(uint8_t *message) {
+  messageHandler_SetWldrLabel(message, 0);
+}
+
+static inline bool messageHandler_HasWldr(const uint8_t *message) {
+  if (messageHandler_IsTCP(message)) {
+    uint16_t lbl = messageHandler_GetWldrLabel(message);
+    if (lbl != 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static inline uint8_t messageHandler_GetProbePacketType(
+    const uint8_t *message) {
+  const uint8_t *icmp_ptr;
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      icmp_ptr = message + IPV6_HDRLEN;
+      break;
+    case IPv4_TYPE:
+      icmp_ptr = message + IPV4_HDRLEN;
+      break;
+    default:
+      return 0;
+  }
+
+  return ((_icmp_header_t *)icmp_ptr)->code;
+}
+
+static inline uint32_t messageHandler_GetPathLabel(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return 0;
+
+  uint32_t path_label;
+  int res = hicn_data_get_path_label((hicn_header_t *)message, &path_label);
+  if (res < 0) return 0;
+  return path_label;
+}
+
+static inline void messageHandler_SetPathLabel(uint8_t *message,
+                                               uint32_t new_path_label) {
+  if (!messageHandler_IsTCP(message)) return;
+
+  uint32_t old_path_label;
+  int res = hicn_data_get_path_label((hicn_header_t *)message, &old_path_label);
+  if (res < 0) return;
+
+  hicn_data_set_path_label((hicn_header_t *)message, new_path_label);
+
+  messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&old_path_label,
+                                   (uint16_t *)&new_path_label, 2);
+}
+
+static inline void messageHandler_UpdatePathLabel(uint8_t *message,
+                                                  uint8_t outFace) {
+  if (!messageHandler_IsTCP(message)) return;
+
+  uint32_t pl_old_32bit = messageHandler_GetPathLabel(message);
+  uint8_t pl_old_8bit = (uint8_t)(pl_old_32bit >> 24UL);
+  uint32_t pl_new_32bit =
+      (uint32_t)((((pl_old_8bit << 1) | (pl_old_8bit >> 7)) ^ outFace) << 24UL);
+
+  hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit);
+
+  messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit,
+                                   (uint16_t *)&pl_new_32bit, 2);
+}
+
+static inline void messageHandler_ResetPathLabel(uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return;
+
+  uint32_t pl_old_32bit = messageHandler_GetPathLabel(message);
+  uint32_t pl_new_32bit = 0;
+  hicn_data_set_path_label((hicn_header_t *)message, pl_new_32bit);
+  messageHandler_UpdateTCPCheckSum(message, (uint16_t *)&pl_old_32bit,
+                                   (uint16_t *)&pl_new_32bit, 2);
+}
+
+static inline uint16_t messageHandler_GetInterestLifetime(
+    const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return 0;
+
+  hicn_lifetime_t lifetime;
+  int res = hicn_interest_get_lifetime((hicn_header_t *)message, &lifetime);
+  if (res < 0) return 0;
+  return lifetime;
+}
+
+static inline bool messageHandler_HasInterestLifetime(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return false;
+
+  if (messageHandler_GetInterestLifetime(message) == 0) return false;
+  return true;
+}
+
+static inline uint32_t messageHandler_GetContentExpiryTime(
+    const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return 0;
+
+  uint32_t expirationTime;
+  int res =
+      hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime);
+  if (res < 0) return 0;
+  return expirationTime;
+}
+
+static inline bool messageHandler_HasContentExpiryTime(const uint8_t *message) {
+  if (!messageHandler_IsTCP(message)) return 0;
+
+  uint32_t expirationTime;
+  int res =
+      hicn_data_get_expiry_time((hicn_header_t *)message, &expirationTime);
+  if (res < 0) return false;
+
+  if (expirationTime == NEVER_EXPIRE) return false;
+
+  return true;
+}
+
+static inline void *messageHandler_GetSource(const uint8_t *message) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return &H6(message).saddr;
+      break;
+    case IPv4_TYPE:
+      return &H4(message).saddr;
+      break;
+    default:
+      return NULL;
+  }
+}
+
+static inline void *messageHandler_GetDestination(const uint8_t *message) {
+  switch (messageHandler_GetIPPacketType(message)) {
+    case IPv6_TYPE:
+      return &H6(message).daddr;
+      break;
+    case IPv4_TYPE:
+      return &H4(message).daddr;
+      break;
+    default:
+      return NULL;
+  }
+}
+
+static inline void messageHandler_SetSource_IPv6(uint8_t *message,
+                                                 struct in6_addr *address) {
+  if (messageHandler_IsTCP(message)) {
+    uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message);
+    messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 8);
+  }
+  H6(message).saddr.as_in6addr = *address;
+}
+
+static inline void messageHandler_SetDestination_IPv6(
+    uint8_t *message, struct in6_addr *address) {
+  if (messageHandler_IsTCP(message)) {
+    uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message);
+    messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 8);
+  }
+  H6(message).daddr.as_in6addr = *address;
+}
+
+static inline void messageHandler_SetSource_IPv4(uint8_t *message,
+                                                 uint32_t *address) {
+  // update tcp checksum
+  uint16_t *old_src = (uint16_t *)messageHandler_GetSource(message);
+  if (messageHandler_IsTCP(message)) {
+    messageHandler_UpdateTCPCheckSum(message, old_src, (uint16_t *)address, 2);
+  }
+  // update IPv4 cheksum
+  // the IPv4 checksum is not part of the psudo header for TCP checksum
+  // calculation we can update them separetelly
+  messageHandler_UpdateIPv4CheckSum(message, old_src, (uint16_t *)address, 2);
+
+  H4(message).saddr.as_u32 = *address;
+}
+
+static inline void messageHandler_SetDestination_IPv4(uint8_t *message,
+                                                      uint32_t *address) {
+  uint16_t *old_dst = (uint16_t *)messageHandler_GetDestination(message);
+  if (messageHandler_IsTCP(message)) {
+    messageHandler_UpdateTCPCheckSum(message, old_dst, (uint16_t *)address, 2);
+  }
+  messageHandler_UpdateIPv4CheckSum(message, old_dst, (uint16_t *)address, 2);
+  H4(message).daddr.as_u32 = *address;
+}
+
+static inline void messageHandler_SetWldrNotification(uint8_t *notification,
+                                                      uint8_t *original,
+                                                      uint16_t expected,
+                                                      uint16_t received) {
+  hicn_header_t *h = (hicn_header_t *)notification;
+  switch (messageHandler_GetIPPacketType(original)) {
+    case IPv6_TYPE: {
+      *h = (hicn_header_t){.v6 = {
+                               .ip =
+                                   {
+                                       .version_class_flow = htonl(
+                                           (IPV6_DEFAULT_VERSION << 28) |
+                                           (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+                                           (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+                                       .len = htons(ICMP_HDRLEN),
+                                       .nxt = IPPROTO_ICMPV6,
+                                       .hlim = 5,
+                                   },
+                               .wldr =
+                                   {
+                                       .type = ICMP_WLDR_TYPE,
+                                       .code = ICMP_WLDR_CODE,
+                                       .expected_lbl = htons(expected),
+                                       .received_lbl = htons(received),
+                                   },
+                           }};
+      messageHandler_SetSource_IPv6(
+          notification,
+          (struct in6_addr *)messageHandler_GetDestination(original));
+      messageHandler_SetDestination_IPv6(
+          notification, (struct in6_addr *)messageHandler_GetSource(original));
+      break;
+    }
+    case IPv4_TYPE: {
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static inline void messageHandler_SetProbePacket(uint8_t *message,
+                                                 uint8_t probeType,
+                                                 struct in6_addr *src,
+                                                 struct in6_addr *dst) {
+  hicn_header_t *h = (hicn_header_t *)message;
+  *h = (hicn_header_t){
+      .v6 = {
+          .ip =
+              {
+                  .version_class_flow =
+                      htonl((IPV6_DEFAULT_VERSION << 28) |
+                            (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+                            (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+                  .len = htons(ICMP_HDRLEN),
+                  .nxt = IPPROTO_ICMPV6,
+                  .hlim = 5,  // this should be 1, but ... just to be safe
+              },
+          .icmp =
+              {
+                  .type = ICMP_LB_TYPE,
+                  .code = probeType,
+              },
+      }};
+  messageHandler_SetSource_IPv6(message, src);
+  messageHandler_SetDestination_IPv6(message, dst);
+}
+
+#endif  // Metis_metis_MessageHandler
diff --git a/hicn-light/src/core/messagePacketType.h b/hicn-light/src/core/messagePacketType.h
new file mode 100755 (executable)
index 0000000..dfbb123
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file message_packet_type_h
+ * @brief Defines the packet type for a HICN message
+ *
+ */
+
+#ifndef message_packet_type_h
+#define message_packet_type_h
+
+typedef enum message_type {
+  MessagePacketType_Unknown,
+  MessagePacketType_Interest,
+  MessagePacketType_ContentObject,
+  MessagePacketType_WldrNotification
+} MessagePacketType;
+
+#endif  // message_packet_type_h
diff --git a/hicn-light/src/core/name.c b/hicn-light/src/core/name.c
new file mode 100755 (executable)
index 0000000..f6a452d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2017-2019 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 <limits.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/messageHandler.h>
+#include <src/core/name.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#define IPv6_TYPE 6
+#define IPv4_TYPE 4
+
+// assumption: the IPv6 address is the name, the TCP segment number is the ICN
+// segment
+
+struct name {
+  NameBitvector *content_name;
+  uint32_t segment;
+  uint32_t name_hash;
+  // the refcount is shared between all copies
+  unsigned *refCountPtr;
+};
+
+// =====================================================
+
+static unsigned _getRefCount(const Name *name) { return *name->refCountPtr; }
+
+static void _incrementRefCount(Name *name) {
+  parcAssertTrue(*name->refCountPtr > 0,
+                 "Illegal State: Trying to increment a 0 refcount!");
+  (*name->refCountPtr)++;
+}
+
+static void _decrementRefCount(Name *name) {
+  parcAssertTrue(*name->refCountPtr > 0,
+                 "Illegal State: Trying to decrement a 0 refcount!");
+  (*name->refCountPtr)--;
+}
+
+static uint32_t _computeHash(Name *name) {
+  parcAssertNotNull(name, "Parameter must be non-null pointer");
+
+  uint32_t hash1 = nameBitvector_GetHash32(name->content_name);
+  return parcHash32_Data_Cumulative((const uint8_t *)&name->segment, 4, hash1);
+}
+
+// ============================================================================
+
+Name *name_CreateFromPacket(const uint8_t *packet, MessagePacketType type) {
+  Name *name = parcMemory_AllocateAndClear(sizeof(Name));
+  parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Name));
+
+  if (messageHandler_GetIPPacketType(packet) == IPv6_TYPE) {
+    if (type == MessagePacketType_Interest) {
+      name->content_name = nameBitvector_CreateFromIn6Addr(
+          (struct in6_addr *)messageHandler_GetDestination(packet), 128);
+    } else if (type == MessagePacketType_ContentObject) {
+      name->content_name = nameBitvector_CreateFromIn6Addr(
+          (struct in6_addr *)messageHandler_GetSource(packet), 128);
+    } else {
+      parcMemory_Deallocate((void **)&name);
+      return NULL;
+    }
+  } else if (messageHandler_GetIPPacketType(packet) == IPv4_TYPE) {
+    if (type == MessagePacketType_Interest) {
+      name->content_name = nameBitvector_CreateFromInAddr(
+          *((uint32_t *)messageHandler_GetDestination(packet)), 32);
+    } else if (type == MessagePacketType_ContentObject) {
+      name->content_name = nameBitvector_CreateFromInAddr(
+          *((uint32_t *)messageHandler_GetSource(packet)), 32);
+    } else {
+      parcMemory_Deallocate((void **)&name);
+      return NULL;
+    }
+  } else {
+    printf("Error: unknown message type\n");
+    parcMemory_Deallocate((void **)&name);
+    return NULL;
+  }
+
+  name->segment = messageHandler_GetSegment(packet);
+  name->name_hash = _computeHash(name);
+
+  name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
+  parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
+                    sizeof(unsigned));
+  *name->refCountPtr = 1;
+  return name;
+}
+
+Name *name_CreateFromAddress(address_type addressType, union commandAddr addr,
+                             uint8_t len) {
+  Name *name = parcMemory_AllocateAndClear(sizeof(Name));
+  parcAssertNotNull(name, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Name));
+  if (addressType == ADDR_INET) {
+    name->content_name = nameBitvector_CreateFromInAddr(addr.ipv4, len);
+  } else if (addressType == ADDR_INET6) {
+    name->content_name = nameBitvector_CreateFromIn6Addr(&addr.ipv6, len);
+  } else {
+    parcTrapNotImplemented("Unkown packet type");
+  }
+
+  name->segment = 0;
+  name->name_hash = _computeHash(name);
+
+  name->refCountPtr = parcMemory_Allocate(sizeof(unsigned));
+  parcAssertNotNull(name->refCountPtr, "parcMemory_Allocate(%zu) returned NULL",
+                    sizeof(unsigned));
+  *name->refCountPtr = 1;
+
+  return name;
+}
+
+void name_Release(Name **namePtr) {
+  parcAssertNotNull(namePtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*namePtr, "Parameter must dereference to non-null pointer");
+
+  Name *name = *namePtr;
+  _decrementRefCount(name);
+  if (_getRefCount(name) == 0) {
+    parcMemory_Deallocate((void **)&(name->refCountPtr));
+    nameBitvector_Destroy(&(name->content_name));
+  }
+  parcMemory_Deallocate((void **)&name);
+  *namePtr = NULL;
+}
+
+Name *name_Acquire(const Name *original) {
+  parcAssertNotNull(original, "Parameter must be non-null");
+  Name *copy = parcMemory_AllocateAndClear(sizeof(Name));
+  parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Name));
+
+  memcpy(copy, original, sizeof(Name));
+  _incrementRefCount(copy);
+
+  return copy;
+}
+
+uint32_t name_HashCode(const Name *name) {
+  parcAssertNotNull(name, "Parameter must be non-null");
+  return name->name_hash;
+}
+
+NameBitvector *name_GetContentName(const Name *name) {
+  parcAssertNotNull(name, "Parameter must be non-null");
+  return name->content_name;
+}
+
+bool name_Equals(const Name *a, const Name *b) {
+  parcAssertNotNull(a, "Parameter a must be non-null");
+  parcAssertNotNull(b, "Parameter b must be non-null");
+
+  if ((nameBitvector_Equals(a->content_name, b->content_name) &&
+       a->segment == b->segment))
+    return true;
+  return false;
+}
+
+int name_Compare(const Name *a, const Name *b) {
+  parcAssertNotNull(a, "Parameter a must be non-null");
+  parcAssertNotNull(b, "Parameter b must be non-null");
+
+  if (a == NULL && b == NULL) {
+    return 0;
+  }
+  if (a == NULL) {
+    return -1;
+  }
+  if (b == NULL) {
+    return +1;
+  }
+
+  int res = nameBitvector_Compare(a->content_name, b->content_name);
+
+  if (res != 0) {
+    return res;
+  } else {
+    if (a->segment < b->segment) {
+      return -1;
+    } else if (a->segment > b->segment) {
+      return +1;
+    } else {
+      return 0;
+    }
+  }
+}
+
+bool name_StartsWith(const Name *name, const Name *prefix) {
+  parcAssertNotNull(name, "Parameter name must be non-null");
+  parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+  return nameBitvector_StartsWith(name->content_name, prefix->content_name);
+}
+
+char *name_ToString(const Name *name) {
+  char *output = malloc(128);
+
+  Address *packetAddr = nameBitvector_ToAddress(name_GetContentName(name));
+
+  sprintf(output, "name: %s seq: %u", addressToString(packetAddr),
+          name->segment);
+
+  addressDestroy(&packetAddr);
+
+  return output;
+}
+
+void name_setLen(const Name *name, uint8_t len) {
+  nameBitvector_setLen(name->content_name, len);
+}
diff --git a/hicn-light/src/core/name.h b/hicn-light/src/core/name.h
new file mode 100755 (executable)
index 0000000..fb4ad7a
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017-2019 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 name_h
+#define name_h
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <src/core/messagePacketType.h>
+#include <src/core/nameBitvector.h>
+#include <src/utils/address.h>
+
+#include <src/utils/commands.h>
+
+struct name;
+typedef struct name Name;
+
+/**
+ * Creates a name from packet
+ *
+ */
+Name *name_CreateFromPacket(const uint8_t *memory, MessagePacketType type);
+
+/**
+ * Releases one reference count, and frees memory after last reference
+ */
+void name_Release(Name **namePtr);
+
+/**
+ * Acquires a reference to the name so that a reference count increments.
+ * Notice however that this * function is used only when a new fib entry is
+ * created (mostly configuration time) probably here performance are not
+ * critical.
+ */
+Name *name_Acquire(const Name *original);
+
+/**
+ * A hash value for use in hash tables
+ *
+ */
+uint32_t name_HashCode(const Name *name);
+
+/**
+ * Returns the content name without the segment value
+ *
+ */
+NameBitvector *name_GetContentName(const Name *name);
+
+/**
+ * Determine if two HicnName instances are equal.
+ */
+bool name_Equals(const Name *a, const Name *b);
+
+/**
+ * Compares two names and returns their ordering
+ *
+ */
+int name_Compare(const Name *a, const Name *b);
+
+/**
+ * @function metsName_StartsWith
+ * @abstract Checks if name starts with prefix
+ * @discussion
+ *   Byte-by-byte prefix comparison
+ *
+ * @return True if the name is equal to or begins with prefix
+ */
+
+bool name_StartsWith(const Name *name, const Name *prefix);
+
+/**
+ * return the name in string format (bitvector + segment number)
+ *
+ */
+char *name_ToString(const Name *name);
+
+/**
+ * @function message_setNameLen
+ * @abstract Sets a message name length
+ * @param [in] message - Interest message
+ * @param [in] len - Name length
+ */
+void name_setLen(const Name *name, uint8_t len);
+
+/**
+ * Creates a name from a Address
+ *
+ */
+Name *name_CreateFromAddress(address_type addressType, union commandAddr addr,
+                             uint8_t len);
+
+#endif  // name_h
diff --git a/hicn-light/src/core/nameBitvector.c b/hicn-light/src/core/nameBitvector.c
new file mode 100755 (executable)
index 0000000..66f3eae
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/messageHandler.h>
+#include <src/core/nameBitvector.h>
+
+#include <parc/algol/parc_Hash.h>
+
+#include <src/utils/commands.h>
+
+#define BLOCKS 2
+
+const uint64_t BLOCK_SIZE = 64;
+const uint64_t WIDTH = 128;
+const uint64_t BLOCK_ONE = 0x1;
+
+// the bits are encoded in the following order:
+// 00100101001---101010  00100011---110100100
+// [bits[0] (uint64_t)]  [bits[1] (uint64_t)]
+// ^                  ^  ^                  ^
+// 0                 63 64                127
+// address  2200::0011 is encoded as:
+//   1000 1000 0000 0010 00000 ....0100 0100
+//   ^                                     ^
+//   0                                   127
+
+struct name_bitvector {
+  uint64_t bits[BLOCKS];
+  uint8_t len;
+  uint8_t IPversion;
+};
+
+NameBitvector *nameBitvector_CreateFromInAddr(uint32_t s_addr, uint8_t len) {
+  NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+  parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(NameBitvector));
+
+  bitvector->bits[0] = 0;
+  bitvector->bits[1] = 0;
+
+  uint8_t addr_1 = (s_addr & 0xff000000) >> 24;
+  uint8_t addr_2 = (s_addr & 0x00ff0000) >> 16;
+  uint8_t addr_3 = (s_addr & 0x0000ff00) >> 8;
+  uint8_t addr_4 = (s_addr & 0x000000ff);
+
+  bitvector->bits[1] = (bitvector->bits[1] | addr_4) << 8;
+  bitvector->bits[1] = (bitvector->bits[1] | addr_3) << 8;
+  bitvector->bits[1] = (bitvector->bits[1] | addr_2) << 8;
+  bitvector->bits[1] = (bitvector->bits[1] | addr_1);
+  bitvector->bits[1] = bitvector->bits[1] << 32;
+
+  bitvector->len = len;
+
+  bitvector->IPversion = IPv4_TYPE;
+
+  return bitvector;
+}
+
+NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr,
+                                               uint8_t len) {
+  parcAssertNotNull(addr, "addr cannot be null");
+
+  NameBitvector *bitvector = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+  parcAssertNotNull(bitvector, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(NameBitvector));
+
+  bitvector->bits[0] = 0;
+  bitvector->bits[1] = 0;
+
+  for (int i = 0; i < 8; ++i) {
+    bitvector->bits[1] = (bitvector->bits[1] << 8) | addr->s6_addr[i];
+  }
+
+  for (int i = 8; i < 16; ++i) {
+    bitvector->bits[0] = (bitvector->bits[0] << 8) | addr->s6_addr[i];
+  }
+
+  bitvector->len = len;
+
+  bitvector->IPversion = IPv6_TYPE;
+
+  return bitvector;
+}
+
+NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix,
+                                               uint8_t len) {
+  parcAssertNotNull(prefix, "prefix cannot be null");
+
+  NameBitvector *bitvector = NULL;
+  switch (addressGetType(prefix)) {
+    case ADDR_INET: {
+      struct sockaddr_in addr;
+      addressGetInet(prefix, &addr);
+      bitvector = nameBitvector_CreateFromInAddr(addr.sin_addr.s_addr, len);
+      break;
+    }
+    case ADDR_INET6: {
+      struct sockaddr_in6 addr;
+      addressGetInet6(prefix, &addr);
+      bitvector = nameBitvector_CreateFromIn6Addr(&addr.sin6_addr, len);
+      break;
+    }
+    default:
+      parcTrapNotImplemented("Unkown packet type");
+      break;
+  }
+
+  return bitvector;
+}
+
+NameBitvector *nameBitvector_Copy(const NameBitvector *original) {
+  parcAssertNotNull(original, "original cannot be null");
+
+  NameBitvector *copy = parcMemory_AllocateAndClear(sizeof(NameBitvector));
+  parcAssertNotNull(copy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(NameBitvector));
+
+  copy->bits[0] = original->bits[0];
+  copy->bits[1] = original->bits[1];
+  copy->len = original->len;
+
+  return copy;
+}
+
+void nameBitvector_Destroy(NameBitvector **bitvectorPtr) {
+  parcAssertNotNull(bitvectorPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*bitvectorPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  NameBitvector *bv = *bitvectorPtr;
+  parcMemory_Deallocate((void **)&(bv));
+  *bitvectorPtr = NULL;
+}
+
+uint8_t nameBitvector_GetLength(const NameBitvector *name) { return name->len; }
+
+uint32_t nameBitvector_GetHash32(const NameBitvector *name) {
+  return parcHash32_Data_Cumulative((const uint8_t *)name->bits, 16, 0);
+}
+
+bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b) {
+  if (a->bits[0] == b->bits[0] && a->bits[1] == b->bits[1] && a->len == b->len)
+    return true;
+  return false;
+}
+
+int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b) {
+  if (a == NULL && b == NULL) {
+    return 0;
+  }
+  if (a == NULL) {
+    return -1;
+  }
+  if (b == NULL) {
+    return +1;
+  }
+
+  if (a->bits[0] < b->bits[0]) {
+    return -1;
+  } else if (a->bits[0] > b->bits[0]) {
+    return +1;
+  } else if (a->bits[1] < b->bits[1]) {
+    return -1;
+  } else if (a->bits[1] > b->bits[1]) {
+    return +1;
+  } else if (a->len < b->len) {
+    return -1;
+  } else if (a->len > b->len) {
+    return +1;
+  } else {
+    return 0;
+  }
+}
+
+bool nameBitvector_StartsWith(const NameBitvector *name,
+                              const NameBitvector *prefix) {
+  parcAssertNotNull(name, "name cannot be NULL");
+  parcAssertNotNull(prefix, "prefix cannot be NULL");
+  parcAssertTrue(prefix->len > 0, "prefix length can not be 0");
+
+  if (prefix->len > BLOCK_SIZE)
+    return (name->bits[1] == prefix->bits[1]) &&
+           ((name->bits[0] ^ prefix->bits[0]) >>
+                (BLOCK_SIZE - (prefix->len - BLOCK_SIZE)) ==
+            0);
+
+  return ((name->bits[1] ^ prefix->bits[1]) >> (BLOCK_SIZE - prefix->len) == 0);
+}
+
+bool nameBitvector_testBit(const NameBitvector *name, uint8_t pos) {
+  if (pos == WIDTH) pos = 127;
+
+  uint8_t final_pos = WIDTH - name->len;
+
+  // the bit to test is inside the name/prefix len
+  if (pos > final_pos) {
+    return (name->bits[pos / BLOCK_SIZE] & (BLOCK_ONE << (pos % BLOCK_SIZE)));
+  }
+
+  // the bit to test is outside the name/prefix len
+  if (pos < final_pos) {
+    return false;
+  }
+
+  // pos is equal to the name/prefix len
+  return true;
+}
+
+uint64_t _diff_bit_log2(uint64_t val) {
+  // base 2 log of an uint64_t. This is the same as get the position of
+  // the highest bit set (or most significant bit set, MSB)
+  uint64_t result = 0;
+
+  if (val & 0xFFFFFFFF00000000) {
+    val = val >> 32;
+    result = result | 32;
+  }
+  if (val & 0xFFFF0000) {
+    val = val >> 16;
+    result = result | 16;
+  }
+  if (val & 0xFF00) {
+    val = val >> 8;
+    result = result | 8;
+  }
+  if (val & 0xF0) {
+    val = val >> 4;
+    result = result | 4;
+  }
+  if (val & 0xC) {
+    val = val >> 2;
+    result = result | 2;
+  }
+  if (val & 0x2) {
+    val = val >> 1;
+    result = result | 1;
+  }
+  return result;
+}
+
+uint8_t nameBitvector_firstDiff(const NameBitvector *a,
+                                const NameBitvector *b) {
+  uint8_t res = 0;
+  uint64_t diff = a->bits[1] ^ b->bits[1];
+  if (diff)
+    res = 64 + _diff_bit_log2(diff);
+  else
+    res = _diff_bit_log2(a->bits[0] ^ b->bits[0]);
+
+  // res is computed over the bitvector which is composed by 128 bit all the
+  // times however the prefixes may be diffrent just because the have different
+  // lengths example: prefix 1: 0::/30 prefix 2: 0::/20 at this point of the
+  // function res would be 0 since both the bitvectors are composed by 0s but the
+  // function will return 127-20, which is the position at which the two prefix
+  // are different, since prefix 2 has only 20 bits
+
+  uint8_t len_diff;
+  if (a->len < b->len)
+    len_diff = WIDTH - a->len;
+  else
+    len_diff = WIDTH - b->len;
+
+  if (len_diff > res) res = len_diff;
+
+  return res;
+}
+
+int nameBitvector_ToIPAddress(const NameBitvector *name,
+                              ip_address_t *ip_address) {
+  if (name->IPversion == IPv4_TYPE) {
+    struct in_addr *addr = (struct in_addr *)(&ip_address->buffer);
+    ip_address->family = AF_INET;
+    ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
+
+    uint32_t tmp_addr = name->bits[1] >> 32ULL;
+    uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+    uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+    uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+    uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+    addr->s_addr = 0;
+    addr->s_addr = (addr->s_addr | addr_4) << 8;
+    addr->s_addr = (addr->s_addr | addr_3) << 8;
+    addr->s_addr = (addr->s_addr | addr_2) << 8;
+    addr->s_addr = (addr->s_addr | addr_1);
+
+  } else {
+    struct in6_addr *addr = (struct in6_addr *)(&ip_address->buffer);
+    ip_address->family = AF_INET6;
+    ip_address->prefix_len = name->len;  // IPV6_ADDR_LEN_BITS;
+
+    for (int i = 0; i < 8; i++) {
+      addr->s6_addr[i] = (uint8_t)((name->bits[1] >> 8 * (7 - i)) & 0xFF);
+    }
+
+    int x = 0;
+    for (int i = 8; i < 16; ++i) {
+      addr->s6_addr[i] = (uint8_t)((name->bits[0] >> 8 * (7 - x)) & 0xFF);
+      x++;
+    }
+  }
+  return true;
+}
+
+void nameBitvector_setLen(NameBitvector *name, uint8_t len) { name->len = len; }
+
+Address *nameBitvector_ToAddress(const NameBitvector *name) {
+  if (name->IPversion == IPv4_TYPE) {
+    struct sockaddr_in addr;
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(1234);
+
+    uint32_t tmp_addr = name->bits[1] >> 32ULL;
+    uint8_t addr_1 = (tmp_addr & 0xff000000) >> 24;
+    uint8_t addr_2 = (tmp_addr & 0x00ff0000) >> 16;
+    uint8_t addr_3 = (tmp_addr & 0x0000ff00) >> 8;
+    uint8_t addr_4 = (tmp_addr & 0x000000ff);
+
+    addr.sin_addr.s_addr = 0;
+    addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_4) << 8;
+    addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_3) << 8;
+    addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_2) << 8;
+    addr.sin_addr.s_addr = (addr.sin_addr.s_addr | addr_1);
+
+    Address *packetAddr = addressCreateFromInet(&addr);
+
+    return packetAddr;
+
+  } else {
+    struct sockaddr_in6 addr;
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(1234);
+    addr.sin6_scope_id = 0;
+    addr.sin6_flowinfo = 0;
+
+    for (int i = 0; i < 8; i++) {
+      addr.sin6_addr.s6_addr[i] =
+          (uint8_t)((name->bits[1] >> 8 * (7 - i)) & 0xFF);
+    }
+
+    int x = 0;
+    for (int i = 8; i < 16; ++i) {
+      addr.sin6_addr.s6_addr[i] =
+          (uint8_t)((name->bits[0] >> 8 * (7 - x)) & 0xFF);
+      x++;
+    }
+
+    Address *packetAddr = addressCreateFromInet6(&addr);
+
+    return packetAddr;
+  }
+}
+
+char *nameBitvector_ToString(const NameBitvector *name) {
+  char *output = malloc(WIDTH);
+
+  Address *packetAddr = nameBitvector_ToAddress(name);
+
+  sprintf(output, "prefix: %s len: %u", addressToString(packetAddr), name->len);
+
+  addressDestroy(&packetAddr);
+
+  return output;
+}
\ No newline at end of file
diff --git a/hicn-light/src/core/nameBitvector.h b/hicn-light/src/core/nameBitvector.h
new file mode 100755 (executable)
index 0000000..28a31dc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017-2019 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 name_bitvector_h
+#define name_bitvector_h
+
+#include <hicn/hicn.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <src/utils/address.h>
+
+struct name_bitvector;
+typedef struct name_bitvector NameBitvector;
+
+NameBitvector *nameBitvector_CreateFromInAddr(uint32_t s_addr, uint8_t len);
+
+NameBitvector *nameBitvector_CreateFromIn6Addr(struct in6_addr *addr,
+                                               uint8_t len);
+
+NameBitvector *nameBitvector_CreateFromAddress(const Address *prefix,
+                                               uint8_t len);
+
+NameBitvector *nameBitvector_Copy(const NameBitvector *original);
+
+void nameBitvector_Destroy(NameBitvector **bitvectorPtr);
+
+uint8_t nameBitvector_GetLength(const NameBitvector *name);
+
+uint32_t nameBitvector_GetHash32(const NameBitvector *name);
+
+bool nameBitvector_Equals(const NameBitvector *a, const NameBitvector *b);
+
+int nameBitvector_Compare(const NameBitvector *a, const NameBitvector *b);
+
+bool nameBitvector_StartsWith(const NameBitvector *name,
+                              const NameBitvector *prefix);
+
+bool nameBitvector_testBit(const NameBitvector *name, uint8_t pos);
+
+uint8_t nameBitvector_firstDiff(const NameBitvector *a, const NameBitvector *b);
+
+int nameBitvector_ToIPAddress(const NameBitvector *name,
+                              ip_address_t *ip_address);
+void nameBitvector_setLen(NameBitvector *name, uint8_t len);
+
+Address *nameBitvector_ToAddress(const NameBitvector *name);
+
+char *nameBitvector_ToString(const NameBitvector *name);
+
+#endif  // name_bitvector_h
diff --git a/hicn-light/src/core/numberSet.c b/hicn-light/src/core/numberSet.c
new file mode 100755 (executable)
index 0000000..75fec15
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/config.h>
+#include <src/core/numberSet.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct number_set {
+  Number *arrayOfNumbers;
+  size_t length;
+  size_t limit;
+  unsigned refcount;
+};
+
+static void numberSet_Expand(NumberSet *set);
+
+NumberSet *numberSet_Create() {
+  NumberSet *set = parcMemory_AllocateAndClear(sizeof(NumberSet));
+  parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(NumberSet));
+  set->arrayOfNumbers = parcMemory_AllocateAndClear(sizeof(Number) * 16);
+  parcAssertNotNull((set->arrayOfNumbers),
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Number) * 16);
+  set->length = 0;
+  set->limit = 16;
+  set->refcount = 1;
+  return set;
+}
+
+NumberSet *numberSet_Acquire(const NumberSet *original) {
+  parcAssertNotNull(original, "Parameter original must be non-null");
+  NumberSet *copy = (NumberSet *)original;
+  copy->refcount++;
+  return copy;
+}
+
+void numberSet_Release(NumberSet **setPtr) {
+  parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+  NumberSet *set = *setPtr;
+  parcAssertTrue(
+      set->refcount > 0,
+      "Invalid state: calling destroy on an object with 0 reference count");
+  set->refcount--;
+
+  if (set->refcount == 0) {
+    parcMemory_Deallocate((void **)&(set->arrayOfNumbers));
+    parcMemory_Deallocate((void **)&set);
+    *setPtr = NULL;
+  }
+}
+
+/**
+ * @function numberSet_AddNoChecks
+ * @abstract Add a number we know is not already in the set
+ * @discussion
+ *   Used by other functions that already know the number is unique in the set,
+ *   Does not do the expensive Contains check.
+ */
+static void numberSet_AddNoChecks(NumberSet *set, Number number) {
+  if (set->length == set->limit) {
+    numberSet_Expand(set);
+  }
+
+  set->arrayOfNumbers[set->length] = number;
+  set->length++;
+}
+
+bool numberSet_Add(NumberSet *set, Number number) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  if (numberSet_Contains(set, number)) {
+    return false;
+  }
+
+  numberSet_AddNoChecks(set, number);
+  return true;
+}
+
+size_t numberSet_Length(const NumberSet *set) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  return set->length;
+}
+
+Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  parcAssertTrue(ordinalIndex < set->length,
+                 "Limit beyond end of set, length %zu got %zu", set->length,
+                 ordinalIndex);
+
+  return set->arrayOfNumbers[ordinalIndex];
+}
+
+bool numberSet_Contains(const NumberSet *set, Number number) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  for (size_t i = 0; i < set->length; i++) {
+    if (set->arrayOfNumbers[i] == number) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd) {
+  parcAssertNotNull(destinationSet,
+                    "Parameter destinationSet must be non-null");
+  parcAssertNotNull(setToAdd, "Parameter setToAdd must be non-null");
+
+  for (size_t i = 0; i < setToAdd->length; i++) {
+    numberSet_Add(destinationSet, setToAdd->arrayOfNumbers[i]);
+  }
+}
+
+NumberSet *numberSet_Subtract(const NumberSet *minuend,
+                              const NumberSet *subtrahend) {
+  // because the underlying ADT is not sorted, this is pretty ineffient, could
+  // be O(n^2).
+
+  NumberSet *difference = numberSet_Create();
+
+  for (size_t i = 0; i < minuend->length; i++) {
+    bool unique = true;
+    for (size_t j = 0; j < subtrahend->length && unique; j++) {
+      if (minuend->arrayOfNumbers[i] == subtrahend->arrayOfNumbers[j]) {
+        unique = false;
+      }
+    }
+
+    if (unique) {
+      numberSet_AddNoChecks(difference, minuend->arrayOfNumbers[i]);
+    }
+  }
+  return difference;
+}
+
+bool numberSet_Equals(const NumberSet *a, const NumberSet *b) {
+  if (a == NULL && b == NULL) {
+    return true;
+  }
+
+  if (a == NULL || b == NULL) {
+    return false;
+  }
+
+  if (a->length == b->length) {
+    for (size_t i = 0; i < a->length; i++) {
+      bool found = false;
+      for (size_t j = 0; j < b->length && !found; j++) {
+        if (a->arrayOfNumbers[i] == b->arrayOfNumbers[j]) {
+          found = true;
+        }
+      }
+      if (!found) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  return false;
+}
+
+void numberSet_Remove(NumberSet *set, Number number) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  for (size_t i = 0; i < set->length; i++) {
+    if (set->arrayOfNumbers[i] == number) {
+      set->length--;
+      if (set->length > 0) {
+        // move the last element to the removed element to keep the array
+        // packed.
+        set->arrayOfNumbers[i] = set->arrayOfNumbers[set->length];
+      }
+      return;
+    }
+  }
+}
+
+// =====================================================
+
+static void numberSet_Expand(NumberSet *set) {
+  size_t newlimit = set->limit * 2;
+  size_t newbytes = newlimit * sizeof(Number);
+
+  set->arrayOfNumbers = parcMemory_Reallocate(set->arrayOfNumbers, newbytes);
+  set->limit = newlimit;
+}
diff --git a/hicn-light/src/core/numberSet.h b/hicn-light/src/core/numberSet.h
new file mode 100755 (executable)
index 0000000..91a965d
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief Stores a set of numbers.
+ *
+ * Useful for things like the reverse path of a PIT
+ * or the forward paths of a FIB.  Does not allow duplicates.
+ *
+ */
+
+#ifndef numberSet_h
+#define numberSet_h
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct number_set;
+typedef struct number_set NumberSet;
+
+typedef uint32_t Number;
+
+/**
+ * @function numberList_Create
+ * @abstract A new list of numbers
+ */
+NumberSet *numberSet_Create(void);
+
+/**
+ * Obtains a reference counted copy of the original
+ * The reference count is increased by one.  It must be released with
+ * NumberSet_Release().
+ * @param [in] original An allocated NumberSet
+ * @return non-null The reference counted copy
+ */
+NumberSet *numberSet_Acquire(const NumberSet *original);
+
+/**
+ * Releases one reference count and destroys the memory after last release
+ * The pointer will be NULLed after release regardless if the memory was
+ * destroyed.
+ * @param [in,out] setPtr A pointer to a NumberSet.  Will be NULL'd after
+ * release.
+ */
+void numberSet_Release(NumberSet **setPtr);
+
+/**
+ * @function numberList_Append
+ * @abstract Add a number to the end of the list
+ * @discussion
+ *   No check for duplicates is done
+ * @return true if added, false if a duplicate
+ */
+bool numberSet_Add(NumberSet *set, Number number);
+
+/**
+ * @function numberList_Length
+ * @abstract The count of numbers in the list
+ */
+size_t numberSet_Length(const NumberSet *set);
+
+/**
+ * @function numberSet_GetItem
+ * @abstract Retrieves an item based on the ordinal index
+ * @discussion
+ *   Will assert if the ordinalIndex is out of bounds.
+ */
+Number numberSet_GetItem(const NumberSet *set, size_t ordinalIndex);
+
+/**
+ * @function numberSet_Contains
+ * @abstract Checks for set membership
+ * @return true if the set contains the number, false otherwise
+ */
+bool numberSet_Contains(const NumberSet *set, Number number);
+
+/**
+ * @function numberSet_AddSet
+ * @abstract Adds one set to another set
+ * @discussion
+ *   Adds <code>setToAdd</code> to <code>destinationSet</code>
+ * @return true if the set contains the number, false otherwise
+ */
+void numberSet_AddSet(NumberSet *destinationSet, const NumberSet *setToAdd);
+
+/**
+ * @function numberSet_Subtract
+ * @abstract Computes set difference <code>difference = minuend -
+ * subtrahend</code>, returns a new number set.
+ * @discussion
+ *   <code>minuend</code> and <code>subtrahend</code> are not modified.  A new
+ * difference set is created.
+ *
+ *   Returns the elements in <code>minuend</code> that are not in
+ * <code>subtrahend</code>.
+ *
+ * @param minuend The set from which to subtract
+ * @param subrahend The set begin removed from minuend
+ * @return The set difference.  May be empty, but will not be NULL.
+ */
+NumberSet *numberSet_Subtract(const NumberSet *minuend,
+                              const NumberSet *subtrahend);
+
+/**
+ * Determine if two NumberSet instances are equal.
+ *
+ * Two NumberSet instances are equal if, and only if,
+ *   they are the same size and contain the same elements.  Empty sets are
+ * equal. NULL equals NULL, but does not equal non-NULL.
+ *
+ * The following equivalence relations on non-null `NumberSet` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x, `NumberSet_Equals(x,
+ * x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `numberSet_Equals(x, y)` must return true if and only if
+ *        `numberSet_Equals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `numberSet_Equals(x, y)` returns true and
+ *        `numberSet_Equals(y, z)` returns true,
+ *        then  `numberSet_Equals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `numberSet_Equals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `numberSet_Equals(x, NULL)` must
+ *      return false.
+ *
+ * @param a A pointer to a `NumberSet` instance.
+ * @param b A pointer to a `NumberSet` instance.
+ * @return true if the two `NumberSet` instances are equal.
+ */
+bool numberSet_Equals(const NumberSet *a, const NumberSet *b);
+
+/**
+ * @function numberSet_Remove
+ * @abstract Removes the number from the set
+ */
+void numberSet_Remove(NumberSet *set, Number number);
+#endif  // numberSet_h
diff --git a/hicn-light/src/core/streamBuffer.c b/hicn-light/src/core/streamBuffer.c
new file mode 100755 (executable)
index 0000000..7aebb5e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/core/streamBuffer.h>
+
+void streamBuffer_Destroy(PARCEventQueue **bufferPtr) {
+  parcAssertNotNull(bufferPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*bufferPtr,
+                    "Parameter must dereference to non-null pointer");
+  parcEventQueue_Destroy(bufferPtr);
+  *bufferPtr = NULL;
+}
+
+void streamBuffer_SetWatermark(PARCEventQueue *buffer, bool setRead,
+                               bool setWrite, size_t low, size_t high) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+  short flags = 0;
+  if (setRead) {
+    flags |= PARCEventType_Read;
+  }
+
+  if (setWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  parcEventQueue_SetWatermark(buffer, flags, low, high);
+}
+
+int streamBuffer_Flush(PARCEventQueue *buffer, bool flushRead,
+                       bool flushWrite) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+  short flags = 0;
+  if (flushRead) {
+    flags |= PARCEventType_Read;
+  }
+
+  if (flushWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  return parcEventQueue_Flush(buffer, flags);
+}
+
+int streamBuffer_FlushCheckpoint(PARCEventQueue *buffer, bool flushRead,
+                                 bool flushWrite) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+  short flags = 0;
+  if (flushRead) {
+    flags |= PARCEventType_Read;
+  }
+
+  if (flushWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  return parcEventQueue_Flush(buffer, flags);
+}
+
+int streamBuffer_FlushFinished(PARCEventQueue *buffer, bool flushRead,
+                               bool flushWrite) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+  short flags = 0;
+  if (flushRead) {
+    flags |= PARCEventType_Read;
+  }
+
+  if (flushWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  return parcEventQueue_Flush(buffer, flags);
+}
+
+void streamBuffer_SetCallbacks(PARCEventQueue *buffer,
+                               PARCEventQueue_Callback *readCallback,
+                               PARCEventQueue_Callback *writeCallback,
+                               PARCEventQueue_EventCallback *eventCallback,
+                               void *user_data) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+
+  parcEventQueue_SetCallbacks(buffer, readCallback, writeCallback,
+                              eventCallback, user_data);
+}
+
+void streamBuffer_EnableCallbacks(PARCEventQueue *buffer, bool enableRead,
+                                  bool enableWrite) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+  short flags = 0;
+  if (enableRead) {
+    flags |= PARCEventType_Read;
+  }
+  if (enableWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  parcEventQueue_Enable(buffer, flags);
+}
+
+/**
+ * @function StreamBuffer_DisableCallbacks
+ * @abstract Disables specified callbacks.  Does not affect others.
+ * @discussion
+ *   Disables enabled callbacks.  If a callback is already disabled, has no
+ * effect. A "false" value does not enable it.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+void streamBuffer_DisableCallbacks(PARCEventQueue *buffer, bool disableRead,
+                                   bool disableWrite) {
+  parcAssertNotNull(buffer, "Parameter buffer must be non-null");
+  short flags = 0;
+  if (disableRead) {
+    flags |= PARCEventType_Read;
+  }
+  if (disableWrite) {
+    flags |= PARCEventType_Write;
+  }
+
+  parcEventQueue_Disable(buffer, flags);
+}
diff --git a/hicn-light/src/core/streamBuffer.h b/hicn-light/src/core/streamBuffer.h
new file mode 100755 (executable)
index 0000000..27e7931
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Wrapper around event scheduler
+ */
+
+#ifndef streamBuffer_h
+#define streamBuffer_h
+
+#include <parc/algol/parc_EventQueue.h>
+#include <stdbool.h>
+
+void streamBuffer_Destroy(PARCEventQueue **bufferPtr);
+
+/**
+ * @function streamBuffer_SetWatermark
+ * @abstract Sets the read and/or write watermarks
+ * @discussion
+ *   For a read watermark, when there is at least <code>low</code> bytes
+ * available to read, the read callback will be fired.  If the bytes in the
+ * buffer exceed <code>high</code>, the stream buffer will stop reading from the
+ * network.
+ *
+ *   For a write watermark, when the bytes in the buffer fall below
+ * <code>low</code>, the write callback is fired.   The <code>high</code>
+ * watermark limits stream filters and shapers from exceeding that threashold on
+ * what they write to the buffer.
+ *
+ */
+void streamBuffer_SetWatermark(PARCEventQueue *buffer, bool setRead,
+                               bool setWrite, size_t low, size_t high);
+
+/**
+ * @function streamBuffer_Flush
+ * @abstract The buffer will read/write more data if available
+ *
+ * @return -1 error, 0 no more data, 1 more data
+ */
+int streamBuffer_Flush(PARCEventQueue *buffer, bool flushRead, bool flushWrite);
+
+/**
+ * @function streamBuffer_FlushCheckpoint
+ * @abstract Flushes the stream, checkpointing all data in the buffer
+ */
+int streamBuffer_FlushCheckpoint(PARCEventQueue *buffer, bool flushRead,
+                                 bool flushWrite);
+
+/**
+ * @function streamBuffer_FlushFinished
+ * @abstract Flush the stream and indicate the end of new data
+ */
+int streamBuffer_FlushFinished(PARCEventQueue *buffer, bool flushRead,
+                               bool flushWrite);
+
+/**
+ * @typedef StreamBufferReadWriteCallback
+ * @abstract Callback when data is available or write space available
+ * @constant user_data opaque data passed to
+ * <code>StreamBuffer_SetCallbacks()</code>
+ */
+typedef void(StreamBufferReadWriteCallback)(PARCEventQueue *buffer,
+                                            void *user_data);
+
+/**
+ * @typedef StreamBufferEventCallback
+ * @abstract Callback on error or other event on the stream buffer
+ * @constant what logical or of STREAM events.  STREAM_READING and
+ * STREAM_WRITING indicate if the error was on the read or write direction.  The
+ * conditions may be STREAM_ERROR, STREAM_EOF, STREAM_TIMEOUT, or
+ * STREAM_CONNECTED.
+ * @constant user_data opaque data passed to
+ * <code>StreamBuffer_SetCallbacks()</code>
+ */
+typedef void(StreamBufferEventCallback)(PARCEventQueue *buffer, short what,
+                                        void *user_data);
+
+/**
+ * Changes the callbacks for a buffer event.
+ *
+ * @param bufev the buffer event object for which to change callbacks
+ * @param readcb callback to invoke when there is data to be read, or NULL if
+ * no callback is desired
+ * @param writecb callback to invoke when the file descriptor is ready for
+ * writing, or NULL if no callback is desired
+ * @param eventcb callback to invoke when there is an event on the file
+ * descriptor
+ * @param cbarg an argument that will be supplied to each of the callbacks
+ * (readcb, writecb, and errorcb)
+ * @see parcEventQueue_Create()
+ */
+void streamBuffer_SetCallbacks(PARCEventQueue *buffer,
+                               PARCEventQueue_Callback *readCallback,
+                               PARCEventQueue_Callback *writeCallback,
+                               PARCEventQueue_EventCallback *eventCallback,
+                               void *user_data);
+
+/**
+ * @function StreamBuffer_EnableCallbacks
+ * @abstract Enables specified callbacks.  Does not affect others.
+ * @discussion
+ *   Enables disabled callbacks.  If a callback is already enabled, has no
+ * effect. A "false" value does not disable it.
+ */
+void streamBuffer_EnableCallbacks(PARCEventQueue *buffer, bool enableRead,
+                                  bool enableWrite);
+
+/**
+ * @function StreamBuffer_DisableCallbacks
+ * @abstract Disables specified callbacks.  Does not affect others.
+ * @discussion
+ *   Disables enabled callbacks.  If a callback is already disabled, has no
+ * effect. A "false" value does not enable it.
+ */
+void streamBuffer_DisableCallbacks(PARCEventQueue *buffer, bool disableRead,
+                                   bool disableWrite);
+#endif  // streamBuffer_h
diff --git a/hicn-light/src/core/system.h b/hicn-light/src/core/system.h
new file mode 100755 (executable)
index 0000000..3c5c8cb
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @header system.h
+ * @abstract System-level properties
+ * @discussion
+ *     <#Discussion#>
+ *
+ */
+
+#ifndef system_h
+#define system_h
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+/**
+ * @function system_Interfaces
+ * @abstract The system network interfaces
+ */
+InterfaceSet *system_Interfaces(Forwarder *forwarder);
+
+/**
+ * Returns the MTU of the named interface
+ *
+ * @param [in] an allocated hicn-light forwarder
+ * @param [in] interfaceName The system interface name, e.g. "eth0"
+ *
+ * @return 0 Interface does not exist
+ * @return positive the MTU the kernel reports
+ *
+ */
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName);
+
+/**
+ * Returns the LINK address of the specified interface
+ *
+ * @param [in] an allocated hicn-light forwarder
+ * @param [in] interfaceName The system interface name, e.g. "eth0"
+ *
+ * @retval non-null The MAC address of the interface
+ * @retval null The interface does not exist
+ *
+ */
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+                                    const char *interfaceName);
+#endif
diff --git a/hicn-light/src/core/ticks.h b/hicn-light/src/core/ticks.h
new file mode 100755 (executable)
index 0000000..8750abd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief The router periodically measures time in units of Ticks
+ *
+ * See forwarder.c HZ which specifies the tick rate.  forwarder.h has functions
+ * to convert between ticks and milliseconds.
+ *
+ */
+#ifndef ticks_h
+#define ticks_h
+
+#define __STDC_FORMAT_MACROS
+#include <stdint.h>
+
+typedef uint64_t Ticks;
+
+#endif  // ticks_h
diff --git a/hicn-light/src/core/wldr.c b/hicn-light/src/core/wldr.c
new file mode 100755 (executable)
index 0000000..b94ae76
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/assert/parc_Assert.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/wldr.h>
+#include <stdint.h>
+#include <stdio.h>
+
+struct wldr_buffer {
+  Message *message;
+  uint8_t rtx_counter;
+};
+
+typedef struct wldr_buffer WldrBuffer;
+
+struct wldr_state {
+  uint16_t expected_label;
+  uint16_t next_label;
+  WldrBuffer *buffer[BUFFER_SIZE];
+};
+
+Wldr *wldr_Init() {
+  Wldr *wldr = parcMemory_AllocateAndClear(sizeof(Wldr));
+  parcAssertNotNull(wldr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Wldr));
+  wldr->expected_label = 1;
+  wldr->next_label = 1;
+  for (int i = 0; i < BUFFER_SIZE; i++) {
+    WldrBuffer *entry = parcMemory_AllocateAndClear(sizeof(WldrBuffer));
+    parcAssertNotNull(
+        entry,
+        "WldrBuffer init: parcMemory_AllocateAndClear(%zu) returned NULL",
+        sizeof(WldrBuffer));
+    entry->message = NULL;
+    entry->rtx_counter = 0;
+    wldr->buffer[i] = entry;
+  }
+  return wldr;
+}
+
+void wldr_ResetState(Wldr *wldr) {
+  wldr->expected_label = 1;
+  wldr->next_label = 1;
+  for (int i = 0; i < BUFFER_SIZE; i++) {
+    wldr->buffer[i]->message = NULL;
+    wldr->buffer[i]->rtx_counter = 0;
+  }
+}
+
+void wldr_Destroy(Wldr **wldrPtr) {
+  Wldr *wldr = *wldrPtr;
+  for (unsigned i = 0; i < BUFFER_SIZE; i++) {
+    if (wldr->buffer[i]->message != NULL) {
+      message_Release(&(wldr->buffer[i]->message));
+      parcMemory_Deallocate((void **)&(wldr->buffer[i]));
+    }
+  }
+  parcMemory_Deallocate((void **)&wldr);
+  *wldrPtr = NULL;
+}
+
+static void _wldr_RetransmitPacket(Wldr *wldr, const Connection *conn,
+                                   uint16_t label) {
+  if (wldr->buffer[label % BUFFER_SIZE]->message == NULL) {
+    // the required message for retransmission is not in the buffer
+    return;
+  }
+
+  if (wldr->buffer[label % BUFFER_SIZE]->rtx_counter < MAX_RTX) {
+    Message *msg = wldr->buffer[label % BUFFER_SIZE]->message;
+    message_SetWldrLabel(msg, wldr->next_label);
+
+    if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
+      message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+    }
+
+    wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = msg;
+    wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter =
+        wldr->buffer[label % BUFFER_SIZE]->rtx_counter + 1;
+    message_Acquire(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message);
+    wldr->next_label++;
+    connection_ReSend(conn, msg, false);
+  }
+}
+
+static void _wldr_SendWldrNotificaiton(Wldr *wldr, const Connection *conn,
+                                       Message *message, uint16_t expected_lbl,
+                                       uint16_t received_lbl) {
+  // here we need to create a new packet that is used to send the wldr
+  // notification to the prevoius hop. the destionation address of the
+  // notification is the source address of the message for which we want to
+  // create a notification. in fact, if message is an interest the prevoius hop
+  // is identified by the src. if message is a data, we need to send the
+  // notification message with the content name has a source address in this way
+  // the message will be trapped by the pounting rules in the next hop We define
+  // the notification as an interest message so that the NAT in the send function
+  // will set the src address of the local connection. Notice that in this way
+  // the notification packet will be dispaced to the right connection at the next
+  // hop.
+
+  Message *notification =
+      message_CreateWldrNotification(message, expected_lbl, received_lbl);
+  parcAssertNotNull(notification, "Got null from CreateWldrNotification");
+  connection_ReSend(conn, notification, true);
+}
+
+void wldr_SetLabel(Wldr *wldr, Message *message) {
+  // in this function we send the packet for the first time
+  // 1) we set the wldr label
+  message_SetWldrLabel(message, wldr->next_label);
+
+  // 2) we store the pointer to packet in the buffer
+  if (wldr->buffer[wldr->next_label % BUFFER_SIZE]->message != NULL) {
+    // release an old message if necessary
+    message_Release(&(wldr->buffer[wldr->next_label % BUFFER_SIZE]->message));
+  }
+
+  // we need to acquire the message to avoid that it gets destroyed
+  message_Acquire(message);
+
+  wldr->buffer[wldr->next_label % BUFFER_SIZE]->message = message;
+  wldr->buffer[wldr->next_label % BUFFER_SIZE]->rtx_counter = 0;
+  wldr->next_label++;
+  if (wldr->next_label ==
+      0)  // we alwasy skip label 0 beacause it means that wldr is not active
+    wldr->next_label++;
+}
+
+void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message) {
+  if (message_HasWldr(message)) {
+    // this is a normal wldr packet
+    uint16_t pkt_lbl = (uint16_t)message_GetWldrLabel(message);
+    if (pkt_lbl != wldr->expected_label) {
+      // if the received packet label is 1 and the expected packet label >
+      // pkt_lbl usually we are in the case where a remote note disconnected for
+      // a while and reconnected on this same connection, so the two nodes are
+      // out of synch for this reason we do not send any notification, we just
+      // synch the labels
+
+      if ((pkt_lbl != 1) || (wldr->expected_label < pkt_lbl)) {
+        _wldr_SendWldrNotificaiton(wldr, conn, message, wldr->expected_label,
+                                   pkt_lbl);
+      }
+
+      // here we always synch
+      wldr->expected_label = (uint16_t)(pkt_lbl + 1);
+    } else {
+      wldr->expected_label++;
+      if (wldr->expected_label == 0)
+        wldr->expected_label++;  // for the next_label we want to skip 0
+    }
+  }
+}
+
+void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
+                                 Message *message) {
+  uint16_t expected_lbl = (uint16_t)message_GetWldrExpectedLabel(message);
+  uint16_t received_lbl = (uint16_t)message_GetWldrLastReceived(message);
+  if ((wldr->next_label - expected_lbl) > BUFFER_SIZE) {
+    // the packets are not in the buffer anymore
+    return;
+  }
+  while (expected_lbl < received_lbl) {
+    _wldr_RetransmitPacket(wldr, conn, expected_lbl);
+    expected_lbl++;
+  }
+}
diff --git a/hicn-light/src/core/wldr.h b/hicn-light/src/core/wldr.h
new file mode 100755 (executable)
index 0000000..1666b4d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017-2019 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 wldr_h
+#define wldr_h
+
+#include <src/config.h>
+#include <src/core/connection.h>
+#include <src/core/message.h>
+
+#define BUFFER_SIZE 8192
+#define MAX_RTX 3
+#define WLDR_LBL 13
+#define WLDR_NOTIFICATION 14
+#define WLDR_UNKNOWN 15
+
+//  NORMAL PACKET or RETRASMISSION
+//      WLDR_LBL:  label = window size in the TCP header
+//  NOTIFICATION
+//    WLDR_NOTIFICATION:  expected_label = window size in the TCP header,
+//    last_received_label = urgent pointer in the TCP header
+//                        ATTENTION!!! in order to detect a notificaiton the
+//                        source and destination ports must be set to 0
+
+struct wldr_state;
+typedef struct wldr_state Wldr;
+
+Wldr *wldr_Init();
+
+void wldr_Destroy(Wldr **wldrPtr);
+
+void wldr_ResetState(Wldr *wldr);
+
+void wldr_SetLabel(Wldr *wldr, Message *message);
+
+void wldr_DetectLosses(Wldr *wldr, const Connection *conn, Message *message);
+
+void wldr_HandleWldrNotification(Wldr *wldr, const Connection *conn,
+                                 Message *message);
+#endif  // wldr_h
diff --git a/hicn-light/src/io/CMakeLists.txt b/hicn-light/src/io/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f65f0b5
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/listener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicnListener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicnTunnel.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicnConnection.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/addressPair.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/ioOperations.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/listenerSet.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/streamConnection.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/tcpListener.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/tcpTunnel.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpConnection.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpListener.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/udpTunnel.c
+)
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+  list(APPEND SOURCE_FILES
+    io/hicnTunnel.c
+    io/hicnConnection.c
+    io/hicnListener.c
+  )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/io/addressPair.c b/hicn-light/src/io/addressPair.c
new file mode 100755 (executable)
index 0000000..5d2017a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/io/addressPair.h>
+
+struct address_pair {
+  Address *local;
+  Address *remote;
+};
+
+static void _addressPair_Destroy(AddressPair **addressPairPtr) {
+  AddressPair *pair = *addressPairPtr;
+
+  addressDestroy(&pair->local);
+  addressDestroy(&pair->remote);
+}
+
+parcObject_ExtendPARCObject(AddressPair, _addressPair_Destroy, NULL,
+                            addressPair_ToString, addressPair_Equals, NULL,
+                            addressPair_HashCode, NULL);
+
+parcObject_ImplementAcquire(addressPair, AddressPair);
+
+parcObject_ImplementRelease(addressPair, AddressPair);
+
+AddressPair *addressPair_Create(const Address *local, const Address *remote) {
+  parcAssertNotNull(local, "Parameter local must be non-null");
+  parcAssertNotNull(remote, "Parameter remote must be non-null");
+
+  AddressPair *pair = parcObject_CreateInstance(AddressPair);
+  parcAssertNotNull(pair, "Got null from parcObject_Create()");
+
+  pair->local = addressCopy(local);
+  pair->remote = addressCopy(remote);
+
+  return pair;
+}
+
+bool addressPair_Equals(const AddressPair *a, const AddressPair *b) {
+  if (a == b) {
+    return true;
+  }
+  if (a == NULL || b == NULL) {
+    return false;
+  }
+
+  if (addressEquals(a->local, b->local)) {
+    if (addressEquals(a->remote, b->remote)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local,
+                                 const Address *remote) {
+  if (a == NULL || local == NULL || remote == NULL) {
+    return false;
+  }
+
+  if (addressEquals(a->local, local)) {
+    if (addressEquals(a->remote, remote)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+char *addressPair_ToString(const AddressPair *pair) {
+  parcAssertNotNull(pair, "Parameter pair must be non-null");
+
+  char *local = addressToString(pair->local);
+  char *remote = addressToString(pair->remote);
+
+  char *output;
+  int failure = asprintf(&output, "{ .local=%s, .remote=%s }", local, remote);
+  parcAssertTrue(failure > -1, "Error on asprintf");
+
+  parcMemory_Deallocate((void **)&local);
+  parcMemory_Deallocate((void **)&remote);
+
+  return output;
+}
+
+const Address *addressPair_GetLocal(const AddressPair *pair) {
+  parcAssertNotNull(pair, "Parameter pair must be non-null");
+  return pair->local;
+}
+
+const Address *addressPair_GetRemote(const AddressPair *pair) {
+  parcAssertNotNull(pair, "Parameter pair must be non-null");
+  return pair->remote;
+}
+
+/**
+ * @function addressPair_HashCode
+ * @abstract Hash useful for tables.  Consistent with Equals.
+ * @discussion
+ *   Returns a non-cryptographic hash that is consistent with equals.  That is,
+ *   if a == b, then hash(a) == hash(b).
+ *
+ */
+PARCHashCode addressPair_HashCode(const AddressPair *pair) {
+  PARCHashCode hashpair[2];
+  hashpair[0] = addressHashCode(pair->local);
+  hashpair[1] = addressHashCode(pair->remote);
+  return parcHashCode_Hash((const uint8_t *)hashpair, sizeof(hashpair));
+}
diff --git a/hicn-light/src/io/addressPair.h b/hicn-light/src/io/addressPair.h
new file mode 100755 (executable)
index 0000000..5152267
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Used to identify a connection between a specific local address and
+ * a specific remote address.
+ */
+
+#ifndef address_Pair_h
+#define address_Pair_h
+
+#include <src/utils/address.h>
+
+struct address_pair;
+typedef struct address_pair AddressPair;
+
+/**
+ * @function addressPair_Create
+ * @abstract Creates and address pair.  There is no restriction on the address
+ * types.
+ * @discussion
+ *   Creates an ordered pair of addresses, where the first is considered the
+ * "local" address and the second is the "remote" address.  Those designations
+ * are purely a convention used to name them, and does not imply any specifici
+ * types of operations.
+ *
+ *   The two addresses may be of any address types (e.g. IPv4, IPv6, Local,
+ * Ethernet). However, some functions that use an AddressPair may require that
+ * the local and remote addresses be the same type.
+ *
+ */
+AddressPair *addressPair_Create(const Address *local, const Address *remote);
+
+/**
+ * Returns a reference counted copy of the address pair
+ *
+ * Increments the reference count and returns the same address pair
+ *
+ * @param [in] addressPair An allocated address pair
+ *
+ * @retval non-null A reference counted copy
+ * @retval null An error
+ */
+AddressPair *addressPair_Acquire(const AddressPair *addressPair);
+
+/**
+ * Releases a reference count to the object
+ *
+ * Decrements the reference count and destroys the object when it reaches 0.
+ */
+void addressPair_Release(AddressPair **pairPtr);
+
+/**
+ * Determine if two AddressPair instances are equal.
+ *
+ * Two AddressPair instances are equal if, and only if, the local and remote
+ * addresses are identical. Equality is determined by addressEquals(a->local,
+ * b->local) and Adress_Equals(a->remote, b->remote).
+ *
+ * The following equivalence relations on non-null `AddressPair` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x,
+ * `AddressPair_Equals(x, x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `addressPair_Equals(x, y)` must return true if and only if
+ *        `addressPair_Equals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `addressPair_Equals(x, y)` returns true and
+ *        `addressPair_Equals(y, z)` returns true,
+ *        then  `addressPair_Equals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `addressPair_Equals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `addressPair_Equals(x, NULL)` must
+ *      return false.
+ *
+ * @param a A pointer to a `AddressPair` instance.
+ * @param b A pointer to a `AddressPair` instance.
+ * @return true if the two `AddressPair` instances are equal.
+ */
+bool addressPair_Equals(const AddressPair *a, const AddressPair *b);
+
+/**
+ * @function addressPair_EqualsAddresses
+ * @abstract As AddressEquals, but "b" is broken out
+ * @discussion
+ *   Equality is determined by addressEquals(a->local, local) and
+ *   Adress_Equals(a->remote, remote).
+ */
+bool addressPair_EqualsAddresses(const AddressPair *a, const Address *local,
+                                 const Address *remote);
+
+const Address *addressPair_GetLocal(const AddressPair *pair);
+
+const Address *addressPair_GetRemote(const AddressPair *pair);
+
+/**
+ * @function addressPair_HashCode
+ * @abstract Hash useful for tables.  Consistent with Equals.
+ * @discussion
+ *   Returns a non-cryptographic hash that is consistent with equals.  That is,
+ *   if a == b, then hash(a) == hash(b).
+ */
+PARCHashCode addressPair_HashCode(const AddressPair *pair);
+
+/**
+ * @function addressPair_ToString
+ * @abstract Human readable string representation.  Caller must use free(3).
+ */
+char *addressPair_ToString(const AddressPair *pair);
+#endif  // address_Pair_h
diff --git a/hicn-light/src/io/hicnConnection.c b/hicn-light/src/io/hicnConnection.c
new file mode 100755 (executable)
index 0000000..85cf509
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Embodies the reader/writer for a HIcn connection
+ *
+ * NB The Send() function may overflow the output buffer
+ *
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <src/core/message.h>
+#include <src/io/hicnConnection.h>
+
+#include <src/core/messageHandler.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+
+typedef struct hicn_state {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  // the hicn listener socket we receive packets on
+  int hicnListenerSocket;
+
+  AddressPair *addressPair;
+
+  // We need to access this all the time, so grab it out
+  // of the addressPair;
+  struct sockaddr *peerAddress;
+  socklen_t peerAddressLength;
+
+  struct sockaddr *localAddress;
+  socklen_t localAddressLength;
+
+  // this address contains one of the content names reachable
+  // throught the connection peer. We need this address beacuse it is
+  // the only way we have to conntact the next hop, since the main tun
+  // does not have address. Notice that a connection that sends probes
+  // is a connection that sends interest. In a "data" connection this
+  // value will remain NULL. We refresh the content address every time
+  // we send a probe, in this way we don't need to waste to much time in
+  // copy the address, but we can also react to the routing changes
+  struct sockaddr *probeDestAddress;
+  socklen_t probeDestAddressLength;
+  bool refreshProbeDestAddress;
+
+  bool isLocal;
+  bool isUp;
+  unsigned id;
+
+  unsigned delay;
+} _HicnState;
+
+// Prototypes
+static bool _send(IoOperations *ops, const Address *nexthop, Message *message);
+static const Address *_getRemoteAddress(const IoOperations *ops);
+static const AddressPair *_getAddressPair(const IoOperations *ops);
+static unsigned _getConnectionId(const IoOperations *ops);
+static bool _isUp(const IoOperations *ops);
+static bool _isLocal(const IoOperations *ops);
+static void _destroy(IoOperations **opsPtr);
+static list_connections_type _getConnectionType(const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message);
+
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_ioOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+  return _ioOperationsGuid;
+}
+
+static IoOperations _template = {.closure = NULL,
+                                 .send = &_send,
+                                 .getRemoteAddress = &_getRemoteAddress,
+                                 .getAddressPair = &_getAddressPair,
+                                 .getConnectionId = &_getConnectionId,
+                                 .isUp = &_isUp,
+                                 .isLocal = &_isLocal,
+                                 .destroy = &_destroy,
+                                 .class = &_streamConnection_Class,
+                                 .getConnectionType = &_getConnectionType,
+                                 .sendProbe = &_sendProbe};
+
+// =================================================================
+
+static void _setConnectionState(_HicnState *HIcn, bool isUp);
+static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair);
+static void _refreshProbeDestAddress(_HicnState *hicnConnState,
+                                     const uint8_t *message);
+
+IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+                                    const AddressPair *pair, bool isLocal) {
+  IoOperations *io_ops = NULL;
+
+  _HicnState *hicnConnState = parcMemory_AllocateAndClear(sizeof(_HicnState));
+  parcAssertNotNull(hicnConnState,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_HicnState));
+
+  hicnConnState->forwarder = forwarder;
+  hicnConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  bool saved = _saveSockaddr(hicnConnState, pair);
+  if (saved) {
+    hicnConnState->hicnListenerSocket = fd;
+    hicnConnState->id = forwarder_GetNextConnectionId(forwarder);
+    hicnConnState->addressPair = addressPair_Acquire(pair);
+    hicnConnState->isLocal = isLocal;
+
+    // allocate a connection
+    io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+    parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(IoOperations));
+    memcpy(io_ops, &_template, sizeof(IoOperations));
+    io_ops->closure = hicnConnState;
+
+    _setConnectionState(hicnConnState, true);
+
+    if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+                          PARCLogLevel_Info)) {
+      char *str = addressPair_ToString(hicnConnState->addressPair);
+      logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+                 __func__,
+                 "HIcnConnection %p created for address %s (isLocal %d)",
+                 (void *)hicnConnState, str, hicnConnState->isLocal);
+      free(str);
+    }
+
+    messenger_Send(
+        forwarder_GetMessenger(forwarder),
+        missive_Create(MissiveType_ConnectionCreate, hicnConnState->id));
+    messenger_Send(forwarder_GetMessenger(forwarder),
+                   missive_Create(MissiveType_ConnectionUp, hicnConnState->id));
+  } else {
+    // _saveSockaddr will already log an error, no need for extra log message
+    // here
+    logger_Release(&hicnConnState->logger);
+    parcMemory_Deallocate((void **)&hicnConnState);
+  }
+
+  return io_ops;
+}
+
+// =================================================================
+// I/O Operations implementation
+
+static void _destroy(IoOperations **opsPtr) {
+  parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+  parcAssertNotNull(*opsPtr,
+                    "Parameter opsPtr must dereference to non-null pointer");
+
+  IoOperations *ops = *opsPtr;
+  parcAssertNotNull(ioOperations_GetClosure(ops),
+                    "ops->context must not be null");
+
+  _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+  addressPair_Release(&hicnConnState->addressPair);
+  parcMemory_Deallocate((void **)&(hicnConnState->peerAddress));
+  parcMemory_Deallocate((void **)&(hicnConnState->localAddress));
+  if (hicnConnState->probeDestAddress != NULL)
+    parcMemory_Deallocate((void **)&(hicnConnState->probeDestAddress));
+
+  messenger_Send(
+      forwarder_GetMessenger(hicnConnState->forwarder),
+      missive_Create(MissiveType_ConnectionDestroyed, hicnConnState->id));
+
+  if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+                        PARCLogLevel_Info)) {
+    logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+               __func__, "HIcnConnection %p destroyed", (void *)hicnConnState);
+  }
+
+  // XXX
+  // do not close hicListenerSocket, the listener will close
+  // that when its done
+  // should I say something to libhicn?
+
+  logger_Release(&hicnConnState->logger);
+  parcMemory_Deallocate((void **)&hicnConnState);
+  parcMemory_Deallocate((void **)&ops);
+
+  *opsPtr = NULL;
+}
+
+static bool _isUp(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _HicnState *hicnConnState =
+      (const _HicnState *)ioOperations_GetClosure(ops);
+  return hicnConnState->isUp;
+}
+
+static bool _isLocal(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _HicnState *hicnConnState =
+      (const _HicnState *)ioOperations_GetClosure(ops);
+  return hicnConnState->isLocal;
+}
+
+static const Address *_getRemoteAddress(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _HicnState *hicnConnState =
+      (const _HicnState *)ioOperations_GetClosure(ops);
+  return addressPair_GetRemote(hicnConnState->addressPair);
+}
+
+static const AddressPair *_getAddressPair(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _HicnState *hicnConnState =
+      (const _HicnState *)ioOperations_GetClosure(ops);
+  return hicnConnState->addressPair;
+}
+
+static unsigned _getConnectionId(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _HicnState *hicnConnState =
+      (const _HicnState *)ioOperations_GetClosure(ops);
+  return hicnConnState->id;
+}
+
+/**
+ * @function hicnConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ *   sends a message to the peer.
+ *
+ * @param dummy is ignored. .
+ * @return <#return#>
+ */
+static bool _send(IoOperations *ops, const Address *dummy, Message *message) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+
+  // NAT for HICN
+  // XXX
+  if (message_GetType(message) == MessagePacketType_ContentObject) {
+    // this is a data packet. We need to put the remote address in the
+    // destination field
+
+    if (messageHandler_GetIPPacketType(message_FixedHeader(message)) ==
+        IPv6_TYPE) {
+      messageHandler_SetDestination_IPv6(
+          (uint8_t *)message_FixedHeader(message),
+          &((struct sockaddr_in6 *)hicnConnState->peerAddress)->sin6_addr);
+    } else {
+      messageHandler_SetDestination_IPv4(
+          (uint8_t *)message_FixedHeader(message),
+          &(((struct sockaddr_in *)hicnConnState->peerAddress)
+                ->sin_addr.s_addr));
+    }
+  } else if (message_GetType(message) == MessagePacketType_Interest) {
+    // this si an interest packet. We need to put the local address in the
+    // source field
+    if (messageHandler_GetIPPacketType(message_FixedHeader(message)) ==
+        IPv6_TYPE) {
+      messageHandler_SetSource_IPv6(
+          (uint8_t *)message_FixedHeader(message),
+          &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr);
+    } else {
+      messageHandler_SetSource_IPv4(
+          (uint8_t *)message_FixedHeader(message),
+          &(((struct sockaddr_in *)hicnConnState->localAddress)
+                ->sin_addr.s_addr));
+    }
+
+    // only in this case we may need to set the probeDestAddress
+    if (hicnConnState->refreshProbeDestAddress) {
+      _refreshProbeDestAddress(hicnConnState, message_FixedHeader(message));
+    }
+
+  } else if (message_GetType(message) == MessagePacketType_WldrNotification) {
+    // here we don't need to do anything for now
+  } else {
+    // unkown packet
+    if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug,
+                 __func__, "connid %u can't parse the message",
+                 hicnConnState->id);
+    }
+    return false;
+  }
+
+  ssize_t writeLength =
+      write(hicnConnState->hicnListenerSocket, message_FixedHeader(message),
+            message_Length(message));
+
+  if (writeLength < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      return false;
+    } else {
+      // this print is for debugging
+      printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength,
+             message_Length(message), errno, strerror(errno));
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static list_connections_type _getConnectionType(const IoOperations *ops) {
+  return CONN_HICN;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  _HicnState *hicnConnState = (_HicnState *)ioOperations_GetClosure(ops);
+
+  if ((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) ||
+      (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+    return false;
+
+  if (hicnConnState->probeDestAddress == NULL &&
+      probeType == PACKET_TYPE_PROBE_REPLY) {
+    uint8_t *pkt = parcMemory_AllocateAndClear(
+        messageHandler_GetICMPPacketSize(IPv6_TYPE));
+    messageHandler_SetProbePacket(
+        pkt, probeType,
+        (struct in6_addr *)messageHandler_GetDestination(message),
+        (struct in6_addr *)messageHandler_GetSource(message));
+
+    ssize_t writeLength = write(hicnConnState->hicnListenerSocket, pkt,
+                                messageHandler_GetICMPPacketSize(IPv6_TYPE));
+
+    parcMemory_Deallocate((void **)&pkt);
+
+    if (writeLength < 0) {
+      return 0;
+    }
+
+  } else if (hicnConnState->probeDestAddress != NULL &&
+             probeType == PACKET_TYPE_PROBE_REQUEST) {
+    hicnConnState->refreshProbeDestAddress = true;
+
+    uint8_t *pkt = parcMemory_AllocateAndClear(
+        messageHandler_GetICMPPacketSize(IPv6_TYPE));
+    messageHandler_SetProbePacket(
+        pkt, probeType,
+        &((struct sockaddr_in6 *)hicnConnState->localAddress)->sin6_addr,
+        &((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_addr);
+
+    ssize_t writeLength = write(hicnConnState->hicnListenerSocket, pkt,
+                                messageHandler_GetICMPPacketSize(IPv6_TYPE));
+
+    parcMemory_Deallocate((void **)&pkt);
+
+    if (writeLength < 0) {
+      return 0;
+    }
+
+  } else {
+    if (hicnConnState->probeDestAddress == NULL &&
+        probeType == PACKET_TYPE_PROBE_REQUEST) {
+      // this happen for the first probe
+      hicnConnState->refreshProbeDestAddress = true;
+    }
+    // do nothing
+    return 0;
+  }
+
+  return forwarder_GetTicks(hicnConnState->forwarder);
+}
+
+// =================================================================
+// Internal API
+
+static bool _saveSockaddr(_HicnState *hicnConnState, const AddressPair *pair) {
+  bool success = false;
+  const Address *remoteAddress = addressPair_GetRemote(pair);
+  const Address *localAddress = addressPair_GetLocal(pair);
+  switch (addressGetType(remoteAddress)) {  // local must be of the same type
+
+    case ADDR_INET: {
+      size_t bytes = sizeof(struct sockaddr_in);
+      hicnConnState->peerAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(hicnConnState->peerAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet(remoteAddress,
+                     (struct sockaddr_in *)hicnConnState->peerAddress);
+      hicnConnState->peerAddressLength = (socklen_t)bytes;
+
+      hicnConnState->localAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(hicnConnState->localAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet(localAddress,
+                     (struct sockaddr_in *)hicnConnState->localAddress);
+      hicnConnState->localAddressLength = (socklen_t)bytes;
+
+      hicnConnState->probeDestAddress = NULL;
+      hicnConnState->probeDestAddressLength = (socklen_t)bytes;
+      hicnConnState->refreshProbeDestAddress = false;
+
+      success = true;
+      break;
+    }
+
+    case ADDR_INET6: {
+      size_t bytes = sizeof(struct sockaddr_in6);
+      hicnConnState->peerAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(hicnConnState->peerAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet6(remoteAddress,
+                      (struct sockaddr_in6 *)hicnConnState->peerAddress);
+      hicnConnState->peerAddressLength = (socklen_t)bytes;
+
+      hicnConnState->localAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(hicnConnState->localAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet6(localAddress,
+                      (struct sockaddr_in6 *)hicnConnState->localAddress);
+      hicnConnState->localAddressLength = (socklen_t)bytes;
+
+      hicnConnState->probeDestAddress = NULL;
+      hicnConnState->probeDestAddressLength = (socklen_t)bytes;
+      hicnConnState->refreshProbeDestAddress = false;
+
+      success = true;
+      break;
+    }
+
+    default:
+      if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO,
+                            PARCLogLevel_Error)) {
+        char *str = addressToString(remoteAddress);
+        logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Error,
+                   __func__, "Remote address is not INET or INET6: %s", str);
+        parcMemory_Deallocate((void **)&str);
+      }
+      break;
+  }
+  return success;
+}
+
+static void _refreshProbeDestAddress(_HicnState *hicnConnState,
+                                     const uint8_t *message) {
+  if ((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) ||
+      (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+    return;
+
+  if (hicnConnState->probeDestAddress == NULL) {
+    hicnConnState->probeDestAddress =
+        parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+    parcAssertNotNull(hicnConnState->probeDestAddress,
+                      "parcMemory_Allocate(%zu) returned NULL",
+                      sizeof(struct sockaddr_in6));
+  }
+
+  ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_family =
+      AF_INET6;
+  ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_port =
+      htons(1234);
+  ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_scope_id = 0;
+  ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_flowinfo = 0;
+  ((struct sockaddr_in6 *)hicnConnState->probeDestAddress)->sin6_addr =
+      *((struct in6_addr *)messageHandler_GetDestination(message));
+  hicnConnState->refreshProbeDestAddress = false;
+}
+
+static void _setConnectionState(_HicnState *hicnConnState, bool isUp) {
+  parcAssertNotNull(hicnConnState, "Parameter HICN must be non-null");
+
+  Messenger *messenger = forwarder_GetMessenger(hicnConnState->forwarder);
+
+  bool oldStateIsUp = hicnConnState->isUp;
+  hicnConnState->isUp = isUp;
+
+  if (oldStateIsUp && !isUp) {
+    // bring connection DOWN
+    Missive *missive =
+        missive_Create(MissiveType_ConnectionDown, hicnConnState->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+
+  if (!oldStateIsUp && isUp) {
+    // bring connection UP
+    Missive *missive =
+        missive_Create(MissiveType_ConnectionUp, hicnConnState->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+}
diff --git a/hicn-light/src/io/hicnConnection.h b/hicn-light/src/io/hicnConnection.h
new file mode 100755 (executable)
index 0000000..757e534
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hicnConnection.h
+ * @brief Represents a HIcn connection for the connection table
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef hicnConnection_h
+#define hicnConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * Creates a HIcn connection that can send to the remote address
+ *
+ * The address pair must both be same type (i.e. INET or INET6).
+ *
+ * @param [in] an allocated hicn-light Forwarder (saves reference)
+ * @param [in] fd The socket to use
+ * @param [in] pair An allocated address pair for the connection (saves
+ * reference)
+ * @param [in] isLocal determines if the remote address is on the current system
+ *
+ * @retval non-null An allocated Io operations
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *hicnConnection_Create(Forwarder *forwarder, int fd,
+                                    const AddressPair *pair, bool isLocal);
+#endif  // hicnConnection_h
diff --git a/hicn-light/src/io/hicnListener.c b/hicn-light/src/io/hicnListener.c
new file mode 100755 (executable)
index 0000000..161f5b3
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <unistd.h>
+
+#include <src/io/hicnConnection.h>
+#include <src/io/hicnListener.h>
+
+#include <src/core/connection.h>
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#ifdef WITH_MAPME
+#include <src/config/symbolicNameTable.h>
+#include <src/core/mapMe.h>
+#include <src/core/message.h>
+#include <src/io/hicnTunnel.h>
+#endif /* WITH_MAPME */
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/mapMe.h>
+#include <src/core/messagePacketType.h>
+#include <src/io/listener.h>
+#include <src/socket/api.h>
+
+#define IPv6 6
+#define IPv4 4
+#define MTU_SIZE 1500  // bytes
+#define MAX_HICN_RETRY 5
+
+struct hicn_listener {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  PARCEvent *hicn_event;
+  int hicn_fd;  // this is the file descriptor got from hicn library
+
+  Address *localAddress;  // this is the local address  or 0::0 in case of the
+                          // main listener this is the address used inside
+                          // forwarder to identify the listener. Notice that this
+                          // address is the same as the fisical interfaces on
+                          // which we create the TUN. it is NOT the TUN address
+                          // which is given by libhicn after the bind operation
+                          // However the user alway uses this address since is
+                          // the only one available at configuration time
+
+  unsigned inetFamily;
+
+  int connection_id;  // this is used only if the listener is used to receive
+                      // data packets we assume that 1 connection is associated
+                      // to one listener in this case so we set the connection_id
+                      // we the connection is create. if this id is not set and a
+                      // data packet is received, the packet is dropped
+
+  unsigned conn_id;
+};
+
+static void _destroy(ListenerOps **listenerOpsPtr);
+static unsigned _getInterfaceIndex(const ListenerOps *ops);
+static const Address *_getListenAddress(const ListenerOps *ops);
+static EncapType _getEncapType(const ListenerOps *ops);
+static int _getSocket(const ListenerOps *ops);
+
+static ListenerOps _hicnTemplate = {.context = NULL,
+                                    .destroy = &_destroy,
+                                    .getInterfaceIndex = &_getInterfaceIndex,
+                                    .getListenAddress = &_getListenAddress,
+                                    .getEncapType = &_getEncapType,
+                                    .getSocket = &_getSocket};
+
+static void _hicnListener_readcb(int fd, PARCEventType what, void *hicnVoid);
+
+static bool _isEmptyAddressIPv6(Address *address) {
+  struct sockaddr_in6 *addr6 =
+      parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+  parcAssertNotNull(addr6, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(addr6));
+
+  addressGetInet6(address, addr6);
+
+  bool res = true;
+  for (int i = 0; i < 16; ++i) {
+    if (addr6->sin6_addr.s6_addr[i] != 0) {
+      res = false;
+    }
+  }
+
+  parcMemory_Deallocate((void **)&addr6);
+
+  return res;
+}
+
+static bool _isEmptyAddressIPv4(Address *address) {
+  bool res = false;
+
+  if (strcmp("inet4://0.0.0.0:1234", addressToString(address)) == 0) res = true;
+  return res;
+}
+
+ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
+                                     Address *address) {
+  HIcnListener *hicn = parcMemory_AllocateAndClear(sizeof(HIcnListener));
+  parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(HIcnListener));
+
+  hicn->forwarder = forwarder;
+  hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
+  hicn->localAddress = addressCopy(address);
+
+  hicn->inetFamily = IPv4;
+
+  hicn->connection_id = -1;
+
+  hicn_socket_helper_t *hicnSocketHelper =
+      forwarder_GetHIcnSocketHelper(forwarder);
+
+  if (_isEmptyAddressIPv4(address)) {
+    hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL);
+  } else {
+    struct sockaddr_in *tmpAddr =
+        parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+    parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(tmpAddr));
+    addressGetInet(address, tmpAddr);
+    char *local_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN);
+    inet_ntop(AF_INET, &(tmpAddr->sin_addr), local_addr, INET_ADDRSTRLEN);
+    parcMemory_Deallocate((void **)&tmpAddr);
+
+    hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr);
+
+    parcMemory_Deallocate((void **)&local_addr);
+  }
+
+  if (hicn->hicn_fd < 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(
+          hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+          "HIcnListener %s: error while creating an hicn listener in lib_hicn",
+          symbolic);
+    }
+    logger_Release(&hicn->logger);
+    addressDestroy(&hicn->localAddress);
+    parcMemory_Deallocate((void **)&hicn);
+    return NULL;
+  }
+
+  // Set non-blocking flag
+  int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL);
+  parcAssertTrue(flags != -1,
+                 "fcntl failed to obtain file descriptor flags (%d)", errno);
+  int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK);
+  parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+                  errno);
+
+  hicn->hicn_event = dispatcher_CreateNetworkEvent(
+      forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb,
+      (void *)hicn, hicn->hicn_fd);
+  dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+                               hicn->hicn_event);
+
+  ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+  parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListenerOps));
+
+  memcpy(ops, &_hicnTemplate, sizeof(ListenerOps));
+  ops->context = hicn;
+
+  if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "HIcnListener %s created", symbolic);
+  }
+
+  return ops;
+  return NULL;
+}
+
+ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
+                                      Address *address) {
+  HIcnListener *hicn = parcMemory_AllocateAndClear(sizeof(HIcnListener));
+  parcAssertNotNull(hicn, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(HIcnListener));
+
+  hicn->forwarder = forwarder;
+  hicn->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  hicn->conn_id = forwarder_GetNextConnectionId(forwarder);
+  hicn->localAddress = addressCopy(address);
+
+  hicn->inetFamily = IPv6;
+
+  hicn->connection_id = -1;
+
+  // the call to libhicn is the same both for the main and the normal listeners
+  // in both cases we need to set only the identifier. In the case of normal
+  // listener (listener for data packet) we let the library select the right ip
+  //address we just need to set the right type of packet
+
+  hicn_socket_helper_t *hicnSocketHelper =
+      forwarder_GetHIcnSocketHelper(forwarder);
+
+  if (_isEmptyAddressIPv6(address)) {
+    // create main listener
+    hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, NULL);
+  } else {
+    // create listener for the connetion
+    struct sockaddr_in6 *tmpAddr =
+        parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+
+    parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(tmpAddr));
+    addressGetInet6(address, tmpAddr);
+
+    char *local_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN);
+    inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), local_addr, INET6_ADDRSTRLEN);
+
+    parcMemory_Deallocate((void **)&tmpAddr);
+
+    hicn->hicn_fd = hicn_socket(hicnSocketHelper, symbolic, local_addr);
+
+    parcMemory_Deallocate((void **)&local_addr);
+  }
+
+  if (hicn->hicn_fd < 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(
+          hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+          "HIcnListener %s: error while creating an hicn listener in lib_hicn",
+          symbolic);
+    }
+    logger_Release(&hicn->logger);
+    addressDestroy(&hicn->localAddress);
+    parcMemory_Deallocate((void **)&hicn);
+    return NULL;
+  }
+
+  // Set non-blocking flag
+  int flags = fcntl(hicn->hicn_fd, F_GETFL, NULL);
+  parcAssertTrue(flags != -1,
+                 "fcntl failed to obtain file descriptor flags (%d)", errno);
+  int failure = fcntl(hicn->hicn_fd, F_SETFL, flags | O_NONBLOCK);
+  parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+                  errno);
+
+  hicn->hicn_event = dispatcher_CreateNetworkEvent(
+      forwarder_GetDispatcher(forwarder), true, _hicnListener_readcb,
+      (void *)hicn, hicn->hicn_fd);
+  dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+                               hicn->hicn_event);
+
+  ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+  parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListenerOps));
+
+  memcpy(ops, &_hicnTemplate, sizeof(ListenerOps));
+  ops->context = hicn;
+
+  if (logger_IsLoggable(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "HIcnListener %s created", symbolic);
+  }
+
+  return ops;
+}
+
+bool _hicnListener_BindInet6(ListenerOps *ops, const Address *remoteAddress) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  hicn_socket_helper_t *hicnSocketHelper =
+      forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+  struct sockaddr_in6 *tmpAddr =
+      parcMemory_AllocateAndClear(sizeof(struct sockaddr_in6));
+  parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(tmpAddr));
+  addressGetInet6(remoteAddress, tmpAddr);
+  char *remote_addr = parcMemory_AllocateAndClear(INET6_ADDRSTRLEN);
+  inet_ntop(AF_INET6, &(tmpAddr->sin6_addr), remote_addr, INET6_ADDRSTRLEN);
+  parcMemory_Deallocate((void **)&tmpAddr);
+
+  int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr);
+
+  bool result = false;
+  if (res < 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "hicn_bild failed %d %s", res, hicn_socket_strerror(res));
+    }
+  } else {
+    result = true;
+  }
+
+  parcMemory_Deallocate((void **)&remote_addr);
+
+  return result;
+}
+
+bool _hicnListener_BindInet(ListenerOps *ops, const Address *remoteAddress) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  hicn_socket_helper_t *hicnSocketHelper =
+      forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+  struct sockaddr_in *tmpAddr =
+      parcMemory_AllocateAndClear(sizeof(struct sockaddr_in));
+  parcAssertNotNull(tmpAddr, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(tmpAddr));
+  addressGetInet(remoteAddress, tmpAddr);
+  char *remote_addr = parcMemory_AllocateAndClear(INET_ADDRSTRLEN);
+  inet_ntop(AF_INET, &(tmpAddr->sin_addr), remote_addr, INET_ADDRSTRLEN);
+  parcMemory_Deallocate((void **)&tmpAddr);
+
+  int res = hicn_bind(hicnSocketHelper, hicn->hicn_fd, remote_addr);
+  bool result = false;
+
+  if (res < 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "hicn_bild failed %d %s", res, hicn_socket_strerror(res));
+    }
+  } else {
+    result = true;
+  }
+
+  parcMemory_Deallocate((void **)&remote_addr);
+
+  return result;
+}
+
+bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress) {
+  if (addressGetType(remoteAddress) == ADDR_INET) {
+    return _hicnListener_BindInet(ops, remoteAddress);
+  } else if (addressGetType(remoteAddress) == ADDR_INET6) {
+    return _hicnListener_BindInet6(ops, remoteAddress);
+  } else {
+    printf("Bind failed: Invalid address\n");
+    return false;
+  }
+}
+
+bool hicnListener_Punting(ListenerOps *ops, const char *prefix) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  hicn_socket_helper_t *hicnSocketHelper =
+      forwarder_GetHIcnSocketHelper(hicn->forwarder);
+
+  int res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix);
+  int retry = 0;
+
+  while (res < 0 && retry < MAX_HICN_RETRY) {
+    sleep(1);
+    res = hicn_listen(hicnSocketHelper, hicn->hicn_fd, prefix);
+    retry++;
+  }
+
+  if (res < 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "hicn_listen failed %d %s", res, hicn_socket_strerror(res));
+    }
+    return false;
+  }
+
+  return true;
+}
+
+bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  if (hicn) {
+    hicn->connection_id = connId;
+    return true;
+  }
+  return false;
+}
+
+static void _hicnListener_Destroy(HIcnListener **listenerPtr) {
+  parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listenerPtr,
+                    "Parameter must derefernce to non-null pointer");
+
+  HIcnListener *hicn = *listenerPtr;
+
+  // close(hicn->hicn_fd); //XXX close the fd in the hicnlib (detroy listener?)
+  dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(hicn->forwarder),
+                                 &hicn->hicn_event);
+  logger_Release(&hicn->logger);
+  addressDestroy(&hicn->localAddress);
+  parcMemory_Deallocate((void **)&hicn);
+  *listenerPtr = NULL;
+}
+
+static void _destroy(ListenerOps **listenerOpsPtr) {
+  ListenerOps *ops = *listenerOpsPtr;
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  _hicnListener_Destroy(&hicn);
+  parcMemory_Deallocate((void **)&ops);
+  *listenerOpsPtr = NULL;
+}
+
+static unsigned _getInterfaceIndex(const ListenerOps *ops) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  return hicn->conn_id;
+}
+
+static const Address *_getListenAddress(const ListenerOps *ops) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  return hicn->localAddress;
+}
+
+static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_HICN; }
+
+static int _getSocket(const ListenerOps *ops) {
+  HIcnListener *hicn = (HIcnListener *)ops->context;
+  return hicn->hicn_fd;
+}
+
+// ===============================
+
+static void _readFrameToDiscard(HIcnListener *hicn, int fd) {
+  // we need to discard the frame.  Read 1 byte.  This will clear it off the
+  // stack.
+  uint8_t buffer;
+  int nread = read(fd, &buffer, 1);
+
+  if (nread > 0) {
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Debug)) {
+      logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "Discarded frame from fd %d", fd);
+    }
+  } else if (nread < 0) {
+    printf("Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+           strerror(errno));
+    if (logger_IsLoggable(hicn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      logger_Log(hicn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+                 strerror(errno));
+    }
+  }
+}
+
+static unsigned _createNewConnection(HIcnListener *hicn, int fd,
+                                     const AddressPair *pair) {
+  bool isLocal = false;
+
+  // udpConnection_Create takes ownership of the pair
+  IoOperations *ops = hicnConnection_Create(hicn->forwarder, fd, pair, isLocal);
+  Connection *conn = connection_Create(ops);
+
+  connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder), conn);
+  unsigned connid = ioOperations_GetConnectionId(ops);
+
+  return connid;
+}
+
+const Connection *_findConnectionFromPacket(HIcnListener *hicn,
+                                            Address *packetSourceAddress) {
+  const Connection *conn = NULL;
+  if (hicn->connection_id != -1) {
+    conn = connectionTable_FindById(
+        forwarder_GetConnectionTable(hicn->forwarder), hicn->connection_id);
+  } else {
+    if (packetSourceAddress != NULL) {
+      // in this first check we try to retrieve the standard connection
+      // generated by the hicn-light
+      AddressPair *pair =
+          addressPair_Create(hicn->localAddress, packetSourceAddress);
+      conn = connectionTable_FindByAddressPair(
+          forwarder_GetConnectionTable(hicn->forwarder), pair);
+      addressPair_Release(&pair);
+    }
+  }
+
+  return conn;
+}
+
+static Address *_createAddressFromPacket(uint8_t *msgBuffer) {
+  Address *packetAddr = NULL;
+  if (messageHandler_GetIPPacketType(msgBuffer) == IPv6_TYPE) {
+    struct sockaddr_in6 addr_in6;
+    addr_in6.sin6_family = AF_INET6;
+    addr_in6.sin6_port = htons(1234);
+    addr_in6.sin6_flowinfo = 0;
+    addr_in6.sin6_scope_id = 0;
+    memcpy(&addr_in6.sin6_addr,
+           (struct in6_addr *)messageHandler_GetSource(msgBuffer), 16);
+    packetAddr = addressCreateFromInet6(&addr_in6);
+  } else if (messageHandler_GetIPPacketType(msgBuffer) == IPv4_TYPE) {
+    struct sockaddr_in addr_in;
+    addr_in.sin_family = AF_INET;
+    addr_in.sin_port = htons(1234);
+    memcpy(&addr_in.sin_addr,
+           (struct in_addr *)messageHandler_GetSource(msgBuffer), 4);
+    packetAddr = addressCreateFromInet(&addr_in);
+  }
+  return packetAddr;
+}
+
+static void _handleProbeMessage(HIcnListener *hicn, uint8_t *msgBuffer) {
+  Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+  if (packetAddr != NULL) {
+    const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+    if (conn != NULL) {
+      // we drop all the probes for a connection that does not exists
+      connection_HandleProbe((Connection *)conn, msgBuffer,
+                             forwarder_GetTicks(hicn->forwarder));
+    }
+  }
+
+  addressDestroy(&packetAddr);
+  parcMemory_Deallocate((void **)&msgBuffer);
+}
+
+static void _handleWldrNotification(HIcnListener *hicn, uint8_t *msgBuffer) {
+  Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+  if (packetAddr == NULL) {
+    parcMemory_Deallocate((void **)&msgBuffer);
+    return;
+  }
+
+  const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+  if (conn == NULL) {
+    addressDestroy(&packetAddr);
+    return;
+  }
+
+  addressDestroy(&packetAddr);
+
+  Message *message = message_CreateFromByteArray(
+      connection_GetConnectionId(conn), msgBuffer,
+      MessagePacketType_WldrNotification, forwarder_GetTicks(hicn->forwarder),
+      forwarder_GetLogger(hicn->forwarder));
+
+  connection_HandleWldrNotification((Connection *)conn, message);
+
+  message_Release(&message);
+}
+
+#ifdef WITH_MAPME
+static void _handleMapMe(HIcnListener *hicn, int fd, uint8_t *msgBuffer) {
+  Address *packetAddr = _createAddressFromPacket(msgBuffer);
+
+  if (packetAddr == NULL) {
+    parcMemory_Deallocate((void **)&msgBuffer);
+    return;
+  }
+
+  const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+  unsigned conn_id;
+  if (conn == NULL) {
+    /* Unlike the interest path, we don't create virtual connections bound
+     * on the listener, whose only interest is to send data, but full
+     * tunnels to be able to route interests
+     *
+     * packetAddr is the remote address, we need to ask the lib for our
+     * local address
+     * hicn->localAddress is None as the interest is received by the main
+     * listener.
+     */
+    printf("MapMe, connection did not exist, creating\n");
+
+    /* Populate remote_address through packetAddr */
+    struct sockaddr_in6 sockaddr;  // XXX IPv6 only
+    addressGetInet6(packetAddr, &sockaddr);
+    ip_address_t remote_address = {.family = AF_INET6,
+                                   .prefix_len = IPV6_ADDR_LEN_BITS};
+    memcpy(&remote_address.buffer, &sockaddr.sin6_addr,
+           ip_address_len(&remote_address));
+
+    /* Get local address through libhicn */
+    ip_address_t local_address;
+    int rc = hicn_get_local_address(&remote_address, &local_address);
+    if (rc < 0) {
+      printf("Error getting local address. Discarded mapme packet.\n");
+      return;
+    }
+
+    struct sockaddr_in6 addr_in6;
+    addr_in6.sin6_family = AF_INET6;
+    addr_in6.sin6_port = htons(1234);
+    addr_in6.sin6_flowinfo = 0;
+    addr_in6.sin6_scope_id = 0;
+    memcpy(&addr_in6.sin6_addr, (struct in6_addr *)&(local_address.buffer), 16);
+
+    Address *localAddr = addressCreateFromInet6(&addr_in6);
+    IoOperations *ops =
+        hicnTunnel_Create(hicn->forwarder, localAddr, packetAddr);
+
+    if (!ops) {
+      printf("Error creating tunnel. Discarded mapme packet.\n");
+      return;
+    }
+
+    conn = connection_Create(ops);
+
+    connectionTable_Add(forwarder_GetConnectionTable(hicn->forwarder),
+                        (Connection *)conn);
+  }
+  conn_id = connection_GetConnectionId(conn);
+
+  addressDestroy(&packetAddr);
+
+  forwarder_ProcessMapMe(hicn->forwarder, msgBuffer, conn_id);
+}
+#endif /* WITH_MAPME */
+
+static Message *_readMessage(HIcnListener *hicn, int fd, uint8_t *msgBuffer) {
+  Message *message = NULL;
+
+  ssize_t readLength = read(fd, msgBuffer, MTU_SIZE);
+
+  if (readLength < 0) {
+    printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno));
+    return message;
+  }
+
+  size_t packetLength = messageHandler_GetTotalPacketLength(msgBuffer);
+
+  if (readLength != packetLength) {
+    parcMemory_Deallocate((void **)&msgBuffer);
+    return message;
+  }
+
+  if (messageHandler_IsTCP(msgBuffer)) {
+    MessagePacketType pktType;
+    unsigned connid = 0;
+    if (messageHandler_IsData(msgBuffer)) {
+      pktType = MessagePacketType_ContentObject;
+      if (hicn->connection_id == -1) {
+        parcMemory_Deallocate((void **)&msgBuffer);
+        return message;
+      } else {
+        connid = hicn->connection_id;
+      }
+    } else if (messageHandler_IsInterest(msgBuffer)) {
+      // notice that the connections for the interest (the one that we create at
+      // run time) uses as a local address 0::0, so the main tun
+      pktType = MessagePacketType_Interest;
+      Address *packetAddr = _createAddressFromPacket(msgBuffer);
+      const Connection *conn = _findConnectionFromPacket(hicn, packetAddr);
+
+      if (conn == NULL) {
+        AddressPair *pair = addressPair_Create(hicn->localAddress, packetAddr);
+        connid = _createNewConnection(hicn, fd, pair);
+        addressPair_Release(&pair);
+      } else {
+        connid = connection_GetConnectionId(conn);
+      }
+      addressDestroy(&packetAddr);
+    } else {
+      printf("Got a packet that is not a data nor an interest, drop it!\n");
+      parcMemory_Deallocate((void **)&msgBuffer);
+      return message;
+    }
+
+    message = message_CreateFromByteArray(connid, msgBuffer, pktType,
+                                          forwarder_GetTicks(hicn->forwarder),
+                                          forwarder_GetLogger(hicn->forwarder));
+    if (message == NULL) {
+      parcMemory_Deallocate((void **)&msgBuffer);
+    }
+  } else if (messageHandler_IsWldrNotification(msgBuffer)) {
+    _handleWldrNotification(hicn, msgBuffer);
+  } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
+    _handleProbeMessage(hicn, msgBuffer);
+  }
+#ifdef WITH_MAPME
+  else if (mapMe_isMapMe(msgBuffer)) {
+    /* This function triggers the handling of the MAP-Me message, and we
+     * will return NULL so as to terminate the processing of this
+     * msgBuffer. */
+    _handleMapMe(hicn, fd, msgBuffer);
+  }
+#endif /* WITH_MAPME */
+
+  return message;
+}
+
+static void _receivePacket(HIcnListener *hicn, int fd) {
+  Message *msg = NULL;
+  uint8_t *msgBuffer = parcMemory_AllocateAndClear(MTU_SIZE);
+  msg = _readMessage(hicn, fd, msgBuffer);
+
+  if (msg) {
+    forwarder_Receive(hicn->forwarder, msg);
+  }
+}
+
+static void _hicnListener_readcb(int fd, PARCEventType what, void *hicnVoid) {
+  HIcnListener *hicn = (HIcnListener *)hicnVoid;
+
+  if (hicn->inetFamily == IPv4 || hicn->inetFamily == IPv6) {
+    if (what & PARCEventType_Read) {
+      _receivePacket(hicn, fd);
+    }
+  } else {
+    _readFrameToDiscard(hicn, fd);
+  }
+}
diff --git a/hicn-light/src/io/hicnListener.h b/hicn-light/src/io/hicnListener.h
new file mode 100755 (executable)
index 0000000..98c5387
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hicnListener.h
+ * @brief Listens for in coming HIcn connections
+ *
+ *
+ */
+
+#ifndef hicnListener_h
+#define hicnListener_h
+
+#include <src/core/forwarder.h>
+#include <src/core/messageHandler.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+struct hicn_listener;
+typedef struct hicn_listener HIcnListener;
+
+ListenerOps *hicnListener_CreateInet(Forwarder *forwarder, char *symbolic,
+                                     Address *address);
+ListenerOps *hicnListener_CreateInet6(Forwarder *forwarder, char *symbolic,
+                                      Address *address);
+bool hicnListener_Punting(ListenerOps *ops, const char *prefix);
+bool hicnListener_Bind(ListenerOps *ops, const Address *remoteAddress);
+bool hicnListener_SetConnectionId(ListenerOps *ops, unsigned connId);
+// const Address *hicnListener_GetTunAddress(const ListenerOps *ops);
+#endif  // hicnListener_h
diff --git a/hicn-light/src/io/hicnTunnel.c b/hicn-light/src/io/hicnTunnel.c
new file mode 100755 (executable)
index 0000000..e553931
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/hicnConnection.h>
+#include <src/io/hicnListener.h>
+#include <src/io/hicnTunnel.h>
+
+IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder,
+                                          ListenerOps *localListener,
+                                          const Address *remoteAddress) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(localListener, "Parameter localListener must be non-null");
+  parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null");
+
+  Logger *logger = forwarder_GetLogger(forwarder);
+
+  IoOperations *ops = NULL;
+  if (localListener->getEncapType(localListener) == ENCAP_HICN) {
+    const Address *localAddress =
+        localListener->getListenAddress(localListener);
+    address_type localType = addressGetType(localAddress);
+    address_type remoteType = addressGetType(remoteAddress);
+
+    if (localType == remoteType) {
+      bool res = hicnListener_Bind(localListener, remoteAddress);
+      if (res == false) {
+        if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+          logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                     "Unable to bind local listener to remote node");
+        }
+        return ops;
+      }
+
+      // localAddress = hicnListener_GetTunAddress(localListener); //This is the
+      // true local address
+
+      AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+      bool isLocal = false;
+      int fd = localListener->getSocket(localListener);
+      ops = hicnConnection_Create(forwarder, fd, pair, isLocal);
+
+      addressPair_Release(&pair);
+    } else {
+      if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+        logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                   "Local listener of type %s and remote type %s, cannot "
+                   "establish tunnel",
+                   addressTypeToString(localType),
+                   addressTypeToString(remoteType));
+      }
+    }
+  } else {
+    if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+      logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Local listener %p is not type UDP, cannot establish tunnel",
+                 (void *)localListener);
+    }
+  }
+
+  return ops;
+}
+
+IoOperations *hicnTunnel_Create(Forwarder *forwarder,
+                                const Address *localAddress,
+                                const Address *remoteAddress) {
+  ListenerSet *set = forwarder_GetListenerSet(forwarder);
+  ListenerOps *listener = listenerSet_Find(set, ENCAP_HICN, localAddress);
+  IoOperations *ops = NULL;
+  if (listener) {
+    ops = hicnTunnel_CreateOnListener(forwarder, listener, remoteAddress);
+  } else {
+    if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      char *str = addressToString(localAddress);
+      logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "Could not find listener to match address %s", str);
+      parcMemory_Deallocate((void **)&str);
+    }
+  }
+
+  if (ops) {
+    hicnListener_SetConnectionId(listener, ops->getConnectionId(ops));
+  }
+
+  return ops;
+}
diff --git a/hicn-light/src/io/hicnTunnel.h b/hicn-light/src/io/hicnTunnel.h
new file mode 100755 (executable)
index 0000000..7029579
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hicnTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ * Creates a "hicn tunnel" to a remote system.  There must already be a local
+ * HICN listener for the local side of the connection.
+ *
+ */
+
+#ifndef hicnTunnel_h
+#define hicnTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ * Establishes a connection to a remote system over HICN
+ *
+ * The remoteAddress must be of the same type (i.e. v4 or v6) as the
+ * localAddress.  There must be an existing HICN listener on the local address.
+ * If either of these are not true, will return NULL.
+ *
+ * The connection will go in the table immediately, and will be in the "up"
+ * state.
+ *
+ * @param [in] an allocated hicn-light Forwarder
+ * @param [in] localAddress The local IP address and port to use for the
+ * connection
+ * @param [in] remote Address the remote IP address for the connection, must
+ * include a destination port.
+ *
+ * @retval non-null An allocated Io Operations structure for the connection
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *hicnTunnel_Create(Forwarder *forwarder,
+                                const Address *localAddress,
+                                const Address *remoteAddress);
+
+IoOperations *hicnTunnel_CreateOnListener(Forwarder *forwarder,
+                                          ListenerOps *localListener,
+                                          const Address *remoteAddress);
+
+#endif  // hicnTunnel_h
diff --git a/hicn-light/src/io/ioOperations.c b/hicn-light/src/io/ioOperations.c
new file mode 100755 (executable)
index 0000000..bbc8cec
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <src/io/ioOperations.h>
+#include <stdio.h>
+
+void *ioOperations_GetClosure(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  return ops->closure;
+}
+
+bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
+                       Message *message) {
+  return ops->send(ops, nexthop, message);
+}
+
+const Address *ioOperations_GetRemoteAddress(const IoOperations *ops) {
+  return ops->getRemoteAddress(ops);
+}
+
+const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops) {
+  return ops->getAddressPair(ops);
+}
+
+bool ioOperations_IsUp(const IoOperations *ops) { return ops->isUp(ops); }
+
+bool ioOperations_IsLocal(const IoOperations *ops) { return ops->isLocal(ops); }
+
+unsigned ioOperations_GetConnectionId(const IoOperations *ops) {
+  return ops->getConnectionId(ops);
+}
+
+void ioOperations_Release(IoOperations **opsPtr) {
+  IoOperations *ops = *opsPtr;
+  ops->destroy(opsPtr);
+}
+
+const void *ioOperations_Class(const IoOperations *ops) {
+  return ops->class(ops);
+}
+
+list_connections_type ioOperations_GetConnectionType(const IoOperations *ops) {
+  return ops->getConnectionType(ops);
+}
+
+Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
+                             uint8_t *message) {
+  return ops->sendProbe(ops, probeType, message);
+}
diff --git a/hicn-light/src/io/ioOperations.h b/hicn-light/src/io/ioOperations.h
new file mode 100755 (executable)
index 0000000..dee6603
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2017-2019 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 the interface all connections use to communicate with the forwarder.
+ *
+ * @code
+ *
+ *   static IoOperations _template = {
+ *      .closure           = NULL,
+ *      .send              = &_etherConnection_Send,
+ *      .getRemoteAddress  = &_etherConnection_GetRemoteAddress,
+ *      .getAddressPair    = &_etherConnection_GetAddressPair,
+ *      .getConnectionId   = &_etherConnection_GetConnectionId,
+ *      .isUp              = &_etherConnection_IsUp,
+ *      .isLocal           = &_etherConnection_IsLocal,
+ *      .destroy           = &_etherConnection_DestroyOperations,
+ *      .class             = &_etherConnection_Class,
+ *      .getConnectionType = &_etherConnection_getConnectionType
+ *   };
+ *
+ *   IoOperations *
+ *   etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
+ * AddressPair *pair)
+ *   {
+ *      _EtherState *etherConnState = parcMemory_Allocate(sizeof(_EtherState));
+ *      // Fill in etherConnState with instance variables
+ *
+ *      IoOperations *io_ops = parcMemory_Allocate(sizeof(IoOperations));
+ *      memcpy(io_ops, &_template, sizeof(IoOperations));
+ *      io_ops->closure = etherConnState;
+ *      // Add to connection table, send missives about connection state
+ *
+ *      return op_ops;
+ *   }
+ * @endcode
+ *
+ */
+
+/**
+ * I/O is built around a callback structure.  The connection table contains an
+ * operations structure built around function pointers.  These allow the
+ * connection table to be agnostic about underlying connections.
+ */
+
+#ifndef io_h
+#define io_h
+
+#include <src/core/message.h>
+#include <src/core/ticks.h>
+#include <src/io/addressPair.h>
+#include <src/utils/address.h>
+
+// packet types for probing
+#define PACKET_TYPE_PROBE_REQUEST 5
+#define PACKET_TYPE_PROBE_REPLY 6
+
+struct io_ops;
+typedef struct io_ops IoOperations;
+
+/**
+ * @typedef IoOperations
+ * @abstract The IO Operations structure abstracts an connection's properties
+ * and send() method
+ * @constant context Implementation specific opaque data, passed back on each
+ * call
+ * @constant send function pointer to send a message, does not destroy the
+ * message
+ * @constant getRemoteAddress function pointer to return the "to" address
+ * associated with the connection. Some connections might not have a specific
+ * peer, such as multicast, where its the group address.
+ * @constant isUp test if the connection is up, ready to send a message.
+ * @constant isLocal test if the connection is local to the host.
+ * @constant getConnectionId returns the hicn-light id for the connection.
+ * @constant destroy releases a refernce count on the connection and possibly
+ * destroys the connection.
+ * @constant class A unique identifier for each class that instantiates
+ * IoOperations.
+ * @constant getConnectionType Returns the type of connection (TCP, UDP, L2,
+ * etc.) of the underlying connection.
+ * @discussion <#Discussion#>
+ */
+struct io_ops {
+  void *closure;
+  bool (*send)(IoOperations *ops, const Address *nexthop, Message *message);
+  const Address *(*getRemoteAddress)(const IoOperations *ops);
+  const AddressPair *(*getAddressPair)(const IoOperations *ops);
+  bool (*isUp)(const IoOperations *ops);
+  bool (*isLocal)(const IoOperations *ops);
+  unsigned (*getConnectionId)(const IoOperations *ops);
+  void (*destroy)(IoOperations **opsPtr);
+  const void *(*class)(const IoOperations *ops);
+  list_connections_type (*getConnectionType)(const IoOperations *ops);
+  Ticks (*sendProbe)(IoOperations *ops, unsigned probeType, uint8_t *message);
+};
+
+/**
+ * Returns the closure of the interface
+ *
+ * The creator of the closure sets this parameter to store its state.
+ *
+ * @param [in] ops A concrete instance of the interface
+ *
+ * @return The value set by the concrete instance of the interface.
+ *
+ * Example:
+ * @clode
+ * {
+
+ * }
+ * @endcode
+ */
+void *ioOperations_GetClosure(const IoOperations *ops);
+
+/**
+ * Release all memory related to the interface and implementation
+ *
+ * This function must release all referenced memory in the concrete
+ * implementation and memory related to the IoOperations.  It should NULL the
+ * input parameter.
+ *
+ * @param [in,out] opsPtr Pointer to interface.  Will be NULLed.
+ *
+ * Example:
+ * @code
+ *
+ *   static void
+ *   _etherConnection_InternalRelease(_EtherState *etherConnState)
+ *   {
+ *      // release internal state of _EtherState
+ *   }
+ *
+ *   static void
+ *   _etherConnection_Release(IoOperations **opsPtr)
+ *   {
+ *      IoOperations *ops = *opsPtr;
+ *
+ *      _EtherState *etherConnState = (_EtherState *)
+ * ioOperations_GetClosure(ops);
+ *      _etherConnection_InternalRelease(etherConnState);
+ *
+ *      parcMemory_Deallocate((void **) &ops);
+ *   }
+ *
+ *   IoOperations *
+ *   etherConnection_Create(Forwarder *forwarder, GenericEther *ether,
+ * AddressPair *pair)
+ *   {
+ *      size_t allocationSize = sizeof(_EtherState) + sizeof(IoOperations);
+ *      IoOperations *ops = parcMemory_AllocateAndClear(allocationSize);
+ *      if (ops) {
+ *         // fill in other interface functions
+ *         ops->destroy = &_etherConnection_Release;
+ *         ops->closure = (uint8_t *) ops + sizeof(IoOperations);
+ *
+ *         _EtherState *etherConnState = ioOperations_GetClosure(ops);
+ *         // fill in Ethernet state
+ *      }
+ *      return ops;
+ *   }
+ * @endcode
+ */
+void ioOperations_Release(IoOperations **opsPtr);
+
+/**
+ * Sends the specified Message out this connection
+ *
+ * The the implementation of send may queue the message, it must acquire a
+ * reference to it.
+ *
+ * @param [in] ops The connection implementation.
+ * @param [in] nexthop On multiple access networks, this parameter might be
+ * used, usually NULL.
+ * @param [in] message The message to send.  If the message will be queued, it
+ * will be acquired.
+ *
+ * @return true The message was sent or queued
+ * @retrun false An error occured and the message will not be sent or queued
+ *
+ * Example:
+ * @code
+ * {
+ *     if (ioOperations_IsUp(conn->ops)) {
+ *        return ioOperations_Send(conn->ops, NULL, message);
+ *     }
+ * }
+ * @endcode
+ */
+bool ioOperations_Send(IoOperations *ops, const Address *nexthop,
+                       Message *message);
+
+/**
+ * A connection is made up of a local and a remote address.  This function
+ * returns the remote address.
+ *
+ * Represents the destination endpoint of the communication.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null The remote address
+ * @return null The connection does not have a remote address
+ *
+ * Example:
+ * @code
+ * {
+ *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
+ * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
+ * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
+ * addressPair_Create(local, remote); IoOperations *ops =
+ * etherConnection_Create(forwarder, ether, pair);
+ *
+ *    const Address *test = ioOperations_GetRemoteAddress(ops);
+ *    parcAssertTrue(addressEquals(test, remote), "Wrong remote address");
+ *    ioOperations_Release(&ops);
+ *    addressPair_Release(&pair);
+ *    addressDestroy(&local);
+ *    addressDestroy(&remote);
+ * }
+ * @endcode
+ */
+const Address *ioOperations_GetRemoteAddress(const IoOperations *ops);
+
+/**
+ * A connection is made up of a local and a remote address.  This function
+ * returns the address pair.
+ *
+ * Represents the destination endpoint of the communication.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null The address pair
+ * @return null An error.
+ *
+ * Example:
+ * @code
+ * {
+ *    Address *local =  addressCreateFromLink((uint8_t []) { 0x01, 0x02, 0x03,
+ * 0x04, 0x05, 0x06 }, 6); Address *remote = addressCreateFromLink((uint8_t [])
+ * { 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, 6); AddressPair *pair =
+ * addressPair_Create(local, remote); IoOperations *ops =
+ * etherConnection_Create(forwarder, ether, pair);
+ *
+ *    const AddressPair *test = ioOperations_GetAddressPair(ops);
+ *    parcAssertTrue(addressPair(test, pair), "Wrong address pair");
+ *    ioOperations_Release(&ops);
+ *    addressPair_Release(&pair);
+ *    addressDestroy(&local);
+ *    addressDestroy(&remote);
+ * }
+ * @endcode
+ */
+const AddressPair *ioOperations_GetAddressPair(const IoOperations *ops);
+
+/**
+ * Returns true if the underlying connection is in operation
+ *
+ * An UP connection is able to send and receive packets. If a subsystem needs to
+ * take actions when a connection goes UP or DOWN, it should subscribe as a
+ * Missive listener.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return true The connection is UP
+ * @return false The connection is not UP
+ *
+ * Example:
+ * @code
+ * {
+ *     if (ioOperations_IsUp(conn->ops)) {
+ *        return ioOperations_Send(conn->ops, NULL, message);
+ *     }
+ * }
+ * @endcode
+ */
+bool ioOperations_IsUp(const IoOperations *ops);
+
+/**
+ * If the remote address is local to this system, returns true
+ *
+ * Will return true if an INET or INET6 connection is on localhost.  Will return
+ * true for AF_UNIX.  An Ethernet connection is not local.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return true The remote address is local to the system
+ * @return false The remote address is not local
+ *
+ * Example:
+ * @code
+ * {
+ *     // Is the ingress connection remote?  If so check for non-zero and
+ * decrement if (!ioOperations(ingressConnectionOps) { uint8_t hoplimit =
+ * message_GetHopLimit(interestMessage); if (hoplimit == 0) {
+ *           // error
+ *        } else {
+ *           hoplimit--;
+ *        }
+ *        // take actions on hoplimit
+ *     }
+ * }
+ * @endcode
+ */
+bool ioOperations_IsLocal(const IoOperations *ops);
+
+/**
+ * Returns the connection ID represented by this IoOperations in the
+ * ConnectionTable.
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return number The connection ID in the connection table.
+ *
+ * Example:
+ * @code
+ * {
+ *     unsigned id = ioOperations_GetConnectionId(ingressIoOps);
+ *     const Connection *conn =
+ * connectionTable_FindById(forwarder->connectionTable, id);
+ * }
+ * @endcode
+ */
+unsigned ioOperations_GetConnectionId(const IoOperations *ops);
+
+/**
+ * A pointer that represents the class of the connection
+ *
+ * Each concrete implementation has a class pointer that is unique to the
+ * implementation (not instance). Each implementation is free to choose how to
+ * determine the value, so long as it is unique on the system. This is a
+ * system-local value.
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return non-null A pointer value unique to the implementation (not instance).
+ *
+ * Example:
+ * @code
+ *   bool
+ *   etherConnection_IsInstanceOf(const Connection *conn)
+ *   {
+ *      bool result = false;
+ *      if (conn != NULL) {
+ *         IoOperations *ops = connection_GetIoOperations(conn);
+ *         const void *class = ioOperations_Class(ops);
+ *         result = (class == _etherConnection_Class(ops));
+ *      }
+ *      return result;
+ *   }
+ * @endcode
+ */
+const void *ioOperations_Class(const IoOperations *ops);
+
+/**
+ * Returns the transport type of the connection (TCP, UDP, L2, etc.).
+ *
+ * TCP and AF_UNIX are both stream connections and will both return
+ * "Connection_TCP". Ethernet will return "Connection_L2".
+ *
+ * @param [in] ops The connection implementation.
+ *
+ * @return Connection_TCP A TCP4, TCP6, or AF_UNIX connection
+ * @return Connection_UDP A UDP4 or UDP6 connection
+ * @return Connection_L2 An Ethernet connection
+ *
+ * Example:
+ * @code
+ * {
+ *     ConnectionType type =
+ * ioOperations_GetConnectionType(connection_GetIoOperations(connection));
+ *     Connection *Conn =
+ * Connection_Create(connection_GetConnectionId(connection), localAddress,
+ * remoteAddress, type);
+ * }
+ * @endcode
+ */
+list_connections_type ioOperations_GetConnectionType(const IoOperations *ops);
+
+Ticks ioOperations_SendProbe(IoOperations *ops, unsigned probeType,
+                             uint8_t *message);
+#endif  // io_h
diff --git a/hicn-light/src/io/listener.h b/hicn-light/src/io/listener.h
new file mode 100755 (executable)
index 0000000..ffbb513
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file listener.h
+ * @brief Provides the function abstraction of all Listeners.
+ *
+ * A listener accepts in coming packets.  A Stream listener will accept the
+ * connection then pass it off to the {@link StreamConnection} class.  A
+ * datagram listener will have to have its own way to multiplex packets.
+ *
+ */
+
+#ifndef listener_h
+#define listener_h
+
+#include <src/utils/address.h>
+
+struct listener_ops;
+typedef struct listener_ops ListenerOps;
+
+typedef enum {
+  ENCAP_TCP,   /**< TCP encapsulation type */
+  ENCAP_UDP,   /**< UDP encapsulation type */
+  ENCAP_ETHER, /**< Ethernet encapsulation type */
+  ENCAP_LOCAL, /**< A connection to a local protocol stack */
+  ENCAP_HICN
+} EncapType;
+
+struct listener_ops {
+  /**
+   * A user-defined parameter
+   */
+  void *context;
+
+  /**
+   * Called to destroy the Listener.
+   *
+   * @param [in] listenerOpsPtr Double pointer to this structure
+   */
+  void (*destroy)(ListenerOps **listenerOpsPtr);
+
+  /**
+   * Returns the interface index of the listener.
+   *
+   * @param [in] ops Pointer to this structure
+   *
+   * @return the interface index of the listener
+   */
+  unsigned (*getInterfaceIndex)(const ListenerOps *ops);
+
+  /**
+   * Returns the address pair that defines the listener (local, remote)
+   *
+   * @param [in] ops Pointer to this structure
+   *
+   * @return the (local, remote) pair of addresses
+   */
+  const Address *(*getListenAddress)(const ListenerOps *ops);
+
+  /**
+   * Returns the encapsulation type of the listener (e.g. TCP, UDP, HICN)
+   *
+   * @param [in] ops Pointer to this structure
+   *
+   * @return the listener encapsulation type
+   */
+  EncapType (*getEncapType)(const ListenerOps *ops);
+
+  /**
+   * Returns the underlying socket associated with the listener
+   *
+   * Not all listeners are capable of returning a useful socket.  In those
+   * cases, this function pointer is NULL.
+   *
+   * TCP does not support this operation (function is NULL).  UDP returns its
+   * local socket.
+   *
+   * The caller should never close this socket, the listener will do that when
+   * its destroy method is called.
+   *
+   * @param [in] ops Pointer to this structure
+   *
+   * @retval integer The socket descriptor
+   *
+   * Example:
+   * @code
+   * <#example#>
+   * @endcode
+   */
+  int (*getSocket)(const ListenerOps *ops);
+};
+#endif  // listener_h
diff --git a/hicn-light/src/io/listenerSet.c b/hicn-light/src/io/listenerSet.c
new file mode 100755 (executable)
index 0000000..a890cd5
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/io/listenerSet.h>
+
+struct listener_set {
+  PARCArrayList *listOfListeners;
+};
+
+static void listenerSet_DestroyListenerOps(void **opsPtr) {
+  ListenerOps *ops = *((ListenerOps **)opsPtr);
+  ops->destroy(&ops);
+}
+
+ListenerSet *listenerSet_Create() {
+  ListenerSet *set = parcMemory_AllocateAndClear(sizeof(ListenerSet));
+  parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListenerSet));
+  set->listOfListeners = parcArrayList_Create(listenerSet_DestroyListenerOps);
+
+  return set;
+}
+
+void listenerSet_Destroy(ListenerSet **setPtr) {
+  parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+  ListenerSet *set = *setPtr;
+  parcArrayList_Destroy(&set->listOfListeners);
+  parcMemory_Deallocate((void **)&set);
+  *setPtr = NULL;
+}
+
+/**
+ * @function listenerSet_Add
+ * @abstract Adds the listener to the set
+ * @discussion
+ *     Unique set based on pair (EncapType, localAddress)
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+bool listenerSet_Add(ListenerSet *set, ListenerOps *ops) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+
+  int opsEncap = ops->getEncapType(ops);
+  const Address *opsAddress = ops->getListenAddress(ops);
+
+  // make sure its not in the set
+  size_t length = parcArrayList_Size(set->listOfListeners);
+  for (size_t i = 0; i < length; i++) {
+    ListenerOps *entry = parcArrayList_Get(set->listOfListeners, i);
+
+    int entryEncap = entry->getEncapType(entry);
+    const Address *entryAddress = entry->getListenAddress(entry);
+
+    if (opsEncap == entryEncap && addressEquals(opsAddress, entryAddress)) {
+      // duplicate
+      return false;
+    }
+  }
+
+  parcArrayList_Add(set->listOfListeners, ops);
+  return true;
+}
+
+size_t listenerSet_Length(const ListenerSet *set) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  return parcArrayList_Size(set->listOfListeners);
+}
+
+/**
+ * Returns the listener at the given index
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] index The index position (0 <= index < listenerSet_Count)
+ *
+ * @retval non-null The listener at index
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  return parcArrayList_Get(set->listOfListeners, index);
+}
+
+ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
+                              const Address *localAddress) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  parcAssertNotNull(localAddress, "Parameter localAddress must be non-null");
+
+  ListenerOps *match = NULL;
+
+  for (size_t i = 0; i < parcArrayList_Size(set->listOfListeners) && !match;
+       i++) {
+    ListenerOps *ops = parcArrayList_Get(set->listOfListeners, i);
+    parcAssertNotNull(ops, "Got null listener ops at index %zu", i);
+
+    if (ops->getEncapType(ops) == encapType) {
+      if (addressEquals(localAddress, ops->getListenAddress(ops))) {
+        match = ops;
+      }
+    }
+  }
+
+  return match;
+}
diff --git a/hicn-light/src/io/listenerSet.h b/hicn-light/src/io/listenerSet.h
new file mode 100755 (executable)
index 0000000..671e684
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file listenerSet.h
+ * @brief A listener set is unique on (EncapType, localAddress)
+ *
+ * Keeps track of all the running listeners.  The set is unique on the
+ * encapsulation type and the local address.  For example, with TCP
+ * encapsulation and local address 127.0.0.1 or Ethernet encapsulation and MAC
+ * address 00:11:22:33:44:55.
+ *
+ * NOTE: This does not allow multiple EtherType on the same interface because
+ * the Address for a LINK address does not include an EtherType.
+ *
+ */
+
+#ifndef listenerSet_h
+#define listenerSet_h
+
+#include <src/io/listener.h>
+
+struct listener_set;
+typedef struct listener_set ListenerSet;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerSet *listenerSet_Create(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void listenerSet_Destroy(ListenerSet **setPtr);
+
+/**
+ * @function listenerSet_Add
+ * @abstract Adds the listener to the set
+ * @discussion
+ *     Unique set based on pair (EncapType, localAddress).
+ *     Takes ownership of the ops memory if added.
+ *
+ * @param <#param1#>
+ * @return true if added, false if not
+ */
+bool listenerSet_Add(ListenerSet *set, ListenerOps *ops);
+
+/**
+ * The number of listeners in the set
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ *
+ * @retval <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t listenerSet_Length(const ListenerSet *set);
+size_t listenerSet_Length(const ListenerSet *set);
+
+/**
+ * Returns the listener at the given index
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] index The index position (0 <= index < listenerSet_Lenght)
+ *
+ * @retval non-null The listener at index
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+ListenerOps *listenerSet_Get(const ListenerSet *set, size_t index);
+
+/**
+ * Looks up a listener by its key (EncapType, LocalAddress)
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] set An allocated listener set
+ * @param [in] encapType the listener type
+ * @param [in] localAddress The local bind address (e.g. MAC address or TCP
+ * socket)
+ *
+ * @retval non-null The listener matching the query
+ * @retval null Does not exist
+ *
+ * Example:
+ * @code
+ *
+ * @endcode
+ */
+ListenerOps *listenerSet_Find(const ListenerSet *set, EncapType encapType,
+                              const Address *localAddress);
+#endif
diff --git a/hicn-light/src/io/streamConnection.c b/hicn-light/src/io/streamConnection.c
new file mode 100755 (executable)
index 0000000..fedbb15
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Common activity for STREAM based listeners.
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/io/streamConnection.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/messageHandler.h>
+
+#include <src/utils/commands.h>
+
+#include <hicn/hicn.h>
+// 128 KB output queue
+#define OUTPUT_QUEUE_BYTES (128 * 1024)
+
+static void _conn_readcb(PARCEventQueue *bufferEventVector, PARCEventType type,
+                         void *ioOpsVoid);
+
+static void _conn_eventcb(PARCEventQueue *bufferEventVector,
+                          PARCEventQueueEventType events, void *ioOpsVoid);
+
+typedef struct stream_state {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  int fd;
+
+  AddressPair *addressPair;
+  PARCEventQueue *bufferEventVector;
+
+  bool isLocal;
+  bool isUp;
+  bool isClosed;
+  unsigned id;
+
+  size_t nextMessageLength;
+} _StreamState;
+
+// Prototypes
+static bool _streamConnection_Send(IoOperations *ops, const Address *nexthop,
+                                   Message *message);
+static const Address *_streamConnection_GetRemoteAddress(
+    const IoOperations *ops);
+static const AddressPair *_streamConnection_GetAddressPair(
+    const IoOperations *ops);
+static unsigned _streamConnection_GetConnectionId(const IoOperations *ops);
+static bool _streamConnection_IsUp(const IoOperations *ops);
+static bool _streamConnection_IsLocal(const IoOperations *ops);
+static void _streamConnection_DestroyOperations(IoOperations **opsPtr);
+
+static void _setConnectionState(_StreamState *stream, bool isUp);
+static list_connections_type _streamConnection_GetConnectionType(
+    const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message);
+
+// REMINDER: when a new_command is added, the following array has to be updated
+// with the sizeof(new_command). It allows to allocate the buffer for receiving
+// the payload of the CONTROLLER REQUEST after the header has beed read. Each
+// command identifier (typedef enum command_id) corresponds to a position in the
+// following array.
+static int payloadLengthDaemon[LAST_COMMAND_VALUE] = {
+    sizeof(add_listener_command),
+    sizeof(add_connection_command),
+    0,  // list connections: payload always 0 when get controller request
+    sizeof(add_route_command),
+    0,  // list routes: payload always 0 when get controller request
+    sizeof(remove_connection_command),
+    sizeof(remove_route_command),
+    sizeof(cache_store_command),
+    sizeof(cache_serve_command),
+    0,  // cache clear
+    sizeof(set_strategy_command),
+    sizeof(set_wldr_command),
+    sizeof(add_punting_command),
+    0,  // list listeners: payload always 0 when get controller request
+    sizeof(mapme_activator_command),
+    sizeof(mapme_activator_command),
+    sizeof(mapme_timing_command),
+    sizeof(mapme_timing_command)};
+
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_ioOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+  return _ioOperationsGuid;
+}
+
+static IoOperations _template = {
+    .closure = NULL,
+    .send = &_streamConnection_Send,
+    .getRemoteAddress = &_streamConnection_GetRemoteAddress,
+    .getAddressPair = &_streamConnection_GetAddressPair,
+    .getConnectionId = &_streamConnection_GetConnectionId,
+    .isUp = &_streamConnection_IsUp,
+    .isLocal = &_streamConnection_IsLocal,
+    .destroy = &_streamConnection_DestroyOperations,
+    .class = &_streamConnection_Class,
+    .getConnectionType = &_streamConnection_GetConnectionType,
+    .sendProbe = &_sendProbe,
+};
+
+IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
+                                                AddressPair *pair,
+                                                bool isLocal) {
+  _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState));
+  parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_StreamState));
+
+  Dispatcher *dispatcher = forwarder_GetDispatcher(forwarder);
+  PARCEventScheduler *eventBase = dispatcher_GetEventScheduler(dispatcher);
+  stream->bufferEventVector = parcEventQueue_Create(
+      eventBase, fd,
+      PARCEventQueueOption_CloseOnFree | PARCEventQueueOption_DeferCallbacks);
+
+  stream->forwarder = forwarder;
+  stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  stream->fd = fd;
+  stream->id = forwarder_GetNextConnectionId(forwarder);
+  stream->addressPair = pair;
+  stream->isClosed = false;
+
+  // allocate a connection
+  IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+  parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(IoOperations));
+  memcpy(io_ops, &_template, sizeof(IoOperations));
+  io_ops->closure = stream;
+  stream->isLocal = isLocal;
+
+  parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL,
+                              _conn_eventcb, (void *)io_ops);
+  parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read);
+
+  messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                 missive_Create(MissiveType_ConnectionCreate, stream->id));
+
+  // As we are acceting a connection, we begin in the UP state
+  _setConnectionState(stream, true);
+
+  if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                        PARCLogLevel_Debug)) {
+    char *pair_str = addressPair_ToString(pair);
+    logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "StreamConnection %p accept for address pair %s", (void *)stream,
+               pair_str);
+    free(pair_str);
+  }
+
+  return io_ops;
+}
+
+IoOperations *streamConnection_OpenConnection(Forwarder *forwarder,
+                                              AddressPair *pair, bool isLocal) {
+  parcAssertNotNull(forwarder, "Parameter hicn-light must be non-null");
+  parcAssertNotNull(pair, "Parameter pair must be non-null");
+
+  // if there's an error on the bind or connect, will return NULL
+  PARCEventQueue *bufferEventVector =
+      dispatcher_StreamBufferConnect(forwarder_GetDispatcher(forwarder), pair);
+  if (bufferEventVector == NULL) {
+    // error opening connection
+    return NULL;
+  }
+
+  _StreamState *stream = parcMemory_AllocateAndClear(sizeof(_StreamState));
+  parcAssertNotNull(stream, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_StreamState));
+
+  stream->forwarder = forwarder;
+  stream->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  stream->fd = parcEventQueue_GetFileDescriptor(bufferEventVector);
+  stream->bufferEventVector = bufferEventVector;
+  stream->id = forwarder_GetNextConnectionId(forwarder);
+  stream->addressPair = pair;
+  stream->isClosed = false;
+
+  // allocate a connection
+  IoOperations *io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+  parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(IoOperations));
+  memcpy(io_ops, &_template, sizeof(IoOperations));
+  io_ops->closure = stream;
+  stream->isLocal = isLocal;
+
+  parcEventQueue_SetCallbacks(stream->bufferEventVector, _conn_readcb, NULL,
+                              _conn_eventcb, (void *)io_ops);
+  parcEventQueue_Enable(stream->bufferEventVector, PARCEventType_Read);
+
+  // we start in DOWN state, until remote side answers
+  messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                 missive_Create(MissiveType_ConnectionCreate, stream->id));
+  _setConnectionState(stream, false);
+
+  if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) {
+    char *pair_str = addressPair_ToString(pair);
+    logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+               "StreamConnection %p connect for address pair %s",
+               (void *)stream, pair_str);
+    free(pair_str);
+  }
+
+  return io_ops;
+}
+
+static void _streamConnection_DestroyOperations(IoOperations **opsPtr) {
+  parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+  parcAssertNotNull(*opsPtr,
+                    "Parameter opsPtr must dereference to non-null pointer");
+
+  IoOperations *ops = *opsPtr;
+  parcAssertNotNull(ioOperations_GetClosure(ops),
+                    "ops->context must not be null");
+
+  _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+  parcEventQueue_Destroy(&stream->bufferEventVector);
+
+  addressPair_Release(&stream->addressPair);
+
+  if (!stream->isClosed) {
+    stream->isClosed = true;
+    messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                   missive_Create(MissiveType_ConnectionClosed, stream->id));
+  }
+
+  messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                 missive_Create(MissiveType_ConnectionDestroyed, stream->id));
+
+  if (logger_IsLoggable(stream->logger, LoggerFacility_IO, PARCLogLevel_Info)) {
+    logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+               "StreamConnection %p destroyed", (void *)stream);
+  }
+
+  logger_Release(&stream->logger);
+  parcMemory_Deallocate((void **)&stream);
+  parcMemory_Deallocate((void **)&ops);
+
+  *opsPtr = NULL;
+}
+
+static bool _streamConnection_IsUp(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _StreamState *stream =
+      (const _StreamState *)ioOperations_GetClosure(ops);
+  return stream->isUp;
+}
+
+static bool _streamConnection_IsLocal(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _StreamState *stream =
+      (const _StreamState *)ioOperations_GetClosure(ops);
+  return stream->isLocal;
+}
+
+static const Address *_streamConnection_GetRemoteAddress(
+    const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _StreamState *stream =
+      (const _StreamState *)ioOperations_GetClosure(ops);
+  return addressPair_GetRemote(stream->addressPair);
+}
+
+static const AddressPair *_streamConnection_GetAddressPair(
+    const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _StreamState *stream =
+      (const _StreamState *)ioOperations_GetClosure(ops);
+  return stream->addressPair;
+}
+
+static unsigned _streamConnection_GetConnectionId(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _StreamState *stream =
+      (const _StreamState *)ioOperations_GetClosure(ops);
+  return stream->id;
+}
+
+bool streamState_SendCommandResponse(IoOperations *ops,
+                                     struct iovec *response) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  parcAssertNotNull(response, "Parameter message must be non-null");
+  _StreamState *conn = (_StreamState *)ioOperations_GetClosure(ops);
+
+  bool success = false;
+  if (conn->isUp) {
+    PARCEventBuffer *buffer =
+        parcEventBuffer_GetQueueBufferOutput(conn->bufferEventVector);
+    size_t buffer_backlog = parcEventBuffer_GetLength(buffer);
+    parcEventBuffer_Destroy(&buffer);
+
+    if (buffer_backlog < OUTPUT_QUEUE_BYTES) {
+      if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+                            PARCLogLevel_Debug)) {
+        logger_Log(
+            conn->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+            "connid %u Writing %zu bytes to buffer with backlog %zu bytes",
+            conn->id,
+            (response[0].iov_len +
+             response[1].iov_len),  // NEW: take total lenght
+            buffer_backlog);
+      }
+
+      // NEW: write directly ino the parcEventQueue without passing through
+      // message
+      int failure =
+          parcEventQueue_Write(conn->bufferEventVector, response[0].iov_base,
+                               response[0].iov_len) +
+          parcEventQueue_Write(conn->bufferEventVector, response[1].iov_base,
+                               response[1].iov_len);
+
+      if (failure == 0) {
+        success = true;
+      }
+    } else {
+      if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+                            PARCLogLevel_Warning)) {
+        logger_Log(conn->logger, LoggerFacility_IO, PARCLogLevel_Warning,
+                   __func__,
+                   "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE",
+                   conn->id, buffer_backlog);
+      }
+    }
+  } else {
+    if (logger_IsLoggable(conn->logger, LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      logger_Log(
+          conn->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+          "connid %u tried to send to down connection (isUp %d isClosed %d)",
+          conn->id, conn->isUp, conn->isClosed);
+    }
+  }
+
+  return success;
+}
+
+/**
+ * @function streamConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ *   Send uses message_CopyToStreamBuffer, which is a non-destructive write.
+ *   The send may fail if there's no buffer space in the output queue.
+ *
+ * @param dummy is ignored.  A stream has only one peer.
+ * @return <#return#>
+ */
+static bool _streamConnection_Send(IoOperations *ops, const Address *dummy,
+                                   Message *message) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+  bool success = false;
+  if (stream->isUp) {
+    PARCEventBuffer *buffer =
+        parcEventBuffer_GetQueueBufferOutput(stream->bufferEventVector);
+    size_t buffer_backlog = parcEventBuffer_GetLength(buffer);
+    parcEventBuffer_Destroy(&buffer);
+
+    if (buffer_backlog < OUTPUT_QUEUE_BYTES) {
+      if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                            PARCLogLevel_Debug)) {
+        logger_Log(
+            stream->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+            "connid %u Writing %zu bytes to buffer with backlog %zu bytes",
+            stream->id, message_Length(message), buffer_backlog);
+      }
+
+      int failure = message_Write(stream->bufferEventVector, message);
+      if (failure == 0) {
+        success = true;
+      }
+    } else {
+      if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                            PARCLogLevel_Warning)) {
+        logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Warning,
+                   __func__,
+                   "connid %u Writing to buffer backlog %zu bytes DROP MESSAGE",
+                   stream->id, buffer_backlog);
+      }
+    }
+  } else {
+    if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      logger_Log(
+          stream->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+          "connid %u tried to send to down connection (isUp %d isClosed %d)",
+          stream->id, stream->isUp, stream->isClosed);
+    }
+  }
+
+  return success;
+}
+
+list_connections_type _streamConnection_GetConnectionType(
+    const IoOperations *ops) {
+  return CONN_TCP;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message) {
+  // we don't need to implemet this here, it is a local connection
+  return 0;
+}
+
+// =================================================================
+// the actual I/O functions
+
+int _isACommand(PARCEventBuffer *input) {
+  size_t bytesAvailable = parcEventBuffer_GetLength(input);
+  parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+                 "Called with too short an input: %zu", bytesAvailable);
+
+  uint8_t *msg = parcEventBuffer_Pullup(input, bytesAvailable);
+  // read first byte of the header
+
+  // first byte: must be a REQUEST_LIGHT
+  if (msg[0] != 100) {
+    return LAST_COMMAND_VALUE;
+  }
+
+  // second byte: must be a command_id
+  if (msg[1] < 0 || msg[1] >= LAST_COMMAND_VALUE) {
+    return LAST_COMMAND_VALUE;
+  }
+
+  return msg[1];
+}
+
+PARCEventBuffer *_tryReadControlMessage(_StreamState *stream,
+                                        PARCEventBuffer *input,
+                                        command_id command,
+                                        struct iovec **request) {
+  size_t bytesAvailable = parcEventBuffer_GetLength(input);
+
+  if (stream->nextMessageLength == 0) {
+    stream->nextMessageLength =
+        sizeof(header_control_message) +
+        payloadLengthDaemon[command];  // consider the whole packet.
+  }
+
+  if (bytesAvailable >= stream->nextMessageLength) {
+    PARCEventBuffer *message = parcEventBuffer_Create();
+    int bytesRead = parcEventBuffer_ReadIntoBuffer(input, message,
+                                                   stream->nextMessageLength);
+    parcAssertTrue(bytesRead == stream->nextMessageLength,
+                   "Partial read, expected %zu got %d",
+                   stream->nextMessageLength, bytesRead);
+
+    uint8_t *control =
+        parcEventBuffer_Pullup(message, stream->nextMessageLength);
+    if (!(*request = (struct iovec *)parcMemory_AllocateAndClear(
+              sizeof(struct iovec) * 2))) {
+      return NULL;
+    }
+    (*request)[0].iov_base = control;  // header
+    (*request)[0].iov_len = sizeof(header_control_message);
+    if (payloadLengthDaemon[command] > 0) {
+      (*request)[1].iov_base =
+          control + sizeof(header_control_message);  // payload
+    } else {
+      (*request)[1].iov_base = NULL;
+    }
+    (*request)[1].iov_len = payloadLengthDaemon[command];
+    // now reset message length for next packet
+
+    stream->nextMessageLength = 0;
+
+    return message;
+  }
+
+  return NULL;
+}
+
+static bool _isAnHIcnPacket(PARCEventBuffer *input) {
+  size_t bytesAvailable = parcEventBuffer_GetLength(input);
+  parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+                 "Called with too short an input: %zu", bytesAvailable);
+
+  uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message));
+  return messageHandler_IsValidHIcnPacket(fh);
+}
+
+static Message *_readMessage(_StreamState *stream, Ticks time,
+                             PARCEventBuffer *input) {
+  Message *message = message_CreateFromEventBuffer(
+      input, stream->nextMessageLength, stream->id, time, stream->logger);
+
+  return message;
+}
+
+static void _startNewMessage(_StreamState *stream, PARCEventBuffer *input,
+                             size_t inputBytesAvailable) {
+  parcAssertTrue(stream->nextMessageLength == 0,
+                 "Invalid state, nextMessageLength not zero: %zu",
+                 stream->nextMessageLength);
+  parcAssertTrue(inputBytesAvailable >= sizeof(header_control_message),
+                 "read_length not a whole fixed header!: %zd",
+                 inputBytesAvailable);
+
+  // this linearizes the first messageHandler_GetIPv6HeaderLength() bytes of the
+  // input buffer's iovecs and returns a pointer to it.
+  uint8_t *fh = parcEventBuffer_Pullup(input, sizeof(header_control_message));
+
+  // Calculate the total message size based on the fixed header
+  stream->nextMessageLength = messageHandler_GetTotalPacketLength(fh);
+}
+
+static Message *_tryReadMessage(PARCEventBuffer *input, _StreamState *stream) {
+  size_t bytesAvailable = parcEventBuffer_GetLength(input);
+  parcAssertTrue(bytesAvailable >= sizeof(header_control_message),
+                 "Called with too short an input: %zu", bytesAvailable);
+
+  if (stream->nextMessageLength == 0) {
+    _startNewMessage(stream, input, bytesAvailable);
+  }
+
+  // This is not an ELSE statement.  We can both start a new message then
+  // check if there's enough bytes to read the whole thing.
+
+  if (bytesAvailable >= stream->nextMessageLength) {
+    Message *message =
+        _readMessage(stream, forwarder_GetTicks(stream->forwarder), input);
+
+    // now reset message length for next packet
+    stream->nextMessageLength = 0;
+
+    return message;
+  }
+
+  return NULL;
+}
+
+/**
+ * @function conn_readcb
+ * @abstract Event callback for reads
+ * @discussion
+ *   Will read messages off the input.  Continues reading as long as we
+ *   can get a header to determine the next message length or as long as we
+ *   can read a complete message.
+ *
+ *   This function manipulates the read low water mark.  (1) read a fixed header
+ * plus complete message, then set the low water mark to FIXED_HEADER_LEN.  (2)
+ * read a fixed header, but not a complete message, then set low water mark to
+ * the total mesage length.  Using the low water mark like this means the buffer
+ * event will only trigger on meaningful byte boundaries when we can get actual
+ *   work done.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static void _conn_readcb(PARCEventQueue *event, PARCEventType type,
+                         void *ioOpsVoid) {
+  command_id command;
+  IoOperations *ops = (IoOperations *)ioOpsVoid;
+  _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+  PARCEventBuffer *input = parcEventBuffer_GetQueueBufferInput(event);
+
+  // drain the input buffer
+
+  // notice that we always try to read at least 8 bytes
+  // (sizeof(header_control_message)). This is enough to read the length of all
+  // kind of packets
+  while (parcEventBuffer_GetLength(input) >= sizeof(header_control_message) &&
+         parcEventBuffer_GetLength(input) >= stream->nextMessageLength) {
+    if ((command = _isACommand(input)) != LAST_COMMAND_VALUE) {
+      struct iovec *rx;
+      // Get message from the stream and set the stream->nextMessageLength
+      PARCEventBuffer *message =
+          _tryReadControlMessage(stream, input, command, &rx);
+      // If received correctly the whole message, send to dispatcher
+      if (message) {
+        forwarder_ReceiveCommand(stream->forwarder, command, rx, stream->id);
+        parcEventBuffer_Destroy(&message);
+      }
+
+    } else if (_isAnHIcnPacket(input)) {
+      // this is an HIcn packet (here we should distinguish between IPv4 and
+      // IPv6 tryReadMessage may set nextMessageLength
+      Message *message = _tryReadMessage(input, stream);
+
+      if (message) {
+        forwarder_Receive(stream->forwarder, message);
+      }
+
+    } else {
+      parcAssertTrue(false,
+                     "(Local stream connection) malformend packet received");
+    }
+  }
+
+  if (stream->nextMessageLength == 0) {
+    // we don't have the next header, so set it to the header length
+    streamBuffer_SetWatermark(event, true, false,
+                              sizeof(header_control_message), 0);
+  } else {
+    // set it to the packet length
+    streamBuffer_SetWatermark(event, true, false, stream->nextMessageLength, 0);
+  }
+  parcEventBuffer_Destroy(&input);
+}
+
+static void _setConnectionState(_StreamState *stream, bool isUp) {
+  parcAssertNotNull(stream, "Parameter stream must be non-null");
+
+  Messenger *messenger = forwarder_GetMessenger(stream->forwarder);
+
+  bool oldStateIsUp = stream->isUp;
+  stream->isUp = isUp;
+
+  if (oldStateIsUp && !isUp) {
+    // bring connection DOWN
+    Missive *missive = missive_Create(MissiveType_ConnectionDown, stream->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+
+  if (!oldStateIsUp && isUp) {
+    // bring connection UP
+    Missive *missive = missive_Create(MissiveType_ConnectionUp, stream->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+}
+
+static void _conn_eventcb(PARCEventQueue *event, PARCEventQueueEventType events,
+                          void *ioOpsVoid) {
+  IoOperations *ops = (IoOperations *)ioOpsVoid;
+  _StreamState *stream = (_StreamState *)ioOperations_GetClosure(ops);
+
+  if (events & PARCEventQueueEventType_Connected) {
+    if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                          PARCLogLevel_Info)) {
+      logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+                 "Connection %u is connected", stream->id);
+    }
+
+    // if the stream was closed, do not transition to an UP state
+    if (!stream->isClosed) {
+      _setConnectionState(stream, true);
+    }
+  } else if (events & PARCEventQueueEventType_EOF) {
+    if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                          PARCLogLevel_Info)) {
+      logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Info, __func__,
+                 "connid %u closed.", stream->id);
+    }
+
+    parcEventQueue_Disable(stream->bufferEventVector, PARCEventType_Read);
+
+    _setConnectionState(stream, false);
+
+    if (!stream->isClosed) {
+      stream->isClosed = true;
+      // this will cause the connection manager to destroy the connection later
+      messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                     missive_Create(MissiveType_ConnectionClosed, stream->id));
+    }
+  } else if (events & PARCEventQueueEventType_Error) {
+    if (logger_IsLoggable(stream->logger, LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      logger_Log(stream->logger, LoggerFacility_IO, PARCLogLevel_Error,
+                 __func__, "Got an error on the connection %u: %s", stream->id,
+                 strerror(errno));
+    }
+
+    parcEventQueue_Disable(stream->bufferEventVector,
+                           PARCEventType_Read | PARCEventType_Write);
+
+    _setConnectionState(stream, false);
+
+    if (!stream->isClosed) {
+      stream->isClosed = true;
+      // this will cause the connection manager to destroy the connection later
+      messenger_Send(forwarder_GetMessenger(stream->forwarder),
+                     missive_Create(MissiveType_ConnectionClosed, stream->id));
+    }
+  }
+  /* None of the other events can happen here, since we haven't enabled
+   * timeouts */
+}
diff --git a/hicn-light/src/io/streamConnection.h b/hicn-light/src/io/streamConnection.h
new file mode 100755 (executable)
index 0000000..8eb63a0
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Methods common to TCP and PF_LOCAL stream-based listeners
+ */
+
+#ifndef streamConnection_h
+#define streamConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * @function streamConnection_AcceptConnection
+ * @abstract Receive a connection from a remote peer
+ * @discussion
+ *   We are the "server side" of the stream connection, so we need to accept the
+ * client connection and setup state for her.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+IoOperations *streamConnection_AcceptConnection(Forwarder *forwarder, int fd,
+                                                AddressPair *pair,
+                                                bool isLocal);
+
+/**
+ * @function streamConnection_OpenConnection
+ * @abstract Initiate a connection to a remote peer
+ * @discussion
+ *   We are the "client side" of the stream connection.  We'll create state for
+ * the peer, but it will be in the "down" state until the connection
+ * establishes.
+ *
+ *   For TCP, both address pairs need to be the same address family: both INET
+ * or both INET6.  The remote address must have the complete socket information
+ * (address, port).  The local socket could be wildcarded or may specify down to
+ * the (address, port) pair.
+ *
+ *   If the local address is IPADDR_ANY and the port is 0, then it is a normal
+ * call to "connect" that will use whatever local IP address and whatever local
+ * port for the connection.  If either the address or port is set, the local
+ * socket will first be bound (via bind(2)), and then call connect().
+ *
+ *   AF_UNIX is not yet supported
+ *
+ *   If there's an error binding to the specified address or connecting to the
+ * remote address, will return NULL.
+ *
+ * @param pair (takes ownership of this) is the complete socket pair of
+ * (address, port) for each end, if INET or INET6.
+ * @return NULL on error, otherwise the connections IO operations.
+ */
+IoOperations *streamConnection_OpenConnection(Forwarder *forwarder,
+                                              AddressPair *pair, bool isLocal);
+
+bool streamState_SendCommandResponse(IoOperations *ops, struct iovec *response);
+
+#endif  // streamConnection_h
diff --git a/hicn-light/src/io/tcpListener.c b/hicn-light/src/io/tcpListener.c
new file mode 100755 (executable)
index 0000000..6f0477f
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/connectionTable.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <src/io/streamConnection.h>
+#include <src/io/tcpListener.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+
+typedef struct tcp_listener {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  PARCEventSocket *listener;
+
+  Address *localAddress;
+
+  unsigned id;
+
+  // is the localAddress as 127.0.0.0 address?
+  bool isLocalAddressLocal;
+} _TcpListener;
+
+static void _tcpListener_Destroy(_TcpListener **listenerPtr);
+
+static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr);
+static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops);
+static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops);
+static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops);
+
+static ListenerOps _tcpTemplate = {
+    .context = NULL,
+    .destroy = &_tcpListener_OpsDestroy,
+    .getInterfaceIndex = &_tcpListener_OpsGetInterfaceIndex,
+    .getListenAddress = &_tcpListener_OpsGetListenAddress,
+    .getEncapType = &_tcpListener_OpsGetEncapType,
+    .getSocket = NULL};
+
+// STREAM daemon listener callback
+static void _tcpListener_Listen(int, struct sockaddr *, int socklen,
+                                void *tcpVoid);
+
+ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
+                                     struct sockaddr_in6 sin6) {
+  _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
+  parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_TcpListener));
+
+  tcp->forwarder = forwarder;
+  tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  tcp->listener = dispatcher_CreateListener(
+      forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
+      (struct sockaddr *)&sin6, sizeof(sin6));
+
+  if (tcp->listener == NULL) {
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+               "dispatcher_CreateListener failed to create listener (%d) %s",
+               errno, strerror(errno));
+    logger_Release(&tcp->logger);
+    parcMemory_Deallocate((void **)&tcp);
+    return NULL;
+  }
+
+  tcp->localAddress = addressCreateFromInet6(&sin6);
+  tcp->id = forwarder_GetNextConnectionId(forwarder);
+  tcp->isLocalAddressLocal =
+      parcNetwork_IsSocketLocal((struct sockaddr *)&sin6);
+
+  ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+  parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListenerOps));
+
+  memcpy(ops, &_tcpTemplate, sizeof(ListenerOps));
+  ops->context = tcp;
+
+  if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    char *str = addressToString(tcp->localAddress);
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "TcpListener %p created for address %s (isLocal %d)",
+               (void *)tcp, str, tcp->isLocalAddressLocal);
+    parcMemory_Deallocate((void **)&str);
+  }
+
+  return ops;
+}
+
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
+                                    struct sockaddr_in sin) {
+  _TcpListener *tcp = parcMemory_AllocateAndClear(sizeof(_TcpListener));
+  parcAssertNotNull(tcp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_TcpListener));
+
+  tcp->forwarder = forwarder;
+  tcp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  tcp->listener = dispatcher_CreateListener(
+      forwarder_GetDispatcher(forwarder), _tcpListener_Listen, (void *)tcp, -1,
+      (struct sockaddr *)&sin, sizeof(sin));
+
+  if (tcp->listener == NULL) {
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+               "dispatcher_CreateListener failed to create listener (%d) %s",
+               errno, strerror(errno));
+
+    logger_Release(&tcp->logger);
+    parcMemory_Deallocate((void **)&tcp);
+    return NULL;
+  }
+
+  tcp->localAddress = addressCreateFromInet(&sin);
+  tcp->id = forwarder_GetNextConnectionId(forwarder);
+  tcp->isLocalAddressLocal = parcNetwork_IsSocketLocal((struct sockaddr *)&sin);
+
+  ListenerOps *ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+  parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(ListenerOps));
+
+  memcpy(ops, &_tcpTemplate, sizeof(ListenerOps));
+  ops->context = tcp;
+
+  if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    char *str = addressToString(tcp->localAddress);
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "TcpListener %p created for address %s (isLocal %d)",
+               (void *)tcp, str, tcp->isLocalAddressLocal);
+    parcMemory_Deallocate((void **)&str);
+  }
+
+  return ops;
+}
+
+static void _tcpListener_Destroy(_TcpListener **listenerPtr) {
+  parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listenerPtr,
+                    "Parameter must derefernce to non-null pointer");
+  _TcpListener *tcp = *listenerPtr;
+
+  if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    char *str = addressToString(tcp->localAddress);
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "TcpListener %p destroyed", (void *)tcp);
+    parcMemory_Deallocate((void **)&str);
+  }
+
+  logger_Release(&tcp->logger);
+  dispatcher_DestroyListener(forwarder_GetDispatcher(tcp->forwarder),
+                             &tcp->listener);
+  addressDestroy(&tcp->localAddress);
+  parcMemory_Deallocate((void **)&tcp);
+  *listenerPtr = NULL;
+}
+
+// ==================================================
+
+static void _tcpListener_Listen(int fd, struct sockaddr *sa, int socklen,
+                                void *tcpVoid) {
+  _TcpListener *tcp = (_TcpListener *)tcpVoid;
+
+  Address *remote;
+
+  switch (sa->sa_family) {
+    case AF_INET:
+      remote = addressCreateFromInet((struct sockaddr_in *)sa);
+      break;
+
+    case AF_INET6:
+      remote = addressCreateFromInet6((struct sockaddr_in6 *)sa);
+      break;
+
+    default:
+      parcTrapIllegalValue(sa, "Expected INET or INET6, got %d", sa->sa_family);
+      abort();
+  }
+
+  AddressPair *pair = addressPair_Create(tcp->localAddress, remote);
+
+  IoOperations *ops = streamConnection_AcceptConnection(
+      tcp->forwarder, fd, pair, tcp->isLocalAddressLocal);
+  Connection *conn = connection_Create(ops);
+
+  connectionTable_Add(forwarder_GetConnectionTable(tcp->forwarder), conn);
+
+  if (logger_IsLoggable(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    logger_Log(tcp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "TcpListener %p listen started", (void *)tcp);
+  }
+
+  addressDestroy(&remote);
+}
+
+static void _tcpListener_OpsDestroy(ListenerOps **listenerOpsPtr) {
+  ListenerOps *ops = *listenerOpsPtr;
+  _TcpListener *tcp = (_TcpListener *)ops->context;
+  _tcpListener_Destroy(&tcp);
+  parcMemory_Deallocate((void **)&ops);
+  *listenerOpsPtr = NULL;
+}
+
+static unsigned _tcpListener_OpsGetInterfaceIndex(const ListenerOps *ops) {
+  _TcpListener *tcp = (_TcpListener *)ops->context;
+  return tcp->id;
+}
+
+static const Address *_tcpListener_OpsGetListenAddress(const ListenerOps *ops) {
+  _TcpListener *tcp = (_TcpListener *)ops->context;
+  return tcp->localAddress;
+}
+
+static EncapType _tcpListener_OpsGetEncapType(const ListenerOps *ops) {
+  return ENCAP_TCP;
+}
diff --git a/hicn-light/src/io/tcpListener.h b/hicn-light/src/io/tcpListener.h
new file mode 100755 (executable)
index 0000000..c5d1e33
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file tcpListener.h
+ * @brief Listens for in coming TCP connections
+ *
+ * This is the "server socket" of hicn-light for TCP connections.  The actual
+ * I/O is handled by {@link StreamConnection}.
+ *
+ */
+
+#ifndef tcpListener_h
+#define tcpListener_h
+
+#include <netinet/in.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+ListenerOps *tcpListener_CreateInet6(Forwarder *forwarder,
+                                     struct sockaddr_in6 sin6);
+ListenerOps *tcpListener_CreateInet(Forwarder *forwarder,
+                                    struct sockaddr_in sin);
+#endif  // tcpListener_h
diff --git a/hicn-light/src/io/tcpTunnel.c b/hicn-light/src/io/tcpTunnel.c
new file mode 100755 (executable)
index 0000000..a2bf2bd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/streamConnection.h>
+#include <src/io/tcpListener.h>
+#include <src/io/tcpTunnel.h>
+
+IoOperations *tcpTunnel_Create(Forwarder *forwarder,
+                               const Address *localAddress,
+                               const Address *remoteAddress) {
+  IoOperations *ops = NULL;
+
+  address_type localType = addressGetType(localAddress);
+  address_type remoteType = addressGetType(remoteAddress);
+
+  if (localType == remoteType) {
+    AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+    bool isLocal = false;
+
+    ops = streamConnection_OpenConnection(forwarder, pair, isLocal);
+  }
+
+  return ops;
+}
diff --git a/hicn-light/src/io/tcpTunnel.h b/hicn-light/src/io/tcpTunnel.h
new file mode 100755 (executable)
index 0000000..4daa7d0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file tcpTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ */
+
+#ifndef tcpTunnel_h
+#define tcpTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ */
+// IoOperations *tcpTunnel_CreateOnListener(Forwarder *forwarder,
+//                                            ListenerOps *localListener,
+//                                            const Address *remoteAddress);
+
+/**
+ */
+IoOperations *tcpTunnel_Create(Forwarder *forwarder,
+                               const Address *localAddress,
+                               const Address *remoteAddress);
+
+#endif  // tcpTunnel_h
diff --git a/hicn-light/src/io/udpConnection.c b/hicn-light/src/io/udpConnection.c
new file mode 100755 (executable)
index 0000000..2aa6edc
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Embodies the reader/writer for a UDP connection
+ *
+ * NB The Send() function may overflow the output buffer
+ *
+ */
+
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <src/core/messageHandler.h>
+#include <src/io/udpConnection.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+
+typedef struct udp_state {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  // the udp listener socket we receive packets on
+  int udpListenerSocket;
+
+  AddressPair *addressPair;
+
+  // We need to access this all the time, so grab it out
+  // of the addressPair;
+  struct sockaddr *peerAddress;
+  socklen_t peerAddressLength;
+
+  bool isLocal;
+  bool isUp;
+  unsigned id;
+
+  unsigned delay;
+} _UdpState;
+
+// Prototypes
+static bool _send(IoOperations *ops, const Address *nexthop, Message *message);
+static const Address *_getRemoteAddress(const IoOperations *ops);
+static const AddressPair *_getAddressPair(const IoOperations *ops);
+static unsigned _getConnectionId(const IoOperations *ops);
+static bool _isUp(const IoOperations *ops);
+static bool _isLocal(const IoOperations *ops);
+static void _destroy(IoOperations **opsPtr);
+static list_connections_type _getConnectionType(const IoOperations *ops);
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message);
+/*
+ * This assigns a unique pointer to the void * which we use
+ * as a GUID for this class.
+ */
+static const void *_IoOperationsGuid = __FILE__;
+
+/*
+ * Return our GUID
+ */
+static const void *_streamConnection_Class(const IoOperations *ops) {
+  return _IoOperationsGuid;
+}
+
+static IoOperations _template = {.closure = NULL,
+                                 .send = &_send,
+                                 .getRemoteAddress = &_getRemoteAddress,
+                                 .getAddressPair = &_getAddressPair,
+                                 .getConnectionId = &_getConnectionId,
+                                 .isUp = &_isUp,
+                                 .isLocal = &_isLocal,
+                                 .destroy = &_destroy,
+                                 .class = &_streamConnection_Class,
+                                 .getConnectionType = &_getConnectionType,
+                                 .sendProbe = &_sendProbe};
+
+// =================================================================
+
+static void _setConnectionState(_UdpState *Udp, bool isUp);
+static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair);
+
+IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+                                   const AddressPair *pair, bool isLocal) {
+  IoOperations *io_ops = NULL;
+
+  _UdpState *udpConnState = parcMemory_AllocateAndClear(sizeof(_UdpState));
+  parcAssertNotNull(udpConnState,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(_UdpState));
+
+  udpConnState->forwarder = forwarder;
+  udpConnState->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  bool saved = _saveSockaddr(udpConnState, pair);
+  if (saved) {
+    udpConnState->udpListenerSocket = fd;
+    udpConnState->id = forwarder_GetNextConnectionId(forwarder);
+    udpConnState->addressPair = addressPair_Acquire(pair);
+    udpConnState->isLocal = isLocal;
+
+    // allocate a connection
+    io_ops = parcMemory_AllocateAndClear(sizeof(IoOperations));
+    parcAssertNotNull(io_ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(IoOperations));
+    memcpy(io_ops, &_template, sizeof(IoOperations));
+    io_ops->closure = udpConnState;
+
+    _setConnectionState(udpConnState, true);
+
+    if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+                          PARCLogLevel_Info)) {
+      char *str = addressPair_ToString(udpConnState->addressPair);
+      logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+                 __func__,
+                 "UdpConnection %p created for address %s (isLocal %d)",
+                 (void *)udpConnState, str, udpConnState->isLocal);
+      free(str);
+    }
+
+    messenger_Send(
+        forwarder_GetMessenger(forwarder),
+        missive_Create(MissiveType_ConnectionCreate, udpConnState->id));
+    messenger_Send(forwarder_GetMessenger(forwarder),
+                   missive_Create(MissiveType_ConnectionUp, udpConnState->id));
+  } else {
+    // _saveSockaddr will already log an error, no need for extra log message
+    // here
+    logger_Release(&udpConnState->logger);
+    parcMemory_Deallocate((void **)&udpConnState);
+  }
+
+  return io_ops;
+}
+
+// =================================================================
+// I/O Operations implementation
+
+static void _destroy(IoOperations **opsPtr) {
+  parcAssertNotNull(opsPtr, "Parameter opsPtr must be non-null double pointer");
+  parcAssertNotNull(*opsPtr,
+                    "Parameter opsPtr must dereference to non-null pointer");
+
+  IoOperations *ops = *opsPtr;
+  parcAssertNotNull(ioOperations_GetClosure(ops),
+                    "ops->context must not be null");
+
+  _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops);
+  addressPair_Release(&udpConnState->addressPair);
+  parcMemory_Deallocate((void **)&(udpConnState->peerAddress));
+
+  messenger_Send(
+      forwarder_GetMessenger(udpConnState->forwarder),
+      missive_Create(MissiveType_ConnectionDestroyed, udpConnState->id));
+
+  if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+                        PARCLogLevel_Info)) {
+    logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Info,
+               __func__, "UdpConnection %p destroyed", (void *)udpConnState);
+  }
+
+  // do not close udp->udpListenerSocket, the listener will close
+  // that when its done
+
+  logger_Release(&udpConnState->logger);
+  parcMemory_Deallocate((void **)&udpConnState);
+  parcMemory_Deallocate((void **)&ops);
+
+  *opsPtr = NULL;
+}
+
+static bool _isUp(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _UdpState *udpConnState =
+      (const _UdpState *)ioOperations_GetClosure(ops);
+  return udpConnState->isUp;
+}
+
+static bool _isLocal(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _UdpState *udpConnState =
+      (const _UdpState *)ioOperations_GetClosure(ops);
+  return udpConnState->isLocal;
+}
+
+static const Address *_getRemoteAddress(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _UdpState *udpConnState =
+      (const _UdpState *)ioOperations_GetClosure(ops);
+  return addressPair_GetRemote(udpConnState->addressPair);
+}
+
+static const AddressPair *_getAddressPair(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _UdpState *udpConnState =
+      (const _UdpState *)ioOperations_GetClosure(ops);
+  return udpConnState->addressPair;
+}
+
+static unsigned _getConnectionId(const IoOperations *ops) {
+  parcAssertNotNull(ops, "Parameter must be non-null");
+  const _UdpState *udpConnState =
+      (const _UdpState *)ioOperations_GetClosure(ops);
+  return udpConnState->id;
+}
+
+/**
+ * @function metisUdpConnection_Send
+ * @abstract Non-destructive send of the message.
+ * @discussion
+ *   sends a message to the peer.
+ *
+ * @param dummy is ignored.  A udp connection has only one peer.
+ * @return <#return#>
+ */
+static bool _send(IoOperations *ops, const Address *dummy, Message *message) {
+  parcAssertNotNull(ops, "Parameter ops must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+  _UdpState *udpConnState = (_UdpState *)ioOperations_GetClosure(ops);
+
+  // NAT for HICN
+  // in this particular connection we don't need natting beacause we send the
+  // packet to the next hop using upd connection
+
+#if 0
+    if((hicnConnState->peerAddressLength == sizeof(struct sockaddr_in)) || (hicnConnState->localAddressLength == sizeof(struct sockaddr_in)))
+        return false;
+
+    if(message_GetType(message) = MessagePacketType_ContentObject){
+        //this is a data packet. We need to put the remote address in the destination field
+        messageHandler_SetDestination_IPv6((uint8_t *) message_FixedHeader(message),
+                                             &((struct sockaddr_in6 *) hicnConnState->peerAddress)->sin6_addr);
+
+    } else if (message_GetType(message) == MessagePacketType_Interest) {
+        //this si an interest packet. We need to put the local address in the source field
+        messageHandler_SetSource_IPv6((uint8_t *) message_FixedHeader(message),
+                                        &((struct sockaddr_in6 *) hicnConnState->localAddress)->sin6_addr);
+
+        //only in this case we may need to set the probeDestAddress
+        if(hicnConnState->refreshProbeDestAddress){
+            _refreshProbeDestAddress(hicnConnState, message_FixedHeader(message));
+        }
+
+    } else if (message_GetType(message) == MessagePacketType_WldrNotification) {
+        //here we don't need to do anything for now
+    }else{
+        //unkown packet
+        if (logger_IsLoggable(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+            logger_Log(hicnConnState->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                              "connid %u can't parse the message",
+                              hicnConnState->id);
+        }
+        return false;
+    }
+#endif
+
+  ssize_t writeLength =
+      sendto(udpConnState->udpListenerSocket, message_FixedHeader(message),
+             message_Length(message), 0, udpConnState->peerAddress,
+             udpConnState->peerAddressLength);
+
+  if (writeLength < 0) {
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+      return false;
+    } else {
+      // this print is for debugging
+      printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLength,
+             message_Length(message), errno, strerror(errno));
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static list_connections_type _getConnectionType(const IoOperations *ops) {
+  return CONN_UDP;
+}
+
+static Ticks _sendProbe(IoOperations *ops, unsigned probeType,
+                        uint8_t *message) {
+#if 0
+    parcAssertNotNull(ops, "Parameter ops must be non-null");
+    _MetisUdpState *udpConnState = (_MetisUdpState *) metisIoOperations_GetClosure(ops);
+
+
+    uint8_t *pkt;
+    size_t pkt_size = 8;
+    pkt = (uint8_t *) malloc(sizeof(uint8_t) * pkt_size);
+    for (unsigned i = 0; i < pkt_size; i++) {
+        pkt[i] = 0;
+    }
+    pkt[0] = 1;         //type
+    pkt[1] = probeType; //packet type
+    pkt[6] = 8;         //header len (16bit, network order)
+
+    ssize_t writeLen = sendto(udpConnState->udpListenerSocket, pkt, pkt_size, 0, udpConnState->peerAddress, udpConnState->peerAddressLength);
+
+    if (writeLen < 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            free(pkt);
+            return 0;
+        } else  {
+            //this print is for debugging
+            printf("Incorrect write length %zd, expected %zd: (%d) %s\n", writeLen, pkt_size, errno, strerror(errno));
+            free(pkt);
+            return 0;
+        }
+    }
+
+    free(pkt);
+    return metisForwarder_GetTicks(udpConnState->metis);
+#endif
+  return 0;
+}
+
+// =================================================================
+// Internal API
+
+static bool _saveSockaddr(_UdpState *udpConnState, const AddressPair *pair) {
+  bool success = false;
+  const Address *remoteAddress = addressPair_GetRemote(pair);
+
+  switch (addressGetType(remoteAddress)) {
+    case ADDR_INET: {
+      size_t bytes = sizeof(struct sockaddr_in);
+      udpConnState->peerAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(udpConnState->peerAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet(remoteAddress,
+                     (struct sockaddr_in *)udpConnState->peerAddress);
+      udpConnState->peerAddressLength = (socklen_t)bytes;
+
+      success = true;
+      break;
+    }
+
+    case ADDR_INET6: {
+      size_t bytes = sizeof(struct sockaddr_in6);
+      udpConnState->peerAddress = parcMemory_Allocate(bytes);
+      parcAssertNotNull(udpConnState->peerAddress,
+                        "parcMemory_Allocate(%zu) returned NULL", bytes);
+
+      addressGetInet6(remoteAddress,
+                      (struct sockaddr_in6 *)udpConnState->peerAddress);
+      udpConnState->peerAddressLength = (socklen_t)bytes;
+
+      success = true;
+      break;
+    }
+
+    default:
+      if (logger_IsLoggable(udpConnState->logger, LoggerFacility_IO,
+                            PARCLogLevel_Error)) {
+        char *str = addressToString(remoteAddress);
+        logger_Log(udpConnState->logger, LoggerFacility_IO, PARCLogLevel_Error,
+                   __func__, "Remote address is not INET or INET6: %s", str);
+        parcMemory_Deallocate((void **)&str);
+      }
+      break;
+  }
+  return success;
+}
+
+static void _setConnectionState(_UdpState *udpConnState, bool isUp) {
+  parcAssertNotNull(udpConnState, "Parameter Udp must be non-null");
+
+  Messenger *messenger = forwarder_GetMessenger(udpConnState->forwarder);
+
+  bool oldStateIsUp = udpConnState->isUp;
+  udpConnState->isUp = isUp;
+
+  if (oldStateIsUp && !isUp) {
+    // bring connection DOWN
+    Missive *missive =
+        missive_Create(MissiveType_ConnectionDown, udpConnState->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+
+  if (!oldStateIsUp && isUp) {
+    // bring connection UP
+    Missive *missive =
+        missive_Create(MissiveType_ConnectionUp, udpConnState->id);
+    messenger_Send(messenger, missive);
+    return;
+  }
+}
diff --git a/hicn-light/src/io/udpConnection.h b/hicn-light/src/io/udpConnection.h
new file mode 100755 (executable)
index 0000000..122f332
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file udpConnection.h
+ * @brief Represents a UDP connection (socket) for the connection table
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef udpConnection_h
+#define udpConnection_h
+
+#include <src/core/forwarder.h>
+#include <src/io/addressPair.h>
+#include <src/io/ioOperations.h>
+#include <src/utils/address.h>
+
+/**
+ * Creates a UDP connection that can send to the remote address
+ *
+ * The address pair must both be same type (i.e. INET or INET6).
+ *
+ * @param [in] metis An allocated MetisForwarder (saves reference)
+ * @param [in] fd The socket to use
+ * @param [in] pair An allocated address pair for the connection (saves
+ * reference)
+ * @param [in] isLocal determines if the remote address is on the current system
+ *
+ * @retval non-null An allocated Io operations
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+IoOperations *udpConnection_Create(Forwarder *forwarder, int fd,
+                                   const AddressPair *pair, bool isLocal);
+#endif  // udpConnection_h
diff --git a/hicn-light/src/io/udpListener.c b/hicn-light/src/io/udpListener.c
new file mode 100755 (executable)
index 0000000..31c0e67
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2017-2019 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 <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <src/core/messageHandler.h>
+
+#include <src/io/udpConnection.h>
+#include <src/io/udpListener.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/core/connection.h>
+#include <src/core/forwarder.h>
+#include <src/core/messagePacketType.h>
+
+#ifdef WITH_MAPME
+#include <src/core/mapMe.h>
+#endif /* WITH_MAPME */
+
+#define IPv4 4
+#define IPv6 6
+
+struct udp_listener {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  PARCEvent *udp_event;
+  SocketType udp_socket;
+  uint16_t port;
+
+  unsigned id;
+  Address *localAddress;
+};
+
+static void _destroy(ListenerOps **listenerOpsPtr);
+static unsigned _getInterfaceIndex(const ListenerOps *ops);
+static const Address *_getListenAddress(const ListenerOps *ops);
+static EncapType _getEncapType(const ListenerOps *ops);
+static int _getSocket(const ListenerOps *ops);
+
+static ListenerOps udpTemplate = {.context = NULL,
+                                  .destroy = &_destroy,
+                                  .getInterfaceIndex = &_getInterfaceIndex,
+                                  .getListenAddress = &_getListenAddress,
+                                  .getEncapType = &_getEncapType,
+                                  .getSocket = &_getSocket};
+
+static void _readcb(int fd, PARCEventType what, void *udpVoid);
+
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+                                     struct sockaddr_in6 sin6) {
+  ListenerOps *ops = NULL;
+
+  UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
+  parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(UdpListener));
+  udp->forwarder = forwarder;
+  udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  udp->localAddress = addressCreateFromInet6(&sin6);
+  udp->id = forwarder_GetNextConnectionId(forwarder);
+
+  udp->udp_socket = socket(AF_INET6, SOCK_DGRAM, 0);
+  parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s",
+                  errno, strerror(errno));
+
+  // Set non-blocking flag
+  int flags = fcntl(udp->udp_socket, F_GETFL, NULL);
+  parcAssertTrue(flags != -1,
+                 "fcntl failed to obtain file descriptor flags (%d)", errno);
+  int failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK);
+  parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+                  errno);
+
+  int one = 1;
+  // don't hang onto address after listener has closed
+  failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
+                       (socklen_t)sizeof(one));
+  parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno);
+
+  failure = bind(udp->udp_socket, (struct sockaddr *)&sin6, sizeof(sin6));
+  if (failure == 0) {
+    udp->udp_event =
+        dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true,
+                                      _readcb, (void *)udp, udp->udp_socket);
+    dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+                                 udp->udp_event);
+
+    ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+    parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(ListenerOps));
+    memcpy(ops, &udpTemplate, sizeof(ListenerOps));
+    ops->context = udp;
+
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+      char *str = addressToString(udp->localAddress);
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "UdpListener %p created for address %s", (void *)udp, str);
+      parcMemory_Deallocate((void **)&str);
+    }
+  } else {
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+      int myerrno = errno;
+      char *str = addressToString(udp->localAddress);
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Error binding UDP socket to address %s: (%d) %s", str,
+                 myerrno, strerror(myerrno));
+      parcMemory_Deallocate((void **)&str);
+    }
+
+    close(udp->udp_socket);
+    addressDestroy(&udp->localAddress);
+    logger_Release(&udp->logger);
+    parcMemory_Deallocate((void **)&udp);
+  }
+
+  return ops;
+}
+
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+                                    struct sockaddr_in sin) {
+  ListenerOps *ops = NULL;
+
+  UdpListener *udp = parcMemory_AllocateAndClear(sizeof(UdpListener));
+  parcAssertNotNull(udp, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(UdpListener));
+  udp->forwarder = forwarder;
+  udp->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  udp->localAddress = addressCreateFromInet(&sin);
+  udp->id = forwarder_GetNextConnectionId(forwarder);
+
+  udp->udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
+  parcAssertFalse(udp->udp_socket < 0, "Error opening UDP socket: (%d) %s",
+                  errno, strerror(errno));
+
+  // Set non-blocking flag
+  int flags = fcntl(udp->udp_socket, F_GETFL, NULL);
+  parcAssertTrue(flags != -1,
+                 "fcntl failed to obtain file descriptor flags (%d)", errno);
+  int failure = fcntl(udp->udp_socket, F_SETFL, flags | O_NONBLOCK);
+  parcAssertFalse(failure, "fcntl failed to set file descriptor flags (%d)",
+                  errno);
+
+  int one = 1;
+  // don't hang onto address after listener has closed
+  failure = setsockopt(udp->udp_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
+                       (socklen_t)sizeof(one));
+  parcAssertFalse(failure, "failed to set REUSEADDR on socket(%d)", errno);
+
+  failure = bind(udp->udp_socket, (struct sockaddr *)&sin, sizeof(sin));
+  if (failure == 0) {
+    udp->udp_event =
+        dispatcher_CreateNetworkEvent(forwarder_GetDispatcher(forwarder), true,
+                                      _readcb, (void *)udp, udp->udp_socket);
+    dispatcher_StartNetworkEvent(forwarder_GetDispatcher(forwarder),
+                                 udp->udp_event);
+
+    ops = parcMemory_AllocateAndClear(sizeof(ListenerOps));
+    parcAssertNotNull(ops, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                      sizeof(ListenerOps));
+    memcpy(ops, &udpTemplate, sizeof(ListenerOps));
+    ops->context = udp;
+
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+      char *str = addressToString(udp->localAddress);
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "UdpListener %p created for address %s", (void *)udp, str);
+      parcMemory_Deallocate((void **)&str);
+    }
+  } else {
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+      int myerrno = errno;
+      char *str = addressToString(udp->localAddress);
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Error binding UDP socket to address %s: (%d) %s", str,
+                 myerrno, strerror(myerrno));
+      parcMemory_Deallocate((void **)&str);
+    }
+
+    close(udp->udp_socket);
+    addressDestroy(&udp->localAddress);
+    logger_Release(&udp->logger);
+    parcMemory_Deallocate((void **)&udp);
+  }
+
+  return ops;
+}
+
+static void udpListener_Destroy(UdpListener **listenerPtr) {
+  parcAssertNotNull(listenerPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listenerPtr,
+                    "Parameter must derefernce to non-null pointer");
+
+  UdpListener *udp = *listenerPtr;
+
+  if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "UdpListener %p destroyed", (void *)udp);
+  }
+
+  close(udp->udp_socket);
+  addressDestroy(&udp->localAddress);
+  dispatcher_DestroyNetworkEvent(forwarder_GetDispatcher(udp->forwarder),
+                                 &udp->udp_event);
+  logger_Release(&udp->logger);
+  parcMemory_Deallocate((void **)&udp);
+  *listenerPtr = NULL;
+}
+
+static void _destroy(ListenerOps **listenerOpsPtr) {
+  ListenerOps *ops = *listenerOpsPtr;
+  UdpListener *udp = (UdpListener *)ops->context;
+  udpListener_Destroy(&udp);
+  parcMemory_Deallocate((void **)&ops);
+  *listenerOpsPtr = NULL;
+}
+
+static unsigned _getInterfaceIndex(const ListenerOps *ops) {
+  UdpListener *udp = (UdpListener *)ops->context;
+  return udp->id;
+}
+
+static const Address *_getListenAddress(const ListenerOps *ops) {
+  UdpListener *udp = (UdpListener *)ops->context;
+  return udp->localAddress;
+}
+
+static EncapType _getEncapType(const ListenerOps *ops) { return ENCAP_UDP; }
+
+static int _getSocket(const ListenerOps *ops) {
+  UdpListener *udp = (UdpListener *)ops->context;
+  return (int)udp->udp_socket;
+}
+
+// void
+// udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type)
+//{
+//    return;
+//}
+
+// =====================================================================
+
+/**
+ * @function peekMesageLength
+ * @abstract Peek at the next packet to learn its length by reading the fixed
+ * header
+ * @discussion
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+static size_t _peekMessageLength(UdpListener *udp, int fd,
+                                 struct sockaddr *peerIpAddress,
+                                 socklen_t *peerIpAddressLengthPtr) {
+  // to be fast I try to use just ipv6, this needs to be validated for ipv4
+
+  size_t packetLength = 0;
+
+  uint8_t fixedHeader[messageHandler_GetIPHeaderLength(IPv6)];
+
+  // peek at the UDP packet and read in the fixed header.
+  // Also returns the socket information for the remote peer
+
+  ssize_t res = recvfrom(
+      fd, fixedHeader, messageHandler_GetIPHeaderLength(IPv6), MSG_PEEK,
+      (struct sockaddr *)peerIpAddress, peerIpAddressLengthPtr);
+
+  if (res == messageHandler_GetIPHeaderLength(IPv6)) {
+    packetLength =
+        messageHandler_GetTotalPacketLength((const uint8_t *)&fixedHeader);
+  } else {
+    if (res < 0) {
+      printf("error while readin packet\n");
+    }
+  }
+
+  return packetLength;
+}
+
+/**
+ * @function _constructAddressPair
+ * @abstract Creates the address pair that uniquely identifies the connection
+ * @discussion
+ *   The peerIpAddress must be of AF_INET or AF_INET6 family.
+ *
+ * @param <#param1#>
+ * @return Allocated MetisAddressPair, must be destroyed
+ */
+static AddressPair *_constructAddressPair(UdpListener *udp,
+                                          struct sockaddr *peerIpAddress,
+                                          socklen_t peerIpAddressLength) {
+  Address *remoteAddress;
+
+  switch (peerIpAddress->sa_family) {
+    case AF_INET:
+      remoteAddress =
+          addressCreateFromInet((struct sockaddr_in *)peerIpAddress);
+      break;
+
+    case AF_INET6:
+      remoteAddress =
+          addressCreateFromInet6((struct sockaddr_in6 *)peerIpAddress);
+      break;
+
+    default:
+      parcTrapIllegalValue(peerIpAddress,
+                           "Peer address unrecognized family for IP: %d",
+                           peerIpAddress->sa_family);
+  }
+
+  AddressPair *pair = addressPair_Create(udp->localAddress, remoteAddress);
+  addressDestroy(&remoteAddress);
+
+  return pair;
+}
+
+/**
+ * @function _lookupConnectionId
+ * @abstract  Lookup a connection in the connection table
+ * @discussion
+ *   Looks up the connection in the connection table and returns the connection
+ * id if it exists.
+ *
+ * @param outputConnectionIdPtr is the output parameter
+ * @return true if connection found and outputConnectionIdPtr set
+ */
+static bool _lookupConnectionId(UdpListener *udp, AddressPair *pair,
+                                unsigned *outputConnectionIdPtr) {
+  ConnectionTable *connTable = forwarder_GetConnectionTable(udp->forwarder);
+
+  const Connection *conn = connectionTable_FindByAddressPair(connTable, pair);
+  if (conn) {
+    *outputConnectionIdPtr = connection_GetConnectionId(conn);
+    return true;
+  } else {
+    *outputConnectionIdPtr = 0;
+    return false;
+  }
+}
+
+/**
+ * @function _createNewConnection
+ * @abstract Creates a new Metis connection for the peer
+ * @discussion
+ *   PRECONDITION: you know there's not an existing connection with the address
+ * pair
+ *
+ *   Creates a new connection and adds it to the connection table.
+ *
+ * @param <#param1#>
+ * @return The connection id for the new connection
+ */
+
+static unsigned _createNewConnection(UdpListener *udp, int fd,
+                                     const AddressPair *pair) {
+  bool isLocal = false;
+
+  // metisUdpConnection_Create takes ownership of the pair
+  IoOperations *ops = udpConnection_Create(udp->forwarder, fd, pair, isLocal);
+  Connection *conn = connection_Create(ops);
+  // connection_AllowWldrAutoStart(conn);
+
+  connectionTable_Add(forwarder_GetConnectionTable(udp->forwarder), conn);
+  unsigned connid = ioOperations_GetConnectionId(ops);
+
+  return connid;
+}
+
+static void _handleProbeMessage(UdpListener *udp, uint8_t *msgBuffer) {
+  // TODO
+  parcMemory_Deallocate((void **)&msgBuffer);
+}
+
+static void _handleWldrNotification(UdpListener *udp, unsigned connId,
+                                    uint8_t *msgBuffer) {
+  const Connection *conn = connectionTable_FindById(
+      forwarder_GetConnectionTable(udp->forwarder), connId);
+  if (conn == NULL) {
+    return;
+  }
+
+  Message *message = message_CreateFromByteArray(
+      connId, msgBuffer, MessagePacketType_WldrNotification,
+      forwarder_GetTicks(udp->forwarder), forwarder_GetLogger(udp->forwarder));
+
+  connection_HandleWldrNotification((Connection *)conn, message);
+
+  message_Release(&message);
+}
+
+static Message *_readMessage(UdpListener *udp, int fd, size_t packetLength,
+                             AddressPair *pair) {
+  uint8_t *msgBuffer = parcMemory_AllocateAndClear(packetLength);
+
+  ssize_t readLength = read(fd, msgBuffer, packetLength);
+
+  Message *message = NULL;
+
+  if (readLength < 0) {
+    printf("read failed %d: (%d) %s\n", fd, errno, strerror(errno));
+    return message;
+  }
+
+  unsigned connid = 0;
+  bool foundConnection = _lookupConnectionId(udp, pair, &connid);
+
+  if (readLength == packetLength) {
+    // we need to check if it is a valid packet
+    if (messageHandler_IsTCP(msgBuffer)) {
+      MessagePacketType pktType;
+
+      if (messageHandler_IsData(msgBuffer)) {
+        pktType = MessagePacketType_ContentObject;
+        if (!foundConnection) {
+          parcMemory_Deallocate((void **)&msgBuffer);
+          return message;
+        }
+      } else if (messageHandler_IsInterest(msgBuffer)) {
+        pktType = MessagePacketType_Interest;
+        if (!foundConnection) {
+          connid = _createNewConnection(udp, fd, pair);
+        }
+      } else {
+        printf("Got a packet that is not a data nor an interest, drop it!\n");
+        parcMemory_Deallocate((void **)&msgBuffer);
+        return message;
+      }
+
+      message = message_CreateFromByteArray(
+          connid, msgBuffer, pktType, forwarder_GetTicks(udp->forwarder),
+          forwarder_GetLogger(udp->forwarder));
+
+      if (message == NULL) {
+        parcMemory_Deallocate((void **)&msgBuffer);
+      }
+    } else if (messageHandler_IsWldrNotification(msgBuffer)) {
+      _handleWldrNotification(udp, connid, msgBuffer);
+    } else if (messageHandler_IsLoadBalancerProbe(msgBuffer)) {
+      _handleProbeMessage(udp, msgBuffer);
+    }
+#ifdef WITH_MAPME
+    else if (mapMe_isMapMe(msgBuffer)) {
+      forwarder_ProcessMapMe(udp->forwarder, msgBuffer, connid);
+    }
+#endif /* WITH_MAPME */
+  }
+
+  return message;
+}
+
+static void _receivePacket(UdpListener *udp, int fd, size_t packetLength,
+                           struct sockaddr_storage *peerIpAddress,
+                           socklen_t peerIpAddressLength) {
+  AddressPair *pair = _constructAddressPair(
+      udp, (struct sockaddr *)peerIpAddress, peerIpAddressLength);
+
+  Message *message = _readMessage(udp, fd, packetLength, pair);
+  addressPair_Release(&pair);
+
+  if (message) {
+    forwarder_Receive(udp->forwarder, message);
+  } else {
+    return;
+  }
+}
+
+static void _readFrameToDiscard(UdpListener *udp, int fd) {
+  // we need to discard the frame.  Read 1 byte.  This will clear it off the
+  // stack.
+  uint8_t buffer;
+  ssize_t nread = read(fd, &buffer, 1);
+
+  if (nread == 1) {
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                 "Discarded frame from fd %d", fd);
+    }
+  } else if (nread < 0) {
+    if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+      logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Error trying to discard frame from fd %d: (%d) %s", fd, errno,
+                 strerror(errno));
+    }
+  }
+}
+
+static void _readcb(int fd, PARCEventType what, void *udpVoid) {
+  UdpListener *udp = (UdpListener *)udpVoid;
+
+  if (logger_IsLoggable(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+    logger_Log(udp->logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+               "%s socket %d what %s%s%s%s data %p", __func__, fd,
+               (what & PARCEventType_Timeout) ? " timeout" : "",
+               (what & PARCEventType_Read) ? " read" : "",
+               (what & PARCEventType_Write) ? " write" : "",
+               (what & PARCEventType_Signal) ? " signal" : "", udpVoid);
+  }
+
+  if (what & PARCEventType_Read) {
+    struct sockaddr_storage peerIpAddress;
+    socklen_t peerIpAddressLength = sizeof(peerIpAddress);
+
+    size_t packetLength = _peekMessageLength(
+        udp, fd, (struct sockaddr *)&peerIpAddress, &peerIpAddressLength);
+
+    if (packetLength > 0) {
+      _receivePacket(udp, fd, packetLength, &peerIpAddress,
+                     peerIpAddressLength);
+    } else {
+      _readFrameToDiscard(udp, fd);
+    }
+  }
+}
diff --git a/hicn-light/src/io/udpListener.h b/hicn-light/src/io/udpListener.h
new file mode 100755 (executable)
index 0000000..1cf3bd8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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 udpListener_h
+#define udpListener_h
+
+#include <netinet/in.h>
+#include <src/core/forwarder.h>
+#include <src/io/listener.h>
+#include <stdlib.h>
+
+struct udp_listener;
+typedef struct udp_listener UdpListener;
+
+ListenerOps *udpListener_CreateInet6(Forwarder *forwarder,
+                                     struct sockaddr_in6 sin6);
+ListenerOps *udpListener_CreateInet(Forwarder *forwarder,
+                                    struct sockaddr_in sin);
+// void udpListener_SetPacketType(ListenerOps *ops, MessagePacketType type);
+#endif  // udpListener_h
diff --git a/hicn-light/src/io/udpTunnel.c b/hicn-light/src/io/udpTunnel.c
new file mode 100755 (executable)
index 0000000..d06a35c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/io/udpConnection.h>
+#include <src/io/udpListener.h>
+#include <src/io/udpTunnel.h>
+
+IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder,
+                                         ListenerOps *localListener,
+                                         const Address *remoteAddress) {
+  parcAssertNotNull(forwarder, "Parameter metis must be non-null");
+  parcAssertNotNull(localListener, "Parameter localListener must be non-null");
+  parcAssertNotNull(remoteAddress, "Parameter remoteAddress must be non-null");
+
+  Logger *logger = forwarder_GetLogger(forwarder);
+
+  IoOperations *ops = NULL;
+  if (localListener->getEncapType(localListener) == ENCAP_UDP) {
+    const Address *localAddress =
+        localListener->getListenAddress(localListener);
+    address_type localType = addressGetType(localAddress);
+    address_type remoteType = addressGetType(remoteAddress);
+
+    if (localType == remoteType) {
+      AddressPair *pair = addressPair_Create(localAddress, remoteAddress);
+      bool isLocal = false;
+      int fd = localListener->getSocket(localListener);
+      // udpListener_SetPacketType(localListener,
+      //                MessagePacketType_ContentObject);
+      ops = udpConnection_Create(forwarder, fd, pair, isLocal);
+
+      addressPair_Release(&pair);
+    } else {
+      if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+        logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                   "Local listener of type %s and remote type %s, cannot "
+                   "establish tunnel",
+                   addressTypeToString(localType),
+                   addressTypeToString(remoteType));
+      }
+    }
+  } else {
+    if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Error)) {
+      logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Error, __func__,
+                 "Local listener %p is not type UDP, cannot establish tunnel",
+                 (void *)localListener);
+    }
+  }
+
+  return ops;
+}
+
+IoOperations *udpTunnel_Create(Forwarder *forwarder,
+                               const Address *localAddress,
+                               const Address *remoteAddress) {
+  ListenerSet *set = forwarder_GetListenerSet(forwarder);
+  ListenerOps *listener = listenerSet_Find(set, ENCAP_UDP, localAddress);
+  IoOperations *ops = NULL;
+  if (listener) {
+    ops = udpTunnel_CreateOnListener(forwarder, listener, remoteAddress);
+  } else {
+    if (logger_IsLoggable(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+                          PARCLogLevel_Error)) {
+      char *str = addressToString(localAddress);
+      logger_Log(forwarder_GetLogger(forwarder), LoggerFacility_IO,
+                 PARCLogLevel_Error, __func__,
+                 "Could not find listener to match address %s", str);
+      parcMemory_Deallocate((void **)&str);
+    }
+  }
+  return ops;
+}
diff --git a/hicn-light/src/io/udpTunnel.h b/hicn-light/src/io/udpTunnel.h
new file mode 100755 (executable)
index 0000000..a79ca4a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file udpTunnel.h
+ * @brief Establish a tunnel to a remote system
+ *
+ */
+
+#ifndef udpTunnel_h
+#define udpTunnel_h
+
+#include <src/core/forwarder.h>
+#include <src/io/ioOperations.h>
+#include <src/io/listener.h>
+#include <src/utils/address.h>
+
+/**
+ */
+IoOperations *udpTunnel_CreateOnListener(Forwarder *forwarder,
+                                         ListenerOps *localListener,
+                                         const Address *remoteAddress);
+
+/**
+ */
+IoOperations *udpTunnel_Create(Forwarder *forwarder,
+                               const Address *localAddress,
+                               const Address *remoteAddress);
+
+#endif  // udpTunnel_h
diff --git a/hicn-light/src/messenger/CMakeLists.txt b/hicn-light/src/messenger/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..92bc13b
--- /dev/null
@@ -0,0 +1,32 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/missive.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/missiveType.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/messenger.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/messenger.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/messengerRecipient.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/missive.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/missiveDeque.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/messenger/messenger.c b/hicn-light/src/messenger/messenger.c
new file mode 100755 (executable)
index 0000000..26c7a85
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ *
+ * The messenger is contructued with a reference to the forwarder's dispatcher
+ * so it can schedule future events.  When someone calls messenger_Send(...), it
+ * will put the message on a queue.  If the queue was empty, it will scheudle
+ * itself to be run. By running the queue in a future dispatcher slice, it
+ * guarantees that there will be no re-entrant behavior between callers and
+ * message listeners.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ */
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Event.h>
+#include <parc/algol/parc_EventScheduler.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/messenger.h>
+#include <src/messenger/missiveDeque.h>
+
+struct messenger {
+  PARCArrayList *callbacklist;
+  Dispatcher *dispatcher;
+  MissiveDeque *eventQueue;
+
+  PARCEventTimer *timerEvent;
+};
+
+static void messenger_Dequeue(int fd, PARCEventType which_event,
+                              void *messengerVoidPtr);
+
+// =========================================
+// Public API
+
+Messenger *messenger_Create(Dispatcher *dispatcher) {
+  Messenger *messenger = parcMemory_AllocateAndClear(sizeof(Messenger));
+  parcAssertNotNull(messenger, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Messenger));
+
+  // NULL destroyer because we're storing structures owned by the caller
+  messenger->dispatcher = dispatcher;
+  messenger->callbacklist = parcArrayList_Create(NULL);
+  messenger->eventQueue = missiveDeque_Create();
+
+  // creates the timer, but does not start it
+  messenger->timerEvent =
+      dispatcher_CreateTimer(dispatcher, false, messenger_Dequeue, messenger);
+
+  return messenger;
+}
+
+void messenger_Destroy(Messenger **messengerPtr) {
+  parcAssertNotNull(messengerPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*messengerPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  Messenger *messenger = *messengerPtr;
+  parcArrayList_Destroy(&messenger->callbacklist);
+  missiveDeque_Release(&messenger->eventQueue);
+  dispatcher_DestroyTimerEvent(messenger->dispatcher, &messenger->timerEvent);
+  parcMemory_Deallocate((void **)&messenger);
+  *messengerPtr = NULL;
+}
+
+void messenger_Send(Messenger *messenger, Missive *missive) {
+  parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+  parcAssertNotNull(missive, "Parameter event must be non-null");
+
+  missiveDeque_Append(messenger->eventQueue, missive);
+  if (missiveDeque_Size(messenger->eventQueue) == 1) {
+    // We need to scheudle ourself when an event is added to an empty queue
+
+    // precondition: timer should not be running.
+    struct timeval immediateTimeout = {0, 0};
+    dispatcher_StartTimer(messenger->dispatcher, messenger->timerEvent,
+                          &immediateTimeout);
+  }
+}
+
+static void removeRecipient(Messenger *messenger,
+                            const MessengerRecipient *recipient) {
+  // don't increment i in the loop
+  for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist);) {
+    const void *p = parcArrayList_Get(messenger->callbacklist, i);
+    if (p == recipient) {
+      // removing will compact the list, so next element will also be at i.
+      parcArrayList_RemoveAndDestroyAtIndex(messenger->callbacklist, i);
+    } else {
+      i++;
+    }
+  }
+}
+
+/**
+ * @function eventMessenger_Register
+ * @abstract Receive all event messages
+ */
+void messenger_Register(Messenger *messenger,
+                        const MessengerRecipient *recipient) {
+  parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+  parcAssertNotNull(recipient, "Parameter recipient must be non-null");
+
+  // do not allow duplicates
+  removeRecipient(messenger, recipient);
+
+  parcArrayList_Add(messenger->callbacklist, recipient);
+}
+
+/**
+ * @function eventMessenger_Unregister
+ * @abstract Stop receiving event messages
+ */
+void messenger_Unregister(Messenger *messenger,
+                          const MessengerRecipient *recipient) {
+  parcAssertNotNull(messenger, "Parameter messenger must be non-null");
+  parcAssertNotNull(recipient, "Parameter recipient must be non-null");
+
+  removeRecipient(messenger, recipient);
+}
+
+/**
+ * Called by event scheduler to give us a slice in which to dequeue events
+ *
+ * Called inside an event callback, so we now have exclusive access to the
+ * system. Dequeues all pending events and calls all the listeners for each one.
+ *
+ * @param [in] fd unused, required for compliance with function prototype
+ * @param [in] which_event unused, required for compliance with function
+ * prototype
+ * @param [in] messengerVoidPtr A void* to Messenger
+ */
+static void messenger_Dequeue(int fd, PARCEventType which_event,
+                              void *messengerVoidPtr) {
+  Messenger *messenger = (Messenger *)messengerVoidPtr;
+  parcAssertNotNull(messenger, "Called with null messenger pointer");
+
+  Missive *missive;
+  while ((missive = missiveDeque_RemoveFirst(messenger->eventQueue)) != NULL) {
+    for (size_t i = 0; i < parcArrayList_Size(messenger->callbacklist); i++) {
+      MessengerRecipient *recipient =
+          parcArrayList_Get(messenger->callbacklist, i);
+      parcAssertTrue(recipient, "Recipient is null at index %zu", i);
+
+      messengerRecipient_Deliver(recipient, missive_Acquire(missive));
+    }
+
+    // now let go of our reference to the missive
+    missive_Release(&missive);
+  }
+}
diff --git a/hicn-light/src/messenger/messenger.h b/hicn-light/src/messenger/messenger.h
new file mode 100755 (executable)
index 0000000..f945e7e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * The EventMessenger is the system that messages events between
+ * producers and consumers.
+ *
+ * Events are delivered in a deferred event cycle to avoid event callbacks
+ * firing when the event generator is still running.
+ */
+
+#ifndef messenger_h
+#define messenger_h
+
+#include <src/core/dispatcher.h>
+#include <src/messenger/messengerRecipient.h>
+#include <src/messenger/missive.h>
+
+struct messenger;
+typedef struct messenger Messenger;
+
+/**
+ * @function eventmessenger_Create
+ * @abstract Creates an event notification system
+ * @discussion
+ *   Typically there's only one of these managed by forwarder.
+ *
+ * @param dispatcher is the event dispatcher to use to schedule events.
+ */
+Messenger *messenger_Create(Dispatcher *dispatcher);
+
+/**
+ * @function eventMessenger_Destroy
+ * @abstract Destroys the messenger system, no notification is sent
+ */
+void messenger_Destroy(Messenger **messengerPtr);
+
+/**
+ * @function eventMessenger_Send
+ * @abstract Send an event message, takes ownership of the event memory
+ */
+void messenger_Send(Messenger *messenger, Missive *missive);
+
+/**
+ * @function eventMessenger_Register
+ * @abstract Receive all event messages
+ */
+void messenger_Register(Messenger *messenger,
+                        const MessengerRecipient *recipient);
+
+/**
+ * @function eventMessenger_Unregister
+ * @abstract Stop receiving event messages
+ */
+void messenger_Unregister(Messenger *messenger,
+                          const MessengerRecipient *recipient);
+#endif  // messenger_h
diff --git a/hicn-light/src/messenger/messengerRecipient.c b/hicn-light/src/messenger/messengerRecipient.c
new file mode 100755 (executable)
index 0000000..14251f8
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/messenger.h>
+#include <src/messenger/messengerRecipient.h>
+
+struct messenger_recipient {
+  void *context;
+  MessengerRecipientCallback *notify;
+};
+
+MessengerRecipient *messengerRecipient_Create(
+    void *recipientContext, MessengerRecipientCallback *recipientCallback) {
+  parcAssertNotNull(recipientCallback,
+                    "Parameter recipientCallback must be non-null");
+
+  MessengerRecipient *recipient =
+      parcMemory_AllocateAndClear(sizeof(MessengerRecipient));
+  parcAssertNotNull(recipient, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(MessengerRecipient));
+  recipient->context = recipientContext;
+  recipient->notify = recipientCallback;
+  return recipient;
+}
+
+void messengerRecipient_Destroy(MessengerRecipient **recipientPtr) {
+  parcAssertNotNull(recipientPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*recipientPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  parcMemory_Deallocate((void **)recipientPtr);
+  *recipientPtr = NULL;
+}
+
+void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient) {
+  parcAssertNotNull(recipient, "Parameter must be non-null");
+
+  return recipient->context;
+}
+
+void messengerRecipient_Deliver(MessengerRecipient *recipient,
+                                Missive *missive) {
+  parcAssertNotNull(recipient, "Parameter must be non-null");
+  recipient->notify(recipient, missive);
+}
diff --git a/hicn-light/src/messenger/messengerRecipient.h b/hicn-light/src/messenger/messengerRecipient.h
new file mode 100755 (executable)
index 0000000..66d8f40
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file messengerRecipient.h
+ * @brief A recipient represents the entity that will recieve a Missive from the
+ * Messenger.
+ *
+ * A recipient is identified by the pair (contenxt, callback).  The context is
+ * the recipients context, such as it's object pointer.  The callback is the
+ * function the recipient uses to receive a Missive.
+ *
+ * If the receiver is going to do a lot of work or potentially send other
+ * missives, the receiver should queue the received notifications and process
+ * them in its own slice.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ *
+ */
+
+#ifndef messengerRecipient_h
+#define messengerRecipient_h
+
+#include <src/messenger/missive.h>
+
+struct messenger_recipient;
+typedef struct messenger_recipient MessengerRecipient;
+
+/**
+ * @typedef MessengerRecipientCallback
+ * @abstract A recipient implements a callback to receive Missives.
+ * @constant recipient The recipient to recieve the missive
+ * @constant missive The missive, recipient must call {@link missive_Release} on
+ * it
+ */
+typedef void(MessengerRecipientCallback)(MessengerRecipient *recipient,
+                                         Missive *missive);
+
+/**
+ * Creates a Recipient, which represents a reciever of missives.
+ *
+ * Creates a Recipient that can be registerd with the Messenger using {@link
+ * messenger_Register}.
+ *
+ * @param [in] recipientContext This pointer will be passed back to the
+ * recipient with each missive, may be NULL
+ * @param [in] recipientCallback The function that receives the missive, must be
+ * non-NULL.
+ *
+ * @return non-null A recipient object
+ */
+MessengerRecipient *messengerRecipient_Create(
+    void *recipientContext, MessengerRecipientCallback *recipientCallback);
+
+/**
+ * Destroys a recipient.  You should unregister it first.
+ *
+ * Destroying a recipient does not unregister it, so be sure to call
+ * {@link messenger_Unregister} first.
+ *
+ * @param [in,out] recipientPtr Double pointer to the recipient to destroy, will
+ * be NULL'd.
+ */
+void messengerRecipient_Destroy(MessengerRecipient **recipientPtr);
+
+/**
+ * Returns the recipient context passed on Create
+ *
+ * @param [in] recipient The recipient object
+ *
+ * @return pointer The context pointer used to create the object, maybe NULL
+ */
+void *messengerRecipient_GetRecipientContext(MessengerRecipient *recipient);
+
+/**
+ * Delivers a Missive to the recipient
+ *
+ * Passes the missive to the recipients callback.
+ *
+ * A recipient will receive a reference counted copy of the missive, so it must
+ * call
+ * {@link missive_Release} on it.
+ *
+ * @param [in] recipient The receiver
+ * @param [in] missive The message to send
+ */
+void messengerRecipient_Deliver(MessengerRecipient *recipient,
+                                Missive *missive);
+#endif  // messengerRecipient_h
diff --git a/hicn-light/src/messenger/missive.c b/hicn-light/src/messenger/missive.c
new file mode 100755 (executable)
index 0000000..a8bcb02
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017-2019 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 <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/missive.h>
+
+struct missive {
+  MissiveType missiveType;
+  unsigned connectionid;
+};
+
+parcObject_Override(Missive, PARCObject, .isLockable = false);
+
+Missive *missive_Create(MissiveType missiveType, unsigned connectionid) {
+  Missive *missive = parcObject_CreateInstance(Missive);
+  missive->missiveType = missiveType;
+  missive->connectionid = connectionid;
+  return missive;
+}
+
+Missive *missive_Acquire(const Missive *missive) {
+  return parcObject_Acquire(missive);
+}
+
+void missive_Release(Missive **missivePtr) {
+  parcObject_Release((void **)missivePtr);
+}
+
+MissiveType missive_GetType(const Missive *missive) {
+  parcAssertNotNull(missive, "Parameter missive must be non-null");
+  return missive->missiveType;
+}
+
+unsigned missive_GetConnectionId(const Missive *missive) {
+  parcAssertNotNull(missive, "Parameter missive must be non-null");
+  return missive->connectionid;
+}
diff --git a/hicn-light/src/messenger/missive.h b/hicn-light/src/messenger/missive.h
new file mode 100755 (executable)
index 0000000..33f3ef8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file missive.h
+ * @brief A Missive is a status message sent over a broadcast channel inside
+ * hicn-light
+ *
+ * Recipients use {@link messenger_Register} to receive missives.  They are
+ * broadcast to all recipients.
+ *
+ */
+#ifndef missive_h
+#define missive_h
+
+#include <src/messenger/missiveType.h>
+
+struct missive;
+typedef struct missive Missive;
+
+/**
+ * Creates a Missive and sets the reference count to 1
+ *
+ * A Missive may be sent to listeners of the Messenger to inform them of events
+ * on a connection id.
+ *
+ * @param [in] MissiveType The event type
+ * @param [in] connectionid The relevant conneciton id
+ *
+ * @return non-null A message
+ * @retrun null An error
+ */
+Missive *missive_Create(MissiveType missiveType, unsigned connectionid);
+
+/**
+ * Acquire a reference counted copy
+ *
+ * Increases the reference count by 1 and returns the original object.
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return non-null The original missive with increased reference count
+ */
+Missive *missive_Acquire(const Missive *missive);
+
+/**
+ * Releases a reference counted copy.
+ *
+ *  If it is the last reference, the missive is freed.
+ *
+ * @param [in,out] missivePtr Double pointer to a missive, will be nulled.
+ */
+void missive_Release(Missive **missivePtr);
+
+/**
+ * Returns the type of the missive
+ *
+ * Returns the type of event the missive represents
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return MissiveType The event type
+ */
+MissiveType missive_GetType(const Missive *missive);
+
+/**
+ * Returns the connection ID of the missive
+ *
+ * An event is usually associated with a connection id (i.e. the I/O channel
+ * that originaged the event).
+ *
+ * @param [in] missive An allocated missive
+ *
+ * @return number The relevant connection id.
+ */
+unsigned missive_GetConnectionId(const Missive *missive);
+#endif  // missive_h
diff --git a/hicn-light/src/messenger/missiveDeque.c b/hicn-light/src/messenger/missiveDeque.c
new file mode 100755 (executable)
index 0000000..418027d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * A type-safe wrapper for Missives around a {@link PARCDeque}.  We only
+ * implement the subset of functions used.
+ *
+ */
+
+#include <parc/algol/parc_Deque.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/messenger/missive.h>
+#include <src/messenger/missiveDeque.h>
+
+struct missive_deque {
+  PARCDeque *queue;
+};
+
+MissiveDeque *missiveDeque_Create(void) {
+  MissiveDeque *missiveDeque =
+      parcMemory_AllocateAndClear(sizeof(MissiveDeque));
+  parcAssertNotNull(missiveDeque,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(MissiveDeque));
+  missiveDeque->queue = parcDeque_Create();
+  return missiveDeque;
+}
+
+void missiveDeque_Release(MissiveDeque **dequePtr) {
+  parcAssertNotNull(dequePtr, "Double pointer must be non-null");
+  parcAssertNotNull(*dequePtr, "Double pointer must dereference to non-null");
+  MissiveDeque *missiveDeque = *dequePtr;
+
+  // flush the queue
+  while (!parcDeque_IsEmpty(missiveDeque->queue)) {
+    Missive *missive = missiveDeque_RemoveFirst(missiveDeque);
+    missive_Release(&missive);
+  }
+
+  parcDeque_Release(&missiveDeque->queue);
+  parcMemory_Deallocate((void **)&missiveDeque);
+  *dequePtr = NULL;
+}
+
+MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive) {
+  parcAssertNotNull(deque, "Parameter deque must be non-null");
+  parcAssertNotNull(missive, "Parameter missive must be non-null");
+
+  parcDeque_Append(deque->queue, missive);
+  return deque;
+}
+
+Missive *missiveDeque_RemoveFirst(MissiveDeque *deque) {
+  parcAssertNotNull(deque, "Parameter deque must be non-null");
+  return (Missive *)parcDeque_RemoveFirst(deque->queue);
+}
+
+size_t missiveDeque_Size(const MissiveDeque *deque) {
+  parcAssertNotNull(deque, "Parameter deque must be non-null");
+  return parcDeque_Size(deque->queue);
+}
diff --git a/hicn-light/src/messenger/missiveDeque.h b/hicn-light/src/messenger/missiveDeque.h
new file mode 100755 (executable)
index 0000000..c6f955c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file missiveDeque
+ * @brief Double ended queue of Missives
+ *
+ * Used to queue Missives.  This is a type-safe wrapper around {@link PARCDeque}
+ *
+ */
+
+#ifndef missiveDeque_h
+#define missiveDeque_h
+
+struct missive_deque;
+
+typedef struct missive_deque MissiveDeque;
+
+/**
+ * Create a `PARCDeque` instance with the default element equals function.
+ *
+ * The queue is created with no elements.
+ *
+ * The default element equals function is used by the `parcDeque_Equals`
+ * function and simply compares the values using the `==` operator. Users that
+ * need more sophisticated comparisons of the elements need to supply their own
+ * function via the `parcDeque_CreateCustom` function.
+ *
+ * @return non-NULL A pointer to a PARCDeque instance.
+ */
+MissiveDeque *missiveDeque_Create(void);
+
+void missiveDeque_Release(MissiveDeque **dequePtr);
+
+/**
+ * Appends the missive to the queue, taking ownership of the memory
+ */
+MissiveDeque *missiveDeque_Append(MissiveDeque *deque, Missive *missive);
+
+Missive *missiveDeque_RemoveFirst(MissiveDeque *deque);
+
+size_t missiveDeque_Size(const MissiveDeque *deque);
+#endif  // missiveDeque_h
diff --git a/hicn-light/src/messenger/missiveType.h b/hicn-light/src/messenger/missiveType.h
new file mode 100755 (executable)
index 0000000..b0d9c77
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file missiveType
+ * @brief Defines what a Missive represents
+ *
+ * Currently, missives only carry information about the state of a connection
+ * (created, up, down, closed, destroyed).
+ *
+ */
+
+#ifndef missiveType_h
+#define missiveType_h
+
+/**
+ * @typedef Represents the state of a connection
+ * @abstract CREATE is the initial state.  UP & DOWN are recurrent states.
+ * CLOSED is transient.  DESTROYED is the terminal state.
+ * @constant MissiveType_ConnectionCreate    Connection created (new)
+ * @constant MissiveType_ConnectionUp        Connection is active and passing
+ * data
+ * @constant MissiveType_ConnectionDown      Connection is inactive and cannot
+ * pass data
+ * @constant MissiveType_ConnectionClosed    Connection closed and will be
+ * destroyed
+ * @constant MissiveType_ConnectionDestroyed Connection destroyed
+ * @discussion State transitions:
+ *                initial   -> CREATE
+ *                CREATE    -> (UP | DOWN)
+ *                UP        -> (DOWN | DESTROYED)
+ *                DOWN      -> (UP | CLOSED | DESTROYED)
+ *                CLOSED    -> DESTROYED
+ *                DESTROYED -> terminal
+ */
+typedef enum {
+  MissiveType_ConnectionCreate,
+  MissiveType_ConnectionUp,
+  MissiveType_ConnectionDown,
+  MissiveType_ConnectionClosed,
+  MissiveType_ConnectionDestroyed
+} MissiveType;
+#endif  // missiveType_h
diff --git a/hicn-light/src/platforms/CMakeLists.txt b/hicn-light/src/platforms/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..fcb4282
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+  list(APPEND SOURCE_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/android/system.c
+  )
+elseif(APPLE)
+  list(APPEND SOURCE_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/darwin/system.c
+  )
+elseif( ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" )
+  list(APPEND SOURCE_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/linux/system.c
+  )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/platforms/README.txt b/hicn-light/src/platforms/README.txt
new file mode 100755 (executable)
index 0000000..a129394
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+Operating system dependent modules.
+
diff --git a/hicn-light/src/platforms/android/system.c b/hicn-light/src/platforms/android/system.c
new file mode 100755 (executable)
index 0000000..68f9942
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//#define __USE_MISC
+#include <net/if.h>
+
+// to get the list of arp types
+#include <net/if_arp.h>
+
+// for the mac address
+#include <netpacket/packet.h>
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include "ifaddrs.h"
+
+/**
+ * Returns the MTU for a named interface
+ *
+ * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU
+ *
+ * @param [in] ifname Interface name (e.g. "eth0")
+ *
+ * @retval number The MTU in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static int getMtu(const char *ifname) {
+  struct ifreq ifr;
+  int fd;
+
+  fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+  strcpy(ifr.ifr_name, ifname);
+  ioctl(fd, SIOCGIFMTU, &ifr);
+
+  close(fd);
+  return ifr.ifr_mtu;
+}
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+  InterfaceSet *set = interfaceSetCreate();
+
+  Logger *logger = forwarder_GetLogger(forwarder);
+
+  // this is the dynamically allocated head of the list
+  struct ifaddrs *ifaddr;
+  int failure = getifaddrs(&ifaddr);
+  parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+  struct ifaddrs *next;
+  for (next = ifaddr; next != NULL; next = next->ifa_next) {
+    if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+      continue;
+    }
+
+    Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+    if (iface == NULL) {
+      unsigned mtu = (unsigned)getMtu(next->ifa_name);
+
+      iface = interfaceCreate(
+          next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+          next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+      interfaceSetAdd(set, iface);
+    }
+
+    int family = next->ifa_addr->sa_family;
+    switch (family) {
+      case AF_INET: {
+        Address *address =
+            addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_INET6: {
+        Address *address =
+            addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_PACKET: {
+        struct sockaddr_ll *addr_ll = (struct sockaddr_ll *)next->ifa_addr;
+
+        if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+          logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                     "sockaddr_ll family %d proto %d ifindex %d hatype %d "
+                     "pkttype %d halen %d",
+                     addr_ll->sll_family, addr_ll->sll_protocol,
+                     addr_ll->sll_ifindex, addr_ll->sll_hatype,
+                     addr_ll->sll_pkttype, addr_ll->sll_halen);
+        }
+
+        switch (addr_ll->sll_hatype) {
+          // list of the ARP hatypes we can extract a MAC address from
+          case ARPHRD_ETHER:
+          // fallthrough
+          case ARPHRD_IEEE802: {
+            Address *address = addressCreateFromLink(
+                (uint8_t *)addr_ll->sll_addr, addr_ll->sll_halen);
+            interfaceAddAddress(iface, address);
+            break;
+          }
+          default:
+            break;
+        }
+
+        break;
+      }
+    }
+  }
+
+  freeifaddrs(ifaddr);
+  return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+                                    const char *interfaceName) {
+  Address *linkAddress = NULL;
+
+  InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+  Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+  if (interface) {
+    const AddressList *addressList = interfaceGetAddresses(interface);
+
+    size_t length = addressListLength(addressList);
+    for (size_t i = 0; i < length && !linkAddress; i++) {
+      const Address *a = addressListGetItem(addressList, i);
+      if (addressGetType(a) == ADDR_LINK) {
+        linkAddress = addressCopy(a);
+      }
+    }
+  }
+
+  interfaceSetDestroy(&interfaceSet);
+
+  return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+  unsigned mtu = 0;
+
+  InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+  Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+  if (interface) {
+    mtu = interfaceGetMTU(interface);
+  }
+
+  interfaceSetDestroy(&interfaceSet);
+
+  return mtu;
+}
diff --git a/hicn-light/src/platforms/darwin/system.c b/hicn-light/src/platforms/darwin/system.c
new file mode 100755 (executable)
index 0000000..b8ef80c
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <ifaddrs.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <sys/socket.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/interfaceSet.h>
+
+#include <src/core/forwarder.h>
+#include <src/core/system.h>
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+  InterfaceSet *set = interfaceSetCreate();
+
+  // this is the dynamically allocated head of the list
+  struct ifaddrs *ifaddr;
+  int failure = getifaddrs(&ifaddr);
+  parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+  struct ifaddrs *next;
+  for (next = ifaddr; next != NULL; next = next->ifa_next) {
+    if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+      continue;
+    }
+
+    // This assumes the LINK address comes first so we can get the MTU
+    // when the interface is created.
+
+    Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+    if (iface == NULL) {
+      unsigned mtu = 0;
+
+      if (next->ifa_data != NULL) {
+        struct if_data *ifdata = (struct if_data *)next->ifa_data;
+        mtu = ifdata->ifi_mtu;
+      }
+
+      iface = interfaceCreate(
+          next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+          next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+      interfaceSetAdd(set, iface);
+    }
+
+    int family = next->ifa_addr->sa_family;
+    switch (family) {
+      case AF_INET: {
+        Address *address =
+            addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_INET6: {
+        Address *address =
+            addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_LINK: {
+        struct sockaddr_dl *addr_dl = (struct sockaddr_dl *)next->ifa_addr;
+
+        // skip links with 0-length address
+        if (addr_dl->sdl_alen > 0) {
+          // addr_dl->sdl_data[12] contains the interface name followed by the
+          // MAC address, so need to offset in to the array past the interface
+          // name.
+          Address *address = addressCreateFromLink(
+              (uint8_t *)&addr_dl->sdl_data[addr_dl->sdl_nlen],
+              addr_dl->sdl_alen);
+          interfaceAddAddress(iface, address);
+        }
+        break;
+      }
+    }
+  }
+
+  freeifaddrs(ifaddr);
+
+  return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+                                    const char *interfaceName) {
+  Address *linkAddress = NULL;
+
+  InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+  Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+  if (interface) {
+    const AddressList *addressList = interfaceGetAddresses(interface);
+
+    size_t length = addressListLength(addressList);
+    for (size_t i = 0; i < length && !linkAddress; i++) {
+      const Address *a = addressListGetItem(addressList, i);
+      if (addressGetType(a) == ADDR_LINK) {
+        linkAddress = addressCopy(a);
+      }
+    }
+  }
+
+  interfaceSetDestroy(&interfaceSet);
+
+  return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+  unsigned mtu = 0;
+
+  if (interfaceName) {
+    InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+    Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+    if (interface) {
+      mtu = interfaceGetMTU(interface);
+    }
+
+    interfaceSetDestroy(&interfaceSet);
+  }
+  return mtu;
+}
diff --git a/hicn-light/src/platforms/linux/system.c b/hicn-light/src/platforms/linux/system.c
new file mode 100755 (executable)
index 0000000..fcf13be
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017-2019 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 <errno.h>
+#include <ifaddrs.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//#define __USE_MISC
+#include <net/if.h>
+
+// to get the list of arp types
+#include <net/if_arp.h>
+
+// for the mac address
+#include <netpacket/packet.h>
+
+#include <src/core/forwarder.h>
+#include <src/utils/interfaceSet.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/addressList.h>
+
+/**
+ * Returns the MTU for a named interface
+ *
+ * On linux, we get the MTU by opening a socket and reading SIOCGIFMTU
+ *
+ * @param [in] ifname Interface name (e.g. "eth0")
+ *
+ * @retval number The MTU in bytes
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+static int getMtu(const char *ifname) {
+  struct ifreq ifr;
+  int fd;
+
+  fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+  strcpy(ifr.ifr_name, ifname);
+  ioctl(fd, SIOCGIFMTU, &ifr);
+
+  close(fd);
+  return ifr.ifr_mtu;
+}
+
+InterfaceSet *system_Interfaces(Forwarder *forwarder) {
+  InterfaceSet *set = interfaceSetCreate();
+
+  Logger *logger = forwarder_GetLogger(forwarder);
+
+  // this is the dynamically allocated head of the list
+  struct ifaddrs *ifaddr;
+  int failure = getifaddrs(&ifaddr);
+  parcAssertFalse(failure, "Error getifaddrs: (%d) %s", errno, strerror(errno));
+
+  struct ifaddrs *next;
+  for (next = ifaddr; next != NULL; next = next->ifa_next) {
+    if ((next->ifa_addr == NULL) || ((next->ifa_flags & IFF_UP) == 0)) {
+      continue;
+    }
+
+    Interface *iface = interfaceSetGetByName(set, next->ifa_name);
+    if (iface == NULL) {
+      unsigned mtu = (unsigned)getMtu(next->ifa_name);
+
+      iface = interfaceCreate(
+          next->ifa_name, forwarder_GetNextConnectionId(forwarder),
+          next->ifa_flags & IFF_LOOPBACK, next->ifa_flags & IFF_MULTICAST, mtu);
+
+      interfaceSetAdd(set, iface);
+    }
+
+    int family = next->ifa_addr->sa_family;
+    switch (family) {
+      case AF_INET: {
+        Address *address =
+            addressCreateFromInet((struct sockaddr_in *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_INET6: {
+        Address *address =
+            addressCreateFromInet6((struct sockaddr_in6 *)next->ifa_addr);
+        interfaceAddAddress(iface, address);
+        break;
+      }
+
+      case AF_PACKET: {
+        struct sockaddr_ll *addr_ll = (struct sockaddr_ll *)next->ifa_addr;
+
+        if (logger_IsLoggable(logger, LoggerFacility_IO, PARCLogLevel_Debug)) {
+          logger_Log(logger, LoggerFacility_IO, PARCLogLevel_Debug, __func__,
+                     "sockaddr_ll family %d proto %d ifindex %d hatype %d "
+                     "pkttype %d halen %d",
+                     addr_ll->sll_family, addr_ll->sll_protocol,
+                     addr_ll->sll_ifindex, addr_ll->sll_hatype,
+                     addr_ll->sll_pkttype, addr_ll->sll_halen);
+        }
+
+        switch (addr_ll->sll_hatype) {
+          // list of the ARP hatypes we can extract a MAC address from
+          case ARPHRD_ETHER:
+          // fallthrough
+          case ARPHRD_IEEE802: {
+            Address *address = addressCreateFromLink(
+                (uint8_t *)addr_ll->sll_addr, addr_ll->sll_halen);
+            interfaceAddAddress(iface, address);
+            break;
+          }
+          default:
+            break;
+        }
+
+        break;
+      }
+    }
+  }
+
+  freeifaddrs(ifaddr);
+  return set;
+}
+
+Address *system_GetMacAddressByName(Forwarder *forwarder,
+                                    const char *interfaceName) {
+  Address *linkAddress = NULL;
+
+  InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+  Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+  if (interface) {
+    const AddressList *addressList = interfaceGetAddresses(interface);
+
+    size_t length = addressListLength(addressList);
+    for (size_t i = 0; i < length && !linkAddress; i++) {
+      const Address *a = addressListGetItem(addressList, i);
+      if (addressGetType(a) == ADDR_LINK) {
+        linkAddress = addressCopy(a);
+      }
+    }
+  }
+
+  interfaceSetDestroy(&interfaceSet);
+
+  return linkAddress;
+}
+
+unsigned system_InterfaceMtu(Forwarder *forwarder, const char *interfaceName) {
+  unsigned mtu = 0;
+
+  InterfaceSet *interfaceSet = system_Interfaces(forwarder);
+  Interface *interface = interfaceSetGetByName(interfaceSet, interfaceName);
+
+  if (interface) {
+    mtu = interfaceGetMTU(interface);
+  }
+
+  interfaceSetDestroy(&interfaceSet);
+
+  return mtu;
+}
diff --git a/hicn-light/src/processor/CMakeLists.txt b/hicn-light/src/processor/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b7eeabe
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/pit.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/fib.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/pitVerdict.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/hashTableFunction.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/fib.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/fibEntry.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/fibEntryList.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/messageProcessor.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/pit.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/pitEntry.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/pitStandard.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/processor/fib.c b/hicn-light/src/processor/fib.c
new file mode 100755 (executable)
index 0000000..33d31fd
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/processor/fib.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#define NULL_POS 128
+#define MSB_POS 127
+
+struct node;
+typedef struct node FibNode;
+
+struct node {
+  FibNode *left;
+  FibNode *right;
+  FibEntry *entry;
+  unsigned pos;
+};
+
+struct fib {
+  FibNode *root;
+  unsigned size;
+};
+
+// =====================================================
+// Public API
+
+FibNode *_createNode(FibNode *left, FibNode *right, FibEntry *entry,
+                     unsigned pos) {
+  FibNode *n = parcMemory_AllocateAndClear(sizeof(FibNode));
+  parcAssertNotNull(n, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(FibNode));
+
+  n->left = left;
+  n->right = right;
+  n->entry = entry;
+  n->pos = pos;
+
+  return n;
+}
+
+FIB *fib_Create() {
+  FIB *hicnFib = parcMemory_AllocateAndClear(sizeof(FIB));
+  parcAssertNotNull(hicnFib, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(FIB));
+
+  hicnFib->root =
+      _createNode(NULL, NULL, NULL,
+                  NULL_POS);  // the pos will decrease going down in the trie
+  hicnFib->root->left = hicnFib->root;
+  hicnFib->root->right = hicnFib->root;
+
+  hicnFib->size = 0;
+
+  return hicnFib;
+}
+
+void _destroyNode(FibNode *n) {
+  fibEntry_Release(&n->entry);
+  parcMemory_Deallocate((void **)&n);
+  n = NULL;
+}
+
+void _destroyFib(FIB *fib) {
+  // XXX
+  // to be done
+  return;
+}
+
+void fib_Destroy(FIB **fibPtr) {
+  parcAssertNotNull(fibPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*fibPtr, "Parameter must dereference to non-null pointer");
+
+  FIB *fib = *fibPtr;
+
+  _destroyFib(fib);
+  parcMemory_Deallocate((void **)&fib);
+  *fibPtr = NULL;
+}
+
+void fib_Add(FIB *fib, FibEntry *entry) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  parcAssertNotNull(entry, "Parameter must be non-null");
+
+  NameBitvector *name = name_GetContentName(fibEntry_GetPrefix(entry));
+
+  // search the name
+  FibNode *prev = fib->root;
+  FibNode *curr;
+
+  if (nameBitvector_testBit(name, MSB_POS)) {
+    curr = fib->root->right;
+  } else {
+    curr = fib->root->left;
+  }
+
+  while (prev->pos > curr->pos) {
+    prev = curr;
+    if (nameBitvector_testBit(name, curr->pos)) {
+      curr = curr->right;
+    } else {
+      curr = curr->left;
+    }
+  }
+
+  if (curr->entry != NULL &&
+      nameBitvector_Equals(
+          name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+    // there is already an entry with this name
+    // do nothing. Before call ADD we should check
+    // if the node exists, and, in that case update it
+    return;
+  }
+
+  // if the name is not in the FIB search for the first different bit between
+  // the new name to add and the node found in the trie
+  uint8_t pos = MSB_POS;
+  if (curr->entry != NULL)
+    pos = nameBitvector_firstDiff(
+        name, name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+
+  // reset pointer and search the insertion point
+  prev = fib->root;
+  if (nameBitvector_testBit(name, MSB_POS))
+    curr = fib->root->right;
+  else
+    curr = fib->root->left;
+
+  while (prev->pos > curr->pos && curr->pos > pos) {
+    prev = curr;
+    if (nameBitvector_testBit(name, curr->pos)) {
+      curr = curr->right;
+    } else {
+      curr = curr->left;
+    }
+  }
+
+  // insert the node
+  fib->size++;
+  FibNode *n = _createNode(NULL, NULL, entry, pos);
+
+  if (nameBitvector_testBit(name, pos)) {
+    n->left = curr;
+    n->right = n;
+  } else {
+    n->left = n;
+    n->right = curr;
+  }
+
+  uint8_t new_pos = prev->pos;
+  if (new_pos == NULL_POS) new_pos = MSB_POS;
+
+  if (nameBitvector_testBit(name, new_pos)) {
+    prev->right = n;
+  } else {
+    prev->left = n;
+  }
+}
+
+FibEntry *fib_Contains(const FIB *fib, const Name *prefix) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  parcAssertNotNull(prefix, "Parameter must be non-null");
+
+  NameBitvector *name = name_GetContentName(prefix);
+
+  // this is the same as the first part of the add function
+  // we cannnot call this function inside the add because
+  // we need the pointer prev and curr for the insertion
+
+  FibNode *prev = fib->root;
+  FibNode *curr;
+
+  if (nameBitvector_testBit(name, MSB_POS))
+    curr = fib->root->right;
+  else
+    curr = fib->root->left;
+
+  while (prev->pos > curr->pos) {
+    prev = curr;
+
+    if (nameBitvector_testBit(name, curr->pos)) {
+      curr = curr->right;
+    } else {
+      curr = curr->left;
+    }
+  }
+
+  if (curr->entry != NULL &&
+      nameBitvector_Equals(
+          name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+    return curr->entry;
+  } else {
+    return NULL;
+  }
+}
+
+void _removeNode(FIB *fib, const Name *prefix) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  parcAssertNotNull(prefix, "Parameter must be non-null");
+
+  FibNode *grand = NULL;  // grandparent
+  FibNode *prev =
+      fib->root;  // parent: it will points to curr of the next hop in the trie
+  FibNode *curr;  // current node: the node to remove
+
+  NameBitvector *name = name_GetContentName(prefix);
+
+  if (nameBitvector_testBit(name, MSB_POS)) {
+    curr = fib->root->right;
+  } else {
+    curr = fib->root->left;
+  }
+
+  // in the first loop we always search the node to remove
+  while (prev->pos > curr->pos) {
+    grand = prev;
+    prev = curr;
+
+    if (nameBitvector_testBit(name, curr->pos)) {
+      curr = curr->right;
+    } else {
+      curr = curr->left;
+    }
+  }
+
+  if (!nameBitvector_Equals(
+          name, name_GetContentName(fibEntry_GetPrefix(curr->entry)))) {
+    // the node does not exists
+    return;
+  }
+
+  // search for the real parent of curr (*tmpPrev)
+  // prev points to curr or next node in the trie
+  // this is because of the loopback links
+
+  FibNode *tmpPrev = fib->root;
+  FibNode *tmpCurr;
+
+  if (nameBitvector_testBit(name, MSB_POS)) {
+    tmpCurr = fib->root->right;
+  } else {
+    tmpCurr = fib->root->left;
+  }
+
+  // here we compare pointer so we are sure to stop at the right potion
+  while (tmpCurr != curr) {
+    tmpPrev = tmpCurr;
+
+    if (nameBitvector_testBit(name, tmpCurr->pos)) {
+      tmpCurr = tmpCurr->right;
+    } else {
+      tmpCurr = tmpCurr->left;
+    }
+  }
+
+  // now curr is the node to remove and tmpPrev is the real parent of curr
+
+  if (curr == prev) {
+    // this is the case where curr is a leaf node
+    FibNode *next;  // child of curr (the loopback)
+
+    if (nameBitvector_testBit(name, curr->pos)) {
+      next = curr->left;
+    } else {
+      next = curr->right;
+    }
+
+    if (nameBitvector_testBit(name, tmpPrev->pos)) {
+      tmpPrev->right = next;
+    } else {
+      tmpPrev->left = next;
+    }
+
+  } else {
+    // curr is an internal node
+    FibNode *next;  // child of prev (loopback)
+
+    if (nameBitvector_testBit(name, prev->pos)) {
+      next = prev->left;
+    } else {
+      next = prev->right;
+    }
+
+    if (nameBitvector_testBit(name, grand->pos)) {
+      grand->right = next;
+    } else {
+      grand->left = next;
+    }
+
+    if (nameBitvector_testBit(name, tmpPrev->pos)) {
+      tmpPrev->right = prev;
+    } else {
+      tmpPrev->left = prev;
+    }
+
+    prev->left = curr->left;
+    prev->right = curr->right;
+    prev->pos = curr->pos;
+  }
+
+  fib->size--;
+  _destroyNode(curr);
+}
+
+void fib_Remove(FIB *fib, const Name *name, unsigned connId) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  parcAssertNotNull(name, "Parameter must be non-null");
+
+  FibEntry *entry = fib_Contains(fib, name);
+
+  if (entry == NULL) {
+    return;
+  }
+
+  fibEntry_RemoveNexthopByConnectionId(entry, connId);
+  if (fibEntry_NexthopCount(entry) == 0) {
+    _removeNode(fib, name);
+  }
+}
+
+void _removeConnectionId(FibNode *n, unsigned pos, unsigned connectionId,
+                         FibEntryList *list) {
+  if (n->pos < pos) {
+    fibEntry_RemoveNexthopByConnectionId(n->entry, connectionId);
+    if (fibEntry_NexthopCount(n->entry) == 0) {
+      fibEntryList_Append(list, n->entry);
+    }
+    _removeConnectionId(n->left, n->pos, connectionId, list);
+    _removeConnectionId(n->right, n->pos, connectionId, list);
+  }
+}
+
+void fib_RemoveConnectionId(FIB *fib, unsigned connectionId) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+
+  // 1 - we vist the tree to remove the connection id
+  // 2 - during the visit we collect the fib entry with 0 nexthop
+  // 3 - after the visit we remove this entries
+
+  FibEntryList *list = fibEntryList_Create();
+
+  _removeConnectionId(fib->root->left, fib->root->pos, connectionId, list);
+  _removeConnectionId(fib->root->right, fib->root->pos, connectionId, list);
+
+  for (int i = 0; i < fibEntryList_Length(list); i++) {
+    _removeNode(fib, fibEntry_GetPrefix(fibEntryList_Get(list, i)));
+  }
+
+  fibEntryList_Destroy(&list);
+}
+
+size_t fib_Length(const FIB *fib) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  return fib->size;
+}
+
+FibEntry *fib_Match(const FIB *fib, const Message *interestMessage) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+  parcAssertNotNull(interestMessage, "Parameter must be non-null");
+
+  NameBitvector *name = name_GetContentName(message_GetName(interestMessage));
+
+  FibNode *prev = fib->root;
+  FibNode *curr;
+
+  FibNode *match = NULL;
+  unsigned len = 0;
+
+  if (nameBitvector_testBit(name, MSB_POS))
+    curr = fib->root->right;
+  else
+    curr = fib->root->left;
+
+  while (prev->pos > curr->pos) {
+    prev = curr;
+
+    if (curr->entry != NULL) {
+      if (nameBitvector_StartsWith(
+              name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) &&
+          nameBitvector_GetLength(
+              name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) {
+        match = curr;
+        len = nameBitvector_GetLength(
+            name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+      }
+    }
+
+    if (nameBitvector_testBit(name, curr->pos))
+      curr = curr->right;
+    else
+      curr = curr->left;
+  }
+
+  if (curr->entry != NULL) {
+    if (nameBitvector_StartsWith(
+            name, name_GetContentName(fibEntry_GetPrefix(curr->entry))) &&
+        nameBitvector_GetLength(
+            name_GetContentName(fibEntry_GetPrefix(curr->entry))) > len) {
+      match = curr;
+      len = nameBitvector_GetLength(
+          name_GetContentName(fibEntry_GetPrefix(curr->entry)));
+    }
+  }
+
+  if (match != NULL && match->entry != NULL) {
+    return match->entry;
+  } else {
+    return NULL;
+  }
+}
+
+void _collectFibEntries(FibNode *n, int pos, FibEntryList *list) {
+  if (n->pos < pos) {
+    fibEntryList_Append(list, n->entry);
+    _collectFibEntries(n->left, n->pos, list);
+    _collectFibEntries(n->right, n->pos, list);
+  }
+}
+
+FibEntryList *fib_GetEntries(const FIB *fib) {
+  parcAssertNotNull(fib, "Parameter must be non-null");
+
+  FibEntryList *list = fibEntryList_Create();
+
+  _collectFibEntries(fib->root->left, fib->root->pos, list);
+  _collectFibEntries(fib->root->right, fib->root->pos, list);
+
+  return list;
+}
diff --git a/hicn-light/src/processor/fib.h b/hicn-light/src/processor/fib.h
new file mode 100755 (executable)
index 0000000..4409419
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017-2019 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 fib_h
+#define fib_h
+
+#include <src/core/message.h>
+#include <src/core/name.h>
+#include <src/processor/fibEntry.h>
+#include <src/processor/fibEntryList.h>
+
+struct fib;
+typedef struct fib FIB;
+
+FIB *fib_Create();
+
+void fib_Destroy(FIB **fibPtr);
+
+void fib_Add(FIB *fib, FibEntry *node);
+
+FibEntry *fib_Contains(const FIB *fib, const Name *prefix);
+
+void fib_Remove(FIB *fib, const Name *prefix, unsigned connId);
+
+void fib_RemoveConnectionId(FIB *fib, unsigned connectionId);
+
+FibEntry *fib_Match(const FIB *fib, const Message *interestMessage);
+
+size_t fib_Length(const FIB *fib);
+
+FibEntryList *fib_GetEntries(const FIB *fib);
+#endif  // fib_h
diff --git a/hicn-light/src/processor/fibEntry.c b/hicn-light/src/processor/fibEntry.c
new file mode 100755 (executable)
index 0000000..bb87703
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/core/numberSet.h>
+#include <src/processor/fibEntry.h>
+
+#include <src/core/nameBitvector.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/rnd.h>
+#include <src/strategies/rndSegment.h>
+#include <src/strategies/strategyImpl.h>
+#ifdef WITH_MAPME
+#include <parc/algol/parc_HashMap.h>
+#include <src/core/ticks.h>
+#endif /* WITH_MAPME */
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/commands.h>
+
+struct fib_entry {
+  Name *name;
+  unsigned refcount;
+  StrategyImpl *fwdStrategy;
+#ifdef WITH_MAPME
+  void *userData;
+  void (*userDataRelease)(void **userData);
+#endif /* WITH_MAPME */
+};
+
+FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy) {
+  FibEntry *fibEntry = parcMemory_AllocateAndClear(sizeof(FibEntry));
+  parcAssertNotNull(fibEntry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(FibEntry));
+  fibEntry->name = name_Acquire(name);
+
+  if (fwdStrategy) {
+    switch (fwdStrategy) {
+      case SET_STRATEGY_LOADBALANCER:
+        fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+        break;
+
+      case SET_STRATEGY_RANDOM_PER_DASH_SEGMENT:
+        fibEntry->fwdStrategy = strategyRndSegment_Create();
+        break;
+
+      case SET_STRATEGY_LOADBALANCER_WITH_DELAY:
+        fibEntry->fwdStrategy = strategyLoadBalancerWithPD_Create();
+        break;
+
+      default:
+        // LB is the defualt strategy
+        fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+        // the LB strategy is the default one
+        // other strategies can be set using the appropiate function
+        break;
+    }
+
+  } else {
+    fibEntry->fwdStrategy = strategyLoadBalancer_Create();
+  }
+
+  fibEntry->refcount = 1;
+
+#ifdef WITH_MAPME
+  fibEntry->userData = NULL;
+  fibEntry->userDataRelease = NULL;
+#endif /* WITH_MAPME */
+
+  return fibEntry;
+}
+
+FibEntry *fibEntry_Acquire(const FibEntry *fibEntry) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  FibEntry *copy = (FibEntry *)fibEntry;
+  copy->refcount++;
+  return copy;
+}
+
+void fibEntry_Release(FibEntry **fibEntryPtr) {
+  FibEntry *fibEntry = *fibEntryPtr;
+  parcAssertTrue(fibEntry->refcount > 0, "Illegal state: refcount is 0");
+  fibEntry->refcount--;
+  if (fibEntry->refcount == 0) {
+    name_Release(&fibEntry->name);
+    fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy));
+#ifdef WITH_MAPME
+    if (fibEntry->userData) {
+      fibEntry->userDataRelease(&fibEntry->userData);
+    }
+#endif /* WITH_MAPME */
+    parcMemory_Deallocate((void **)&fibEntry);
+  }
+  *fibEntryPtr = NULL;
+}
+
+void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy) {
+  StrategyImpl *fwdStrategyImpl;
+
+  switch (strategy) {
+    case SET_STRATEGY_LOADBALANCER:
+      fwdStrategyImpl = strategyLoadBalancer_Create();
+      break;
+
+    case SET_STRATEGY_RANDOM_PER_DASH_SEGMENT:
+      fwdStrategyImpl = strategyRndSegment_Create();
+      break;
+
+    case SET_STRATEGY_LOADBALANCER_WITH_DELAY:
+      fwdStrategyImpl = strategyLoadBalancerWithPD_Create();
+      break;
+
+    default:
+      // LB is the defualt strategy
+      fwdStrategyImpl = strategyLoadBalancer_Create();
+      // the LB strategy is the default one
+      // other strategies can be set using the appropiate function
+      break;
+  }
+
+  const NumberSet *nexthops = fibEntry_GetNexthops(fibEntry);
+  unsigned size = fibEntry_NexthopCount(fibEntry);
+  for (unsigned i = 0; i < size; i++) {
+    fwdStrategyImpl->addNexthop(fwdStrategyImpl,
+                                numberSet_GetItem(nexthops, i));
+  }
+  fibEntry->fwdStrategy->destroy(&(fibEntry->fwdStrategy));
+  fibEntry->fwdStrategy = fwdStrategyImpl;
+}
+void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->fwdStrategy->addNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry,
+                                          unsigned connectionId) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->fwdStrategy->removeNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+size_t fibEntry_NexthopCount(const FibEntry *fibEntry) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  return fibEntry->fwdStrategy->countNexthops(fibEntry->fwdStrategy);
+}
+
+const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  return fibEntry->fwdStrategy->returnNexthops(fibEntry->fwdStrategy);
+}
+
+const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy(
+    const FibEntry *fibEntry, const Message *interestMessage) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  return fibEntry->fwdStrategy->lookupNexthop(fibEntry->fwdStrategy,
+                                              interestMessage);
+}
+
+void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry,
+                                   const NumberSet *egressId,
+                                   const Message *objectMessage, Ticks rtt) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->fwdStrategy->receiveObject(fibEntry->fwdStrategy, egressId,
+                                       objectMessage, rtt);
+}
+
+void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->fwdStrategy->onTimeout(fibEntry->fwdStrategy, egressId);
+}
+
+Name *fibEntry_GetPrefix(const FibEntry *fibEntry) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  return fibEntry->name;
+  // return metisName_Acquire(fibEntry->name);
+}
+
+strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry) {
+  return fibEntry->fwdStrategy->getStrategy(fibEntry->fwdStrategy);
+}
+
+StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry) {
+  return fibEntry->fwdStrategy;
+}
+
+#ifdef WITH_MAPME
+
+void fibEntry_AddNexthopByConnectionId(FibEntry *fibEntry,
+                                       unsigned connectionId) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->fwdStrategy->addNexthop(fibEntry->fwdStrategy, connectionId);
+}
+
+void *fibEntry_getUserData(const FibEntry *fibEntry) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  return fibEntry->userData;
+}
+
+void fibEntry_setUserData(FibEntry *fibEntry, const void *userData,
+                          void (*userDataRelease)(void **)) {
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  fibEntry->userData = (void *)userData;
+  fibEntry->userDataRelease = userDataRelease;
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/processor/fibEntry.h b/hicn-light/src/processor/fibEntry.h
new file mode 100755 (executable)
index 0000000..3bcac38
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file fibEntry.h
+ * @brief A forwarding entry in the FIB table
+ *
+ * A Forwarding Information Base (FIB) entry (FibEntry) is a
+ * set of nexthops for a name.  It also indicates the forwarding strategy.
+ *
+ * Each nexthop contains the ConnectionId assocaited with it.  This could be
+ * something specific like a MAC address or point-to-point tunnel.  Or, it
+ * could be something general like a MAC group address or ip multicast overlay.
+ *
+ * See strategy.h for a description of forwarding strategies.
+ * In short, a strategy is the algorithm used to select one or more nexthops
+ * from the set of available nexthops.
+ *
+ * Each nexthop also contains a void* to a forwarding strategy data container.
+ * This allows a strategy to keep proprietary information about each nexthop.
+ *
+ *
+ */
+
+#ifndef fibEntry_h
+#define fibEntry_h
+
+#include <src/core/name.h>
+#include <src/strategies/strategyImpl.h>
+
+#ifdef WITH_MAPME
+#include <parc/algol/parc_EventTimer.h>
+#include <parc/algol/parc_Iterator.h>
+#endif /* WITH_MAPME */
+
+struct fib_entry;
+typedef struct fib_entry FibEntry;
+
+FibEntry *fibEntry_Create(Name *name, strategy_type fwdStrategy);
+
+/**
+ * Decrements the reference count by one, and destroys the memory after last
+ * release
+ *
+ */
+void fibEntry_Release(FibEntry **fibEntryPtr);
+
+/**
+ * Returns a reference counted copy of the fib entry
+ *
+ * The reference count is increased by one.  The returned value must be
+ * released via fibEnty_Release().
+ *
+ * @param [in] fibEntry An allocated FibEntry
+ *
+ * @return non-null A reference counted copy of the fibEntry
+ *
+ */
+FibEntry *fibEntry_Acquire(const FibEntry *fibEntry);
+
+void fibEntry_SetStrategy(FibEntry *fibEntry, strategy_type strategy);
+
+void fibEntry_AddNexthop(FibEntry *fibEntry, unsigned connectionId);
+
+void fibEntry_RemoveNexthopByConnectionId(FibEntry *fibEntry,
+                                          unsigned connectionId);
+
+size_t fibEntry_NexthopCount(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_GetNexthops
+ * @abstract Returns the nexthop set of the FIB entry.  You must Acquire if it
+ * will be saved.
+ * @discussion
+ *   Returns the next hop set for the FIB entry.
+ */
+const NumberSet *fibEntry_GetNexthops(const FibEntry *fibEntry);
+
+const NumberSet *fibEntry_GetNexthopsFromForwardingStrategy(
+    const FibEntry *fibEntry, const Message *interestMessage);
+
+void fibEntry_ReceiveObjectMessage(const FibEntry *fibEntry,
+                                   const NumberSet *egressId,
+                                   const Message *objectMessage, Ticks rtt);
+
+void fibEntry_OnTimeout(const FibEntry *fibEntry, const NumberSet *egressId);
+
+strategy_type fibEntry_GetFwdStrategyType(const FibEntry *fibEntry);
+
+StrategyImpl *fibEntry_GetFwdStrategy(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_GetPrefix
+ * @abstract Returns a copy of the prefix.
+ * @return A reference counted copy that you must destroy
+ */
+Name *fibEntry_GetPrefix(const FibEntry *fibEntry);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function fibEntry_AddNexthopByConnectionId
+ * @abstract Adds a next hop directly from the connection id.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @return The sequence number stored in the FIB entry.
+ */
+void fibEntry_AddNexthopByConnectionId(FibEntry *fibEntry,
+                                       unsigned connectionId);
+
+/**
+ * @function fibEntry_getUserData
+ * @abstract Returns user data associated to the FIB entry.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @return User data as a void pointer
+ */
+void *fibEntry_getUserData(const FibEntry *fibEntry);
+
+/**
+ * @function fibEntry_getUserData
+ * @abstract Associates user data and release callback to a FIB entry.
+ * @param [in] fibEntry - Pointer to the FIB entry.
+ * @param [in] userData - Generic pointer to user data
+ * @param [in@ userDataRelease - Callback used to release user data upon change
+ *       of FIB entry removal.
+ */
+void fibEntry_setUserData(FibEntry *fibEntry, const void *userData,
+                          void (*userDataRelease)(void **));
+
+#endif /* WITH_MAPME */
+
+#endif  // fibEntry_h
diff --git a/hicn-light/src/processor/fibEntryList.c b/hicn-light/src/processor/fibEntryList.c
new file mode 100755 (executable)
index 0000000..2221fa6
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/fibEntryList.h>
+
+struct fib_entry_list {
+  PARCArrayList *listOfFibEntries;
+};
+
+static void fibEntryList_ListDestroyer(void **voidPtr) {
+  FibEntry **entryPtr = (FibEntry **)voidPtr;
+  fibEntry_Release(entryPtr);
+}
+
+FibEntryList *fibEntryList_Create() {
+  FibEntryList *fibEntryList =
+      parcMemory_AllocateAndClear(sizeof(FibEntryList));
+  parcAssertNotNull(fibEntryList,
+                    "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(FibEntryList));
+  fibEntryList->listOfFibEntries =
+      parcArrayList_Create(fibEntryList_ListDestroyer);
+  return fibEntryList;
+}
+
+void fibEntryList_Destroy(FibEntryList **listPtr) {
+  parcAssertNotNull(listPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*listPtr, "Parameter must dereference to non-null pointer");
+
+  FibEntryList *list = *listPtr;
+  parcArrayList_Destroy(&list->listOfFibEntries);
+  parcMemory_Deallocate((void **)&list);
+  listPtr = NULL;
+}
+
+void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry) {
+  parcAssertNotNull(list, "Parameter list must be non-null pointer");
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null pointer");
+
+  FibEntry *copy = fibEntry_Acquire(fibEntry);
+  parcArrayList_Add(list->listOfFibEntries, copy);
+}
+
+size_t fibEntryList_Length(const FibEntryList *list) {
+  parcAssertNotNull(list, "Parameter list must be non-null pointer");
+  return parcArrayList_Size(list->listOfFibEntries);
+}
+
+const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index) {
+  parcAssertNotNull(list, "Parameter list must be non-null pointer");
+  FibEntry *entry = parcArrayList_Get(list->listOfFibEntries, index);
+  return entry;
+}
diff --git a/hicn-light/src/processor/fibEntryList.h b/hicn-light/src/processor/fibEntryList.h
new file mode 100755 (executable)
index 0000000..0f60664
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file fibEntryList.h
+ * @brief A typesafe list of FibEntry
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+#ifndef fibEntryList_h
+#define fibEntryList_h
+
+#include <src/processor/fibEntry.h>
+
+struct fib_entry_list;
+typedef struct fib_entry_list FibEntryList;
+
+/**
+ * Creates an emtpy FIB entry list
+ *
+ * Must be destroyed with fibEntryList_Destroy.
+ *
+ * @retval non-null An allocated FibEntryList
+ * @retval null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+FibEntryList *fibEntryList_Create(void);
+
+/**
+ * @function FibEntryList_Detroy
+ * @abstract Destroys the list and all entries.
+ * @discussion
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ */
+void fibEntryList_Destroy(FibEntryList **listPtr);
+
+/**
+ * @function fibEntryList_Append
+ * @abstract Will store a reference counted copy of the entry.
+ * @discussion
+ *   Will create and store a reference counted copy.  You keep ownership
+ *   of the parameter <code>fibEntry</code>.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+void fibEntryList_Append(FibEntryList *list, FibEntry *fibEntry);
+
+/**
+ * Returns the number of entries in the list
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] list An allocated FibEntryList
+ *
+ * @retval number The number of entries in the list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t fibEntryList_Length(const FibEntryList *list);
+
+/**
+ * @function fibEntryList_Get
+ * @abstract Gets an element.  This is the internal reference, do not destroy.
+ * @discussion
+ *   Returns an internal reference from the list.  You must not destroy it.
+ *   Will assert if you go off the end of the list.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ */
+const FibEntry *fibEntryList_Get(const FibEntryList *list, size_t index);
+#endif  // fibEntryList_h
diff --git a/hicn-light/src/processor/hashTableFunction.c b/hicn-light/src/processor/hashTableFunction.c
new file mode 100755 (executable)
index 0000000..6e70ef9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/message.h>
+#include <src/processor/hashTableFunction.h>
+
+#include <parc/assert/parc_Assert.h>
+
+// ======================================================================
+// Hash table key functions
+// We use a Message as the key data type
+
+bool hashTableFunction_MessageNameEquals(const void *messageA,
+                                         const void *messageB) {
+  const Message *a = (const Message *)messageA;
+  const Message *b = (const Message *)messageB;
+
+  return name_Equals(message_GetName(a), message_GetName(b));
+}
+
+HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA) {
+  const Message *message = (const Message *)messageA;
+  Name *name = message_GetName(message);
+
+  // we want the cumulative hash for the whole name
+  uint32_t hash = name_HashCode(name);
+
+  return hash;
+}
\ No newline at end of file
diff --git a/hicn-light/src/processor/hashTableFunction.h b/hicn-light/src/processor/hashTableFunction.h
new file mode 100755 (executable)
index 0000000..eb99890
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hashTableFunction.h
+ * @brief These functions are used in PARCHashCodeTables by the
+ * MatchingRulesTable and ContentStore and PIT. They perform the equality
+ * and has generation needed by the PARCHashCodeTable.
+ *
+ */
+#ifndef hashTableFunction_h
+#define hashTableFunction_h
+
+#include <parc/algol/parc_HashCodeTable.h>
+
+// ==========================================================
+// These functions operate on a message as the key in the HashTable.
+// The functions use void * rather than message instances in the function
+// signature because it is using generic has code tables from PARC Library
+
+/**
+ * Determine if the Names of two `message` instances are equal.
+ *
+ * The following equivalence relations on non-null `message` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x,
+ * `hashTableFunction_MessageNameEquals(x, x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `message_Equals(x, y)` must return true if and only if
+ *        `hashTableFunction_MessageNameEquals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `hashTableFunction_MessageNameEquals(x, y)` returns true and
+ *        `hashTableFunction_MessageNameEquals(y, z)` returns true,
+ *        then  `hashTableFunction_MessageNameEquals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `hashTableFunction_MessageNameEquals(x, y)` consistently
+ * return true or consistently return false.
+ *
+ *  * For any non-null reference value x,
+ * `hashTableFunction_MessageNameEquals(x, NULL)` must return false.
+ *
+ * @param a A pointer to a `message` instance.
+ * @param b A pointer to a `message` instance.
+ * @return true if the names of the two `message` instances are equal.
+ */
+bool hashTableFunction_MessageNameEquals(const void *messageA,
+                                         const void *messageB);
+
+/**
+ * @function hashTableFunction_NameHashCode
+ * @abstract Computes the hash of the entire name in a message
+ *
+ * @param messageA is a message
+ * @return A non-cryptographic hash of Name
+ */
+HashCodeType hashTableFunction_MessageNameHashCode(const void *messageA);
+#endif  // hashTableFunction_h
\ No newline at end of file
diff --git a/hicn-light/src/processor/matchingRulesTable.c b/hicn-light/src/processor/matchingRulesTable.c
new file mode 100755 (executable)
index 0000000..56e59c2
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/processor/hashTableFunction.h>
+#include <src/processor/matchingRulesTable.h>
+
+struct matching_rules_table {
+  // using this wrapper we can manatain multiple hash tables indexed in
+  // different ways
+  // for now we use only a table indexed by name
+
+  PARCHashCodeTable *tableByName;
+  PARCHashCodeTable_Destroyer dataDestroyer;
+};
+
+static PARCHashCodeTable *matchingRulesTable_GetTableForMessage(
+    const MatchingRulesTable *pit, const Message *interestMessage);
+
+// ======================================================================
+
+MatchingRulesTable *matchingRulesTable_Create(
+    PARCHashCodeTable_Destroyer dataDestroyer) {
+  size_t initialSize = 65535;
+
+  MatchingRulesTable *table =
+      parcMemory_AllocateAndClear(sizeof(MatchingRulesTable));
+  parcAssertNotNull(table, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(MatchingRulesTable));
+  table->dataDestroyer = dataDestroyer;
+
+  table->tableByName = parcHashCodeTable_Create_Size(
+      hashTableFunction_MessageNameEquals,
+      hashTableFunction_MessageNameHashCode, NULL, dataDestroyer, initialSize);
+
+  return table;
+}
+
+void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr) {
+  parcAssertNotNull(tablePtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*tablePtr,
+                    "Parameter must dereference to non-null pointer");
+
+  MatchingRulesTable *table = *tablePtr;
+
+  parcHashCodeTable_Destroy(&table->tableByName);
+
+  parcMemory_Deallocate((void **)&table);
+  *tablePtr = NULL;
+}
+
+void *matchingRulesTable_Get(const MatchingRulesTable *rulesTable,
+                             const Message *message) {
+  parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  PARCHashCodeTable *hashTable =
+      matchingRulesTable_GetTableForMessage(rulesTable, message);
+  return parcHashCodeTable_Get(hashTable, message);
+}
+
+PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table,
+                                           const Message *message) {
+  PARCArrayList *list = parcArrayList_Create_Capacity(NULL, NULL, 3);
+
+  void *dataByName = parcHashCodeTable_Get(table->tableByName, message);
+  if (dataByName) {
+    parcArrayList_Add(list, dataByName);
+  }
+
+  return list;
+}
+
+void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable,
+                                       const Message *message) {
+  parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  PARCHashCodeTable *hashTable =
+      matchingRulesTable_GetTableForMessage(rulesTable, message);
+  parcHashCodeTable_Del(hashTable, message);
+}
+
+void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable,
+                                      const Message *message) {
+  parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  parcHashCodeTable_Del(rulesTable->tableByName, message);
+}
+
+bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable,
+                                       Message *key, void *data) {
+  parcAssertNotNull(rulesTable, "Parameter rulesTable must be non-null");
+  parcAssertNotNull(key, "Parameter key must be non-null");
+  parcAssertNotNull(data, "Parameter data must be non-null");
+
+  PARCHashCodeTable *hashTable =
+      matchingRulesTable_GetTableForMessage(rulesTable, key);
+
+  bool success = parcHashCodeTable_Add(hashTable, key, data);
+
+  return success;
+}
+
+// ========================================================================================
+
+static PARCHashCodeTable *matchingRulesTable_GetTableForMessage(
+    const MatchingRulesTable *pit, const Message *interestMessage) {
+  PARCHashCodeTable *table;
+  table = pit->tableByName;
+
+  return table;
+}
diff --git a/hicn-light/src/processor/matchingRulesTable.h b/hicn-light/src/processor/matchingRulesTable.h
new file mode 100755 (executable)
index 0000000..96d0994
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @header matchingRulesTable
+ * @abstract A generic table (void *) that matches a Message
+ * @discussion
+ *     Matching is done based on Name
+ *
+ *     When used in the PIT, one calls
+ * <code>matchingRulesTable_AddToBestTable()</code> to add an interest to the
+ * "best" (i.e. most restrictive match) table, then calls
+ *     <code>matchingRulesTable_GetUnion()</code> on a content object to match
+ * against all of them.
+ *
+ *     When used in a ContentStore, one calls
+ * <code>matchingRulesTable_AddToAllTables()</code> to index a Content Object in
+ * all the tables.  one then calls <code>matchingRulesTable_Get()</code> with an
+ * Interest to do the "best" matching (i.e by hash first, then keyid, then just
+ * by name).
+ *
+ */
+
+#ifndef matchingRulesTable_h
+#define matchingRulesTable_h
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <src/core/message.h>
+
+struct matching_rules_table;
+typedef struct matching_rules_table MatchingRulesTable;
+
+/**
+ * Creates a MatchigRulesTable and specifies the function to call to de-allocate
+ * an entry
+ *
+ * The datadestroyer will be called when an entry is removed from a table. It
+ * may be NULL.
+ */
+MatchingRulesTable *matchingRulesTable_Create(
+    PARCHashCodeTable_Destroyer dataDestroyer);
+
+/**
+ * Destroys the table and removes all stored elements.
+ *
+ */
+void matchingRulesTable_Destroy(MatchingRulesTable **tablePtr);
+
+/**
+ * @function matchingRulesTable_Get
+ * @abstract Returns the data item that best matches the message.
+ * @discussion
+ *   Indexed by NameAndContentObjectHash, NameAndKeyId, and Name, in that order.
+ *
+ * @return NULL if nothing matches, otherwise the stored value
+ */
+void *matchingRulesTable_Get(const MatchingRulesTable *table,
+                             const Message *message);
+
+/**
+ * @function matchingRulesTable_GetUnion
+ * @abstract Returns matching data items from all index tables.
+ * @discussion
+ *   The PARCArrayList does not have an item destructor, so destroying it will
+ * not affect the underlying data.
+ *
+ * @return Will not be NULL, but may be empty
+ */
+PARCArrayList *matchingRulesTable_GetUnion(const MatchingRulesTable *table,
+                                           const Message *message);
+
+/**
+ * @function matchingRulesTable_Add
+ * @abstract Adds the data to the best table
+ * @discussion
+ *   The key must be derived from the data and destroyed when the data is
+ * destroyed.  Only the data destroyer is called.
+ *
+ *   No duplicates are allowed, will return false if not added.
+ *
+ * @return true if unique key and added, false if duplicate and no action taken.
+ */
+bool matchingRulesTable_AddToBestTable(MatchingRulesTable *rulesTable,
+                                       Message *key, void *data);
+
+/**
+ * @function matchingRulesTable_Remove
+ * @abstract Removes the matching entry from the best match table, calling the
+ * destroyer on the data.
+ */
+void matchingRulesTable_RemoveFromBest(MatchingRulesTable *rulesTable,
+                                       const Message *message);
+
+/**
+ * @function matchingRulesTable_RemoveFromAll
+ * @abstract Removes the message from all tables
+ */
+void matchingRulesTable_RemoveFromAll(MatchingRulesTable *rulesTable,
+                                      const Message *message);
+#endif  // matchingRulesTable_h
diff --git a/hicn-light/src/processor/messageProcessor.c b/hicn-light/src/processor/messageProcessor.c
new file mode 100755 (executable)
index 0000000..8c03ee7
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/processor/messageProcessor.h>
+
+#include <src/processor/fib.h>
+#include <src/processor/pitStandard.h>
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/content_store/contentStoreLRU.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/rnd.h>
+#include <src/strategies/rndSegment.h>
+#include <src/strategies/strategyImpl.h>
+
+#include <src/io/streamConnection.h>
+#include <src/io/udpListener.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/commands.h>
+#include <src/utils/utils.h>
+
+#include <src/utils/address.h>
+
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+typedef struct processor_stats {
+  uint32_t countReceived;
+  uint32_t countInterestsReceived;
+  uint32_t countObjectsReceived;
+
+  uint32_t countInterestsAggregated;
+
+  uint32_t countDropped;
+  uint32_t countInterestsDropped;
+  uint32_t countDroppedNoRoute;
+  uint32_t countDroppedNoReversePath;
+
+  uint32_t countDroppedConnectionNotFound;
+  uint32_t countObjectsDropped;
+
+  uint32_t countSendFailures;
+  uint32_t countInterestForwarded;
+  uint32_t countObjectsForwarded;
+  uint32_t countInterestsSatisfiedFromStore;
+
+  uint32_t countDroppedNoHopLimit;
+  uint32_t countDroppedZeroHopLimitFromRemote;
+  uint32_t countDroppedZeroHopLimitToRemote;
+} _ProcessorStats;
+
+struct message_processor {
+  Forwarder *forwarder;
+  Logger *logger;
+
+  PIT *pit;
+  ContentStoreInterface *contentStore;
+  FIB *fib;
+
+  bool store_in_cache;
+  bool serve_from_cache;
+
+  _ProcessorStats stats;
+};
+
+static void messageProcessor_Drop(MessageProcessor *processor,
+                                  Message *message);
+static void messageProcessor_ReceiveInterest(MessageProcessor *processor,
+                                             Message *interestMessage);
+static void messageProcessor_ReceiveContentObject(MessageProcessor *processor,
+                                                  Message *objectMessage);
+static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor,
+                                                   Message *message,
+                                                   const NumberSet *nexthops);
+
+static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor,
+                                                  Message *message,
+                                                  unsigned interfaceId);
+
+// ============================================================
+// Public API
+
+MessageProcessor *messageProcessor_Create(Forwarder *forwarder) {
+  size_t objectStoreSize =
+      configuration_GetObjectStoreSize(forwarder_GetConfiguration(forwarder));
+
+  MessageProcessor *processor =
+      parcMemory_AllocateAndClear(sizeof(MessageProcessor));
+  parcAssertNotNull(processor, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(MessageProcessor));
+  memset(processor, 0, sizeof(MessageProcessor));
+
+  processor->forwarder = forwarder;
+  processor->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+  processor->pit = pitStandard_Create(forwarder);
+
+  processor->fib = fib_Create();
+
+  if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "MessageProcessor %p created", (void *)processor);
+  }
+
+  ContentStoreConfig contentStoreConfig = {
+      .objectCapacity = objectStoreSize,
+  };
+
+  processor->contentStore =
+      contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+
+  // the two flags for the cache are set to true by default. If the cache
+  // is active it always work as expected unless the use modifies this
+  // values using controller
+  processor->store_in_cache = true;
+  processor->serve_from_cache = true;
+
+  return processor;
+}
+
+void messageProcessor_SetContentObjectStoreSize(
+    MessageProcessor *processor, size_t maximumContentStoreSize) {
+  parcAssertNotNull(processor, "Parameter processor must be non-null");
+  contentStoreInterface_Release(&processor->contentStore);
+
+  ContentStoreConfig contentStoreConfig = {.objectCapacity =
+                                               maximumContentStoreSize};
+
+  processor->contentStore =
+      contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+}
+
+void messageProcessor_ClearCache(MessageProcessor *processor) {
+  parcAssertNotNull(processor, "Parameter processor must be non-null");
+  size_t objectStoreSize = configuration_GetObjectStoreSize(
+      forwarder_GetConfiguration(processor->forwarder));
+
+  contentStoreInterface_Release(&processor->contentStore);
+
+  ContentStoreConfig contentStoreConfig = {
+      .objectCapacity = objectStoreSize,
+  };
+
+  processor->contentStore =
+      contentStoreLRU_Create(&contentStoreConfig, processor->logger);
+}
+
+ContentStoreInterface *messageProcessor_GetContentObjectStore(
+    const MessageProcessor *processor) {
+  parcAssertNotNull(processor, "Parameter processor must be non-null");
+  return processor->contentStore;
+}
+
+void messageProcessor_Destroy(MessageProcessor **processorPtr) {
+  parcAssertNotNull(processorPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*processorPtr, "Parameter dereference to non-null pointer");
+
+  MessageProcessor *processor = *processorPtr;
+
+  if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "MessageProcessor %p destroyed", (void *)processor);
+  }
+
+  logger_Release(&processor->logger);
+  fib_Destroy(&processor->fib);
+  contentStoreInterface_Release(&processor->contentStore);
+  pit_Release(&processor->pit);
+
+  parcMemory_Deallocate((void **)&processor);
+  *processorPtr = NULL;
+}
+
+void messageProcessor_Receive(MessageProcessor *processor, Message *message) {
+  parcAssertNotNull(processor, "Parameter processor must be non-null");
+  parcAssertNotNull(message, "Parameter message must be non-null");
+
+  processor->stats.countReceived++;
+
+  if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    char *nameString = name_ToString(message_GetName(message));
+    logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "Message %p ingress %3u length %5u received name %s",
+               (void *)message, message_GetIngressConnectionId(message),
+               message_Length(message), nameString);
+    parcMemory_Deallocate((void **)&nameString);
+  }
+
+  switch (message_GetType(message)) {
+    case MessagePacketType_Interest:
+      messageProcessor_ReceiveInterest(processor, message);
+      break;
+
+    case MessagePacketType_ContentObject:
+      messageProcessor_ReceiveContentObject(processor, message);
+      break;
+
+    default:
+      messageProcessor_Drop(processor, message);
+      break;
+  }
+
+  // if someone wanted to save it, they made a copy
+  message_Release(&message);
+}
+
+bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
+                                       add_route_command *control,
+                                       unsigned ifidx) {
+  Configuration *config = forwarder_GetConfiguration(processor->forwarder);
+
+  const char *prefixStr = utils_PrefixLenToString(
+      control->addressType, &control->address, &control->len);
+  strategy_type fwdStrategy =
+      configuration_GetForwardingStrategy(config, prefixStr);
+  if (fwdStrategy == LAST_STRATEGY_VALUE) {
+    fwdStrategy = SET_STRATEGY_LOADBALANCER;
+  }
+
+  Name *prefix = name_CreateFromAddress(control->addressType, control->address,
+                                        control->len);
+  FibEntry *entry = fib_Contains(processor->fib, prefix);
+  bool newEntry = false;
+  if (entry != NULL) {
+    fibEntry_AddNexthop(entry, ifidx);
+  } else {
+    newEntry = true;
+    entry = fibEntry_Create(prefix, fwdStrategy);
+    fibEntry_AddNexthop(entry, ifidx);
+    fib_Add(processor->fib, entry);
+  }
+
+  name_Release(&prefix);
+  if (newEntry && (fwdStrategy == SET_STRATEGY_LOADBALANCER_WITH_DELAY)) {
+    strategyLoadBalancerWithPD_SetConnectionTable(
+        fibEntry_GetFwdStrategy(entry),
+        forwarder_GetConnectionTable(processor->forwarder));
+  }
+
+  return true;
+}
+
+bool messageProcessor_RemoveRoute(MessageProcessor *processor,
+                                  remove_route_command *control,
+                                  unsigned ifidx) {
+  Name *name = name_CreateFromAddress(control->addressType, control->address,
+                                      control->len);
+  fib_Remove(processor->fib, name, ifidx);
+  name_Release(&name);
+
+  return true;
+}
+
+void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor,
+                                                   unsigned connectionId) {
+  fib_RemoveConnectionId(processor->fib, connectionId);
+}
+
+void processor_SetStrategy(MessageProcessor *processor, Name *prefix,
+                           strategy_type strategy) {
+  FibEntry *entry = fib_Contains(processor->fib, prefix);
+  if (entry != NULL) {
+    fibEntry_SetStrategy(entry, strategy);
+    if (strategy == SET_STRATEGY_LOADBALANCER_WITH_DELAY) {
+      strategyLoadBalancerWithPD_SetConnectionTable(
+          fibEntry_GetFwdStrategy(entry),
+          forwarder_GetConnectionTable(processor->forwarder));
+    }
+  }
+}
+
+FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor) {
+  parcAssertNotNull(processor, "Parameter processor must be non-null");
+  return fib_GetEntries(processor->fib);
+}
+
+// ============================================================
+// Internal API
+
+/**
+ * @function messageProcessor_Drop
+ * @abstract Whenever we "drop" a message, increment countes
+ * @discussion
+ *   This is a bookkeeping function.  It increments the appropriate counters.
+ *
+ *   The default action for a message is to destroy it in
+ * <code>messageProcessor_Receive()</code>, so this function does not need to do
+ * that.
+ *
+ */
+static void messageProcessor_Drop(MessageProcessor *processor,
+                                  Message *message) {
+  processor->stats.countDropped++;
+
+  switch (message_GetType(message)) {
+    case MessagePacketType_Interest:
+      processor->stats.countInterestsDropped++;
+      break;
+
+    case MessagePacketType_ContentObject:
+      processor->stats.countObjectsDropped++;
+      break;
+
+    default:
+      break;
+  }
+
+  // dont destroy message here, its done at end of receive
+}
+
+/**
+ * @function messageProcessor_AggregateInterestInPit
+ * @abstract Try to aggregate the interest in the PIT
+ * @discussion
+ *   Tries to aggregate the interest with another interest.
+ *
+ * @return true if interest aggregagted (no more forwarding needed), false if
+ * need to keep processing it.
+ */
+static bool messageProcessor_AggregateInterestInPit(MessageProcessor *processor,
+                                                    Message *interestMessage) {
+  PITVerdict verdict = pit_ReceiveInterest(processor->pit, interestMessage);
+
+  if (verdict == PITVerdict_Aggregate) {
+    // PIT has it, we're done
+    processor->stats.countInterestsAggregated++;
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(
+          processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+          __func__, "Message %p aggregated in PIT (aggregated count %u)",
+          (void *)interestMessage, processor->stats.countInterestsAggregated);
+    }
+
+    return true;
+  }
+
+  if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(
+        processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+        __func__, "Message %p not aggregated in PIT (aggregated count %u)",
+        (void *)interestMessage, processor->stats.countInterestsAggregated);
+  }
+
+  return false;
+}
+
+static bool _satisfyFromContentStore(MessageProcessor *processor,
+                                     Message *interestMessage) {
+  bool result = false;
+
+  if (message_GetInterestLifetimeTicks(interestMessage) == 0) {
+    return false;
+  }
+
+  if (!processor->serve_from_cache) {
+    return result;
+  }
+
+  // See if there's a match in the store.
+  Message *objectMessage = contentStoreInterface_MatchInterest(
+      processor->contentStore, interestMessage,
+      forwarder_GetTicks(processor->forwarder));
+
+  if (objectMessage != NULL) {
+    // Remove it from the PIT.  nexthops is allocated, so need to destroy
+    NumberSet *nexthops = pit_SatisfyInterest(processor->pit, objectMessage);
+    parcAssertNotNull(
+        nexthops,
+        "Illegal state: got a null nexthops for an interest we just inserted.");
+
+    // send message in reply, then done
+    processor->stats.countInterestsSatisfiedFromStore++;
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(processor->logger, LoggerFacility_Processor,
+                 PARCLogLevel_Debug, __func__,
+                 "Message %p satisfied from content store (satisfied count %u)",
+                 (void *)interestMessage,
+                 processor->stats.countInterestsSatisfiedFromStore);
+    }
+
+    message_ResetPathLabel(objectMessage);
+
+    messageProcessor_ForwardToNexthops(processor, objectMessage, nexthops);
+    numberSet_Release(&nexthops);
+
+    result = true;
+  }
+
+  return result;
+}
+
+/**
+ * @function messageProcessor_ForwardViaFib
+ * @abstract Try to forward the interest via the FIB
+ * @discussion
+ *   This calls <code>messageProcessor_ForwardToNexthops()</code>, so if we find
+ * any nexthops, the interest will be sent on its way.  Depending on the
+ * IoOperations of each nexthop, it may be a deferred write and bump up the
+ * <code>interestMessage</code> refernce count, or it may copy the data out.
+ *
+ *   A TRUE return means we did our best to forward it via the routes.  If those
+ * routes are actually down or have errors, we still return TRUE.  A FALSE
+ * return means there were no routes to try.
+ *
+ * @return true if we found a route and tried to forward it, false if no route
+ */
+static bool messageProcessor_ForwardViaFib(MessageProcessor *processor,
+                                           Message *interestMessage) {
+  FibEntry *fibEntry = fib_Match(processor->fib, interestMessage);
+  if (fibEntry == NULL) {
+    return false;
+  }
+
+  PitEntry *pitEntry = pit_GetPitEntry(processor->pit, interestMessage);
+  if (pitEntry == NULL) {
+    return false;
+  }
+
+  pitEntry_AddFibEntry(pitEntry, fibEntry);
+
+  NumberSet *nexthops = (NumberSet *)fibEntry_GetNexthopsFromForwardingStrategy(
+      fibEntry, interestMessage);
+  // this requires some additional checks. It may happen that some of the output
+  // faces selected by the forwarding strategy are not usable. So far all the
+  // forwarding strategy return only valid faces (or an empty list)
+  for (unsigned i = 0; i < numberSet_Length(nexthops); i++) {
+    pitEntry_AddEgressId(pitEntry, numberSet_GetItem(nexthops, i));
+  }
+
+  // The function GetPitEntry encreases the ref counter in the pit entry
+  // we need to decrease it
+  pitEntry_Release(&pitEntry);
+
+  if (messageProcessor_ForwardToNexthops(processor, interestMessage, nexthops) >
+      0) {
+    numberSet_Release(&nexthops);
+    return true;
+  } else {
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(processor->logger, LoggerFacility_Processor,
+                 PARCLogLevel_Debug, __func__,
+                 "Message %p returned an emtpy next hop set",
+                 (void *)interestMessage);
+    }
+  }
+
+  return false;
+}
+
+/**
+ * @function messageProcessor_ReceiveInterest
+ * @abstract Receive an interest from the network
+ * @discussion
+ *   (1) if interest in the PIT, aggregate in PIT
+ *   (2) if interest in the ContentStore, reply
+ *   (3) if in the FIB, forward
+ *   (4) drop
+ *
+ */
+static void messageProcessor_ReceiveInterest(MessageProcessor *processor,
+                                             Message *interestMessage) {
+  processor->stats.countInterestsReceived++;
+
+  // (1) Try to aggregate in PIT
+  if (messageProcessor_AggregateInterestInPit(processor, interestMessage)) {
+    // done
+    return;
+  }
+
+  // At this point, we just created a PIT entry.  If we don't forward the
+  // interest, we need to remove the PIT entry.
+
+  // (2) Try to satisfy from content store
+  if (_satisfyFromContentStore(processor, interestMessage)) {
+    // done
+    // If we found a content object in the CS,
+    // messageProcess_SatisfyFromContentStore already cleared the PIT state
+    return;
+  }
+
+  // (3) Try to forward it
+  if (messageProcessor_ForwardViaFib(processor, interestMessage)) {
+    // done
+    return;
+  }
+
+  // Remove the PIT entry?
+  processor->stats.countDroppedNoRoute++;
+
+  if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "Message %p did not match FIB, no route (count %u)",
+               (void *)interestMessage, processor->stats.countDroppedNoRoute);
+  }
+
+  messageProcessor_Drop(processor, interestMessage);
+}
+
+/**
+ * @function messageProcessor_ReceiveContentObject
+ * @abstract Process an in-bound content object
+ * @discussion
+ *   (1) If it does not match anything in the PIT, drop it
+ *   (2) Add to Content Store
+ *   (3) Reverse path forward via PIT entries
+ *
+ * @param <#param1#>
+ */
+static void messageProcessor_ReceiveContentObject(MessageProcessor *processor,
+                                                  Message *message) {
+  processor->stats.countObjectsReceived++;
+
+  NumberSet *ingressSetUnion = pit_SatisfyInterest(processor->pit, message);
+
+  if (numberSet_Length(ingressSetUnion) == 0) {
+    // (1) If it does not match anything in the PIT, drop it
+    processor->stats.countDroppedNoReversePath++;
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(processor->logger, LoggerFacility_Processor,
+                 PARCLogLevel_Debug, __func__,
+                 "Message %p did not match PIT, no reverse path (count %u)",
+                 (void *)message, processor->stats.countDroppedNoReversePath);
+    }
+
+    // we store the packets in the content store enven in the case where there
+    // is no match in the PIT table in this way the applications can push the
+    // content in the CS of the forwarder. We allow this only for local faces
+    bool isLocal = connection_IsLocal(connectionTable_FindById(
+        forwarder_GetConnectionTable(processor->forwarder),
+        message_GetIngressConnectionId((const Message *)message)));
+    if (processor->store_in_cache && isLocal) {
+      uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder);
+      contentStoreInterface_PutContent(processor->contentStore, message,
+                                       currentTimeTicks);
+      if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                            PARCLogLevel_Debug)) {
+        logger_Log(processor->logger, LoggerFacility_Processor,
+                   PARCLogLevel_Debug, __func__,
+                   "Message %p sotred in the CS anyway", (void *)message);
+      }
+    }
+
+    messageProcessor_Drop(processor, message);
+  } else {
+    // (2) Add to Content Store. Store may remove expired content, if necessary,
+    // depending on store policy.
+    if (processor->store_in_cache) {
+      uint64_t currentTimeTicks = forwarder_GetTicks(processor->forwarder);
+      contentStoreInterface_PutContent(processor->contentStore, message,
+                                       currentTimeTicks);
+    }
+    // (3) Reverse path forward via PIT entries
+    messageProcessor_ForwardToNexthops(processor, message, ingressSetUnion);
+  }
+
+  numberSet_Release(&ingressSetUnion);
+}
+
+/**
+ * @function messageProcessor_ForwardToNexthops
+ * @abstract Try to forward to each nexthop listed in the NumberSet
+ * @discussion
+ *   Will not forward to the ingress connection.
+ *
+ * @return The number of nexthops tried
+ */
+static unsigned messageProcessor_ForwardToNexthops(MessageProcessor *processor,
+                                                   Message *message,
+                                                   const NumberSet *nexthops) {
+  unsigned forwardedCopies = 0;
+
+  size_t length = numberSet_Length(nexthops);
+
+  unsigned ingressId = message_GetIngressConnectionId(message);
+  uint32_t old_path_label = 0;
+
+  if (message_GetType(message) == MessagePacketType_ContentObject) {
+    old_path_label = message_GetPathLabel(message);
+  }
+
+  for (size_t i = 0; i < length; i++) {
+    unsigned egressId = numberSet_GetItem(nexthops, i);
+    if (egressId != ingressId) {
+      forwardedCopies++;
+      messageProcessor_ForwardToInterfaceId(processor, message, egressId);
+
+      if (message_GetType(message) == MessagePacketType_ContentObject) {
+        // everytime we send out a message we need to restore the original path
+        // label of the message this is important because we keep a single copy
+        // of the message (single pointer) and we modify the path label at each
+        // send.
+        message_SetPathLabel(message, old_path_label);
+      }
+    }
+  }
+  return forwardedCopies;
+}
+
+/**
+ * caller has checked that the hop limit is ok.  Try to send out the connection.
+ */
+static void messageProcessor_SendWithGoodHopLimit(MessageProcessor *processor,
+                                                  Message *message,
+                                                  unsigned interfaceId,
+                                                  const Connection *conn) {
+  bool success = connection_Send(conn, message);
+  if (success) {
+    switch (message_GetType(message)) {
+      case MessagePacketType_Interest:
+        processor->stats.countInterestForwarded++;
+        break;
+
+      case MessagePacketType_ContentObject:
+        processor->stats.countObjectsForwarded++;
+        break;
+
+      default:
+        break;
+    }
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(
+          processor->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+          __func__, "forward message %p to interface %u (int %u, obj %u)",
+          (void *)message, interfaceId, processor->stats.countInterestForwarded,
+          processor->stats.countObjectsForwarded);
+    }
+  } else {
+    processor->stats.countSendFailures++;
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(processor->logger, LoggerFacility_Processor,
+                 PARCLogLevel_Debug, __func__,
+                 "forward message %p to interface %u send failure (count %u)",
+                 (void *)message, interfaceId,
+                 processor->stats.countSendFailures);
+    }
+    messageProcessor_Drop(processor, message);
+  }
+}
+
+/*
+ *   If the hoplimit is equal to 0, then we may only forward it to local
+ * applications.  Otherwise, we may forward it off the system.
+ *
+ */
+static void messageProcessor_ForwardToInterfaceId(MessageProcessor *processor,
+                                                  Message *message,
+                                                  unsigned interfaceId) {
+  ConnectionTable *connectionTable =
+      forwarder_GetConnectionTable(processor->forwarder);
+  const Connection *conn =
+      connectionTable_FindById(connectionTable, interfaceId);
+
+  if (conn != NULL) {
+    messageProcessor_SendWithGoodHopLimit(processor, message, interfaceId,
+                                          conn);
+  } else {
+    processor->stats.countDroppedConnectionNotFound++;
+
+    if (logger_IsLoggable(processor->logger, LoggerFacility_Processor,
+                          PARCLogLevel_Debug)) {
+      logger_Log(processor->logger, LoggerFacility_Processor,
+                 PARCLogLevel_Debug, __func__,
+                 "forward message %p to interface %u not found (count %u)",
+                 (void *)message, interfaceId,
+                 processor->stats.countDroppedConnectionNotFound);
+    }
+
+    messageProcessor_Drop(processor, message);
+  }
+}
+
+void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val) {
+  processor->store_in_cache = val;
+}
+
+bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor) {
+  return processor->store_in_cache;
+}
+
+void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val) {
+  processor->serve_from_cache = val;
+}
+
+bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor) {
+  return processor->serve_from_cache;
+}
+
+#ifdef WITH_MAPME
+
+FIB *messageProcessor_getFib(MessageProcessor *processor) {
+  return processor->fib;
+}
+
+#endif /* WITH_MAPME */
diff --git a/hicn-light/src/processor/messageProcessor.h b/hicn-light/src/processor/messageProcessor.h
new file mode 100755 (executable)
index 0000000..ce30499
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file messageProcessor.h
+ * @brief Executes the set of rules dictated by the PacketType
+ *
+ * This is a "run-to-completion" handling of a message based on the PacketType.
+ *
+ * The MessageProcessor also owns the PIT and FIB tables.
+ *
+ */
+
+#ifndef messageProcessor_h
+#define messageProcessor_h
+
+#include <src/content_store/contentStoreInterface.h>
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+
+#include <src/utils/commands.h>
+
+struct message_processor;
+typedef struct message_processor MessageProcessor;
+
+/**
+ * Allocates a MessageProcessor along with PIT, FIB and ContentStore tables
+ *
+ * The hicn-light pointer is primarily used for logging (forwarder_Log), getting
+ * the configuration, and accessing the connection table.
+ *
+ * @param [in] Pointer to owning hicn-light process
+ *
+ * @retval non-null An allocated message processor
+ * @retval null An error
+ *
+ */
+MessageProcessor *messageProcessor_Create(Forwarder *forwarder);
+
+/**
+ * Deallocates a message processor an all internal tables
+ *
+ * @param [in,out] processorPtr Pointer to message processor to de-allocate,
+ * will be NULL'd.
+ */
+void messageProcessor_Destroy(MessageProcessor **processorPtr);
+
+/**
+ * @function messageProcessor_Receive
+ * @abstract Process the message, takes ownership of the memory.
+ * @discussion
+ *   Will call destroy on the memory when done with it, so if the caller wants
+ * to keep it, make a reference counted copy.
+ *
+ *   Receive may modify some fields in the message, such as the HopLimit field.
+ */
+void messageProcessor_Receive(MessageProcessor *procesor, Message *message);
+
+/**
+ * Adds or updates a route in the FIB
+ *
+ * If the route already exists, it is replaced
+ *
+ * @param [in] procesor An allocated message processor
+ * @param [in] route The route to update
+ *
+ * @retval true added or updated
+ * @retval false An error
+ */
+bool messageProcessor_AddOrUpdateRoute(MessageProcessor *processor,
+                                       add_route_command *control,
+                                       unsigned ifidx);
+
+/**
+ * Removes a route from the FIB
+ *
+ * Removes a specific nexthop for a route.  If there are no nexthops left after
+ * the removal, the entire route is deleted from the FIB.
+ *
+ * @param [in] procesor An allocated message processor
+ * @param [in] route The route to remove
+ *
+ * @retval true Route completely removed
+ * @retval false There is still a nexthop for the route
+ */
+
+bool messageProcessor_RemoveRoute(MessageProcessor *processor,
+                                  remove_route_command *control,
+                                  unsigned ifidx);
+
+/**
+ * Removes a given connection id from all FIB entries
+ *
+ * Iterates the FIB and removes the given connection ID from every route.
+ */
+void messageProcessor_RemoveConnectionIdFromRoutes(MessageProcessor *processor,
+                                                   unsigned connectionId);
+
+/**
+ * Returns a list of all FIB entries
+ *
+ * You must destroy the list.
+ *
+ * @retval non-null The list of FIB entries
+ * @retval null An error
+ */
+FibEntryList *messageProcessor_GetFibEntries(MessageProcessor *processor);
+
+/**
+ * Adjusts the ContentStore to the given size.
+ *
+ * This will destroy and re-create the content store, so any cached objects will
+ * be lost.
+ *
+ */
+void messageProcessor_SetContentObjectStoreSize(MessageProcessor *processor,
+                                                size_t maximumContentStoreSize);
+
+/**
+ * Return the interface to the currently instantiated ContentStore, if any.
+ *
+ * @param [in] processor the `MessageProcessor` from which to return the
+ * ContentStoreInterface.
+ *
+ */
+ContentStoreInterface *messageProcessor_GetContentObjectStore(
+    const MessageProcessor *processor);
+
+void messageProcessor_SetCacheStoreFlag(MessageProcessor *processor, bool val);
+
+bool messageProcessor_GetCacheStoreFlag(MessageProcessor *processor);
+
+void messageProcessor_SetCacheServeFlag(MessageProcessor *processor, bool val);
+
+bool messageProcessor_GetCacheServeFlag(MessageProcessor *processor);
+
+void messageProcessor_ClearCache(MessageProcessor *processor);
+
+void processor_SetStrategy(MessageProcessor *processor, Name *prefix,
+                           strategy_type strategy);
+
+#ifdef WITH_MAPME
+
+/**
+ * @function messageProcessor_getFib
+ * @abstract Returns the hICN processor's FIB.
+ * @param [in] forwarder - Pointer to the hICN processor.
+ * @returns Pointer to the hICN FIB.
+ */
+FIB *messageProcessor_getFib(MessageProcessor *processor);
+
+#endif /* WITH_MAPME */
+
+#endif  // messageProcessor_h
diff --git a/hicn-light/src/processor/pit.c b/hicn-light/src/processor/pit.c
new file mode 100755 (executable)
index 0000000..9cae406
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Generic interface to PIT table
+ *
+ */
+
+#include <parc/assert/parc_Assert.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <src/processor/pit.h>
+
+void *pit_Closure(const PIT *pit) { return pit->closure; }
+
+void pit_Release(PIT **pitPtr) { (*pitPtr)->release(pitPtr); }
+
+PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage) {
+  return pit->receiveInterest(pit, interestMessage);
+}
+
+NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage) {
+  return pit->satisfyInterest(pit, objectMessage);
+}
+
+void pit_RemoveInterest(PIT *pit, const Message *interestMessage) {
+  pit->removeInterest(pit, interestMessage);
+}
+
+PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage) {
+  return pit->getPitEntry(pit, interestMessage);
+}
diff --git a/hicn-light/src/processor/pit.h b/hicn-light/src/processor/pit.h
new file mode 100755 (executable)
index 0000000..1f909be
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file pit.h
+ * @brief The Pending Interest Table interface
+ *
+ * Interface for implementing a PIT table
+ *
+ */
+
+#ifndef pit_h
+#define pit_h
+
+#include <src/core/forwarder.h>
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+#include <src/processor/pitEntry.h>
+#include <src/processor/pitVerdict.h>
+
+struct pit;
+typedef struct pit PIT;
+
+struct pit {
+  void (*release)(PIT **pitPtr);
+  PITVerdict (*receiveInterest)(PIT *pit, Message *interestMessage);
+  NumberSet *(*satisfyInterest)(PIT *pit, const Message *objectMessage);
+  void (*removeInterest)(PIT *pit, const Message *interestMessage);
+  PitEntry *(*getPitEntry)(const PIT *pit, const Message *interestMessage);
+  void *closure;
+};
+
+void *pit_Closure(const PIT *pit);
+
+/**
+ * Destroys the PIT table and all entries contained in it.
+ *
+ * PIT entries are reference counted, so if the user has stored one outside the
+ * PIT table it will still be valid.
+ *
+ * @param [in,out] pitPtr Double pointer to PIT table, will be NULLed
+ */
+void pit_Release(PIT **pitPtr);
+
+/**
+ * @function pit_ReceiveInterest
+ * @abstract Receives an interest and adds to PIT table
+ * @discussion
+ *   If not present, adds entry to the PIT table and returns
+ * PIT_VERDICT_NEW_ENTRY. If present and aggregated, returns
+ * PIT_VERDICT_EXISTING_ENTRY.
+ *
+ *   Some aggregated interests may return PIT_VERDICT_NEW_ENTRY if the interest
+ * needs to be forwarded again (e.g. the lifetime is extended).
+ *
+ *   If the PIT stores the message in its table, it will store a reference
+ * counted copy.
+ *
+ * @return Verdict of receiving the interest
+ */
+PITVerdict pit_ReceiveInterest(PIT *pit, Message *interestMessage);
+
+/**
+ * @function pit_SatisfyInterest
+ * @abstract Tries to satisfy PIT entries based on the message, returning where
+ * to send message
+ * @discussion
+ *     If matching interests are in the PIT, will return the set of reverse
+ * paths to use to forward the content object.
+ *
+ *     The return value is allocated and must be destroyed.
+ *
+ * @return Set of ConnectionTable id's to forward the message, may be empty or
+ * NULL.  Must be destroyed.
+ */
+NumberSet *pit_SatisfyInterest(PIT *pit, const Message *objectMessage);
+
+/**
+ * @function pit_RemoveInterest
+ * @abstract Unconditionally remove the interest from the PIT
+ * @discussion
+ *   The PIT may store a specific name in several tables.  This function will
+ *   remove the interest from the specific table it lives it.  It will not
+ *   remove PIT entries in different tables with the same name.
+ *
+ *   The different tables index interests based on their matching criteria,
+ *   such as by name, by name and keyid, etc.
+ *
+ */
+void pit_RemoveInterest(PIT *pit, const Message *interestMessage);
+
+/**
+ * @function pit_GetPitEntry
+ * @abstract Retrieve the best matching PIT entry for the message.
+ * @discussion
+ *   Returns a reference counted copy of the entry, must call
+ * <code>pitEntry_Destory()</code> on it.
+ *
+ * @return NULL if not in table, otherwise a reference counted copy of the entry
+ */
+PitEntry *pit_GetPitEntry(const PIT *pit, const Message *interestMessage);
+#endif  // pit_h
diff --git a/hicn-light/src/processor/pitEntry.c b/hicn-light/src/processor/pitEntry.c
new file mode 100755 (executable)
index 0000000..38103cb
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/core/numberSet.h>
+#include <src/processor/pitEntry.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct pit_entry {
+  Message *message;
+  NumberSet *ingressIdSet;
+  NumberSet *egressIdSet;
+
+  FibEntry *fibEntry;
+
+  Ticks creationTime;
+  Ticks expiryTime;
+
+  unsigned refcount;
+};
+
+PitEntry *pitEntry_Create(Message *message, Ticks expiryTime,
+                          Ticks creationTime) {
+  PitEntry *pitEntry = parcMemory_AllocateAndClear(sizeof(PitEntry));
+  parcAssertNotNull(pitEntry, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(PitEntry));
+  pitEntry->message = message;
+  pitEntry->ingressIdSet = numberSet_Create();
+  pitEntry->egressIdSet = numberSet_Create();
+  pitEntry->refcount = 1;
+
+  // add the message to the reverse path set
+  numberSet_Add(pitEntry->ingressIdSet,
+                message_GetIngressConnectionId(message));
+
+  // hack in a 4-second timeout
+  pitEntry->expiryTime = expiryTime;
+  pitEntry->fibEntry = NULL;
+
+  pitEntry->creationTime = creationTime;
+  return pitEntry;
+}
+
+void pitEntry_Release(PitEntry **pitEntryPtr) {
+  parcAssertNotNull(pitEntryPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*pitEntryPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  PitEntry *pitEntry = *pitEntryPtr;
+  parcTrapIllegalValueIf(pitEntry->refcount == 0,
+                         "Illegal state: has refcount of 0");
+
+  pitEntry->refcount--;
+  if (pitEntry->refcount == 0) {
+    if (pitEntry->fibEntry != NULL) {
+      fibEntry_Release(&pitEntry->fibEntry);
+    }
+    numberSet_Release(&pitEntry->ingressIdSet);
+    numberSet_Release(&pitEntry->egressIdSet);
+    message_Release(&pitEntry->message);
+    parcMemory_Deallocate((void **)&pitEntry);
+  }
+  *pitEntryPtr = NULL;
+}
+
+PitEntry *pitEntry_Acquire(PitEntry *original) {
+  parcAssertNotNull(original, "Parameter original must be non-null");
+  original->refcount++;
+  return original;
+}
+
+void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  numberSet_Add(pitEntry->ingressIdSet, ingressId);
+}
+
+void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  numberSet_Add(pitEntry->egressIdSet, egressId);
+}
+
+void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  parcAssertNotNull(fibEntry, "Parameter fibEntry must be non-null");
+  // the fibEntry should be always the same for all the interests in the same
+  // pitEntry
+  if (pitEntry->fibEntry == NULL) {
+    fibEntry_Acquire(fibEntry);
+    pitEntry->fibEntry = fibEntry;
+  }
+}
+
+FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return pitEntry->fibEntry;
+}
+
+Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return pitEntry->expiryTime;
+}
+
+Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return pitEntry->creationTime;
+}
+
+void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  pitEntry->expiryTime = expiryTime;
+}
+
+const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return pitEntry->ingressIdSet;
+}
+
+const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return pitEntry->egressIdSet;
+}
+
+Message *pitEntry_GetMessage(const PitEntry *pitEntry) {
+  parcAssertNotNull(pitEntry, "Parameter pitEntry must be non-null");
+  return message_Acquire(pitEntry->message);
+}
diff --git a/hicn-light/src/processor/pitEntry.h b/hicn-light/src/processor/pitEntry.h
new file mode 100755 (executable)
index 0000000..b7d45e6
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file pitEntry.h
+ * @brief The embodiment of a PIT entry
+ *
+ * Embodies a PIT entry
+ *
+ */
+
+#ifndef pitEntry_h
+#define pitEntry_h
+
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+#include <src/core/ticks.h>
+#include <src/processor/fibEntry.h>
+
+struct pit_entry;
+typedef struct pit_entry PitEntry;
+
+/**
+ * @function pitEntry_Create
+ * @abstract Takes ownership of the message inside the PitEntry
+ * @discussion
+ *   When the PIT entry is destroyed, will call <code>message_Release()</code>
+ * on the message.
+ *
+ */
+PitEntry *pitEntry_Create(Message *message, Ticks expiryTime,
+                          Ticks CreationTime);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] pitEntryPtr A pointer to a PitEntry instance pointer, which
+ * will be set to zero on return.
+ *
+ */
+void pitEntry_Release(PitEntry **pitEntryPtr);
+
+/**
+ * @function pitEntry_Acquire
+ * @abstract Returns a reference counted copy
+ * @discussion
+ *   A reference counted copy that shares the same state as the original.
+ *   Caller must use <code>pitEntry_Release()</code> on it when done.
+ *
+ * @return A reference counted copy, use Destroy on it.
+ */
+PitEntry *pitEntry_Acquire(PitEntry *original);
+
+/**
+ * @function pitEntry_AddIngressId
+ * @abstract Add an ingress connection id to the list of reverse paths
+ * @discussion
+ *   A PitEntry has two NumberSets.  The first is the set of ingress ports,
+ * which make up the reverse path.  The second is the set of egress ports, which
+ * make up its forward path.
+ *
+ *   This function tracks which reverse paths have sent us the interest.
+ *
+ * @param ingressId the reverse path
+ */
+void pitEntry_AddIngressId(PitEntry *pitEntry, unsigned ingressId);
+
+/**
+ * @function pitEntry_AddEgressId
+ * @abstract Add an egress connection id to the list of attempted paths
+ * @discussion
+ *   A PitEntry has two NumberSets.  The first is the set of ingress ports,
+ * which make up the reverse path.  The second is the set of egress ports, which
+ * make up its forward path.
+ *
+ *   This function tracks which forward paths we've tried for the interest.
+ *
+ * @param egressId the forwarded path
+ */
+void pitEntry_AddEgressId(PitEntry *pitEntry, unsigned egressId);
+
+void pitEntry_AddFibEntry(PitEntry *pitEntry, FibEntry *fibEntry);
+
+FibEntry *pitEntry_GetFibEntry(PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetIngressSet
+ * @abstract The Ingress connection id set
+ * @discussion
+ *   You must acquire a copy of the number set if you will store the result.
+ * This is the internal reference.
+ *
+ * @return May be empty, will not be null.  Must be destroyed.
+ */
+const NumberSet *pitEntry_GetIngressSet(const PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetEgressSet
+ * @abstract The Egress connection id set
+ * @discussion
+ *   You must acquire a copy of the number set if you will store the result.
+ * This is the internal reference.
+ *
+ * @param <#param1#>
+ * @return May be empty, will not be null.  Must be destroyed.
+ */
+const NumberSet *pitEntry_GetEgressSet(const PitEntry *pitEntry);
+
+/**
+ * @function pitEntry_GetMessage
+ * @abstract Gets the interest underpinning the PIT entry
+ * @discussion
+ *   A reference counted copy, call <code>Message_Release()</code> on it.
+ *
+ * @return A reference counted copy, call <code>Message_Release()</code> on it.
+ */
+Message *pitEntry_GetMessage(const PitEntry *pitEntry);
+
+/**
+ * Returns the time (in ticks) at which the PIT entry is no longer valid
+ *
+ * The ExpiryTime is computed when the PIT entry is added (or via
+ * pitEntry_SetExpiryTime). It is the aboslute time (in Ticks) at which the Pit
+ * entry is no longer valid.
+ *
+ * @param [in] PitEntry An allocated PIT entry
+ *
+ * @retval number The abosolute time (in Ticks) of the Expiry
+ */
+Ticks pitEntry_GetExpiryTime(const PitEntry *pitEntry);
+
+Ticks pitEntry_GetCreationTime(const PitEntry *pitEntry);
+/**
+ * Sets the ExpriyTime of the PIT entry to the given value
+ *
+ * It is probalby an error to set the expiryTime to a smaller value than
+ * currently set to, but this is not enforced.  PIT entries use lazy delete.
+ *
+ * @param [in] pitEntry The allocated PIT entry to modify
+ * @param [in] expiryTime The new expiryTime (UTC in forwarder Ticks)
+ *
+ */
+void pitEntry_SetExpiryTime(PitEntry *pitEntry, Ticks expiryTime);
+
+#endif  // pitEntry_h
diff --git a/hicn-light/src/processor/pitStandard.c b/hicn-light/src/processor/pitStandard.c
new file mode 100755 (executable)
index 0000000..8d50762
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * The pending interest table.
+ *
+ * Interest aggregation strategy:
+ * - The first Interest for a name is forwarded
+ * - A second Interest for a name from a different reverse path may be
+ * aggregated
+ * - A second Interest for a name from an existing Interest is forwarded
+ * - The Interest Lifetime is like a subscription time.  A reverse path entry is
+ * removed once the lifetime is exceeded.
+ * - Whan an Interest arrives or is aggregated, the Lifetime for that reverse
+ * hop is extended.  As a simplification, we only keep a single lifetime not per
+ * reverse hop.
+ *
+ */
+
+#include <src/config.h>
+#include <stdio.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <src/processor/hashTableFunction.h>
+#include <src/processor/pit.h>
+
+#include <src/core/ticks.h>
+
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_HashCodeTable.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/core/forwarder.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct standard_pit;
+typedef struct standard_pit StandardPIT;
+
+struct standard_pit {
+  Forwarder *forwarder;
+  Logger *logger;
+  PARCHashCodeTable *table;  // PIT indexed by name
+};
+
+static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage);
+
+static void _pit_PitEntryDestroyer(void **dataPtr) {
+  pitEntry_Release((PitEntry **)dataPtr);
+}
+
+static bool _pit_IngressSetContains(PitEntry *pitEntry, unsigned connectionId) {
+  const NumberSet *set = pitEntry_GetIngressSet(pitEntry);
+  bool numberInSet = numberSet_Contains(set, connectionId);
+  return numberInSet;
+}
+
+static Ticks _pit_CalculateLifetime(StandardPIT *pit,
+                                    Message *interestMessage) {
+  uint64_t interestLifetimeTicks =
+      message_GetInterestLifetimeTicks(interestMessage);
+  if (interestLifetimeTicks == 0) {
+    interestLifetimeTicks = forwarder_NanosToTicks(4000000000ULL);
+  }
+
+  Ticks expiryTime = forwarder_GetTicks(pit->forwarder) + interestLifetimeTicks;
+  return expiryTime;
+}
+
+static void _pit_StoreInTable(StandardPIT *pit, Message *interestMessage) {
+  Message *key = message_Acquire(interestMessage);
+
+  Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage);
+
+  PitEntry *pitEntry =
+      pitEntry_Create(key, expiryTime, forwarder_GetTicks(pit->forwarder));
+
+  parcHashCodeTable_Add(pit->table, key, pitEntry);
+
+  if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__,
+               "Message %p added to PIT (expiry %" PRIu64 ") ingress %u",
+               (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry),
+               message_GetIngressConnectionId(interestMessage));
+  }
+}
+
+static void _pit_ExtendLifetime(StandardPIT *pit, PitEntry *pitEntry,
+                                Message *interestMessage) {
+  Ticks expiryTime = _pit_CalculateLifetime(pit, interestMessage);
+
+  if (expiryTime > pitEntry_GetExpiryTime(pitEntry))
+    pitEntry_SetExpiryTime(pitEntry, expiryTime);
+}
+
+// ======================================================================
+// Interface API
+
+static void _pitStandard_Destroy(PIT **pitPtr) {
+  parcAssertNotNull(pitPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*pitPtr, "Parameter must dereference to non-null pointer");
+
+  StandardPIT *pit = pit_Closure(*pitPtr);
+
+  if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "PIT %p destroyed", (void *)pit);
+  }
+
+  parcHashCodeTable_Destroy(&pit->table);
+  logger_Release(&pit->logger);
+  parcMemory_Deallocate(pitPtr);
+}
+
+static PITVerdict _pitStandard_ReceiveInterest(PIT *generic,
+                                               Message *interestMessage) {
+  parcAssertNotNull(generic, "Parameter pit must be non-null");
+  parcAssertNotNull(interestMessage,
+                    "Parameter interestMessage must be non-null");
+
+  StandardPIT *pit = pit_Closure(generic);
+
+  PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, interestMessage);
+
+  if (pitEntry) {
+    // has it expired?
+    Ticks now = forwarder_GetTicks(pit->forwarder);
+    if (now < pitEntry_GetExpiryTime(pitEntry)) {
+      _pit_ExtendLifetime(pit, pitEntry, interestMessage);
+
+      // Is the reverse path already in the PIT entry?
+      if (_pit_IngressSetContains(
+              pitEntry, message_GetIngressConnectionId(interestMessage))) {
+        // It is already in the PIT entry, so this is a retransmission, so
+        // forward it.
+
+        if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                              PARCLogLevel_Debug)) {
+          logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                     __func__,
+                     "Message %p existing entry (expiry %" PRIu64
+                     ") and reverse path, forwarding",
+                     (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry));
+        }
+
+        return PITVerdict_Forward;
+      }
+
+      // It is in the PIT but this is the first interest for the reverse path
+      pitEntry_AddIngressId(pitEntry,
+                            message_GetIngressConnectionId(interestMessage));
+
+      if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                            PARCLogLevel_Debug)) {
+        logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+                   __func__,
+                   "Message %p existing entry (expiry %" PRIu64
+                   ") and reverse path is new, aggregate",
+                   (void *)interestMessage, pitEntry_GetExpiryTime(pitEntry));
+      }
+
+      return PITVerdict_Aggregate;
+    }
+    // this is a timeout....
+    FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry);
+    if (fibEntry != NULL) {
+      fibEntry_OnTimeout(fibEntry, pitEntry_GetEgressSet(pitEntry));
+    }
+
+    // it's an old entry, remove it
+    parcHashCodeTable_Del(pit->table, interestMessage);
+  }
+
+  _pit_StoreInTable(pit, interestMessage);
+
+  return PITVerdict_Forward;
+}
+
+static NumberSet *_pitStandard_SatisfyInterest(PIT *generic,
+                                               const Message *objectMessage) {
+  parcAssertNotNull(generic, "Parameter pit must be non-null");
+  parcAssertNotNull(objectMessage, "Parameter objectMessage must be non-null");
+
+  StandardPIT *pit = pit_Closure(generic);
+
+  NumberSet *ingressSet = numberSet_Create();
+
+  PitEntry *pitEntry = parcHashCodeTable_Get(pit->table, objectMessage);
+  if (pitEntry) {
+    // here we need to check if the PIT entry is expired
+    // if so, remove the PIT entry.
+    Ticks now = forwarder_GetTicks(pit->forwarder);
+    if (now < pitEntry_GetExpiryTime(pitEntry)) {
+      // PIT entry is not expired, use it
+      FibEntry *fibEntry = pitEntry_GetFibEntry(pitEntry);
+      if (fibEntry != NULL) {
+        // this is a rough estimation of the residual RTT
+        Ticks rtt = forwarder_GetTicks(pit->forwarder) -
+                    pitEntry_GetCreationTime(pitEntry);
+        fibEntry_ReceiveObjectMessage(fibEntry, pitEntry_GetEgressSet(pitEntry),
+                                      objectMessage,
+                                      rtt);  // need to implement RTT
+      }
+      const NumberSet *is = pitEntry_GetIngressSet(pitEntry);
+      numberSet_AddSet(ingressSet, is);  // with this we do a copy so we can
+                                         // remove the entry from the PIT
+    }
+    // remove the entry from the PIT.  Key is a reference counted copy of the
+    // pit entry message
+    Message *key = pitEntry_GetMessage(pitEntry);
+    parcHashCodeTable_Del(pit->table, key);
+    message_Release(&key);
+  }
+
+  return ingressSet;
+}
+
+static void _pitStandard_RemoveInterest(PIT *generic,
+                                        const Message *interestMessage) {
+  parcAssertNotNull(generic, "Parameter pit must be non-null");
+  parcAssertNotNull(interestMessage,
+                    "Parameter interestMessage must be non-null");
+
+  StandardPIT *pit = pit_Closure(generic);
+
+  if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "Message %p removed from PIT",
+               (void *)interestMessage);
+  }
+
+  parcHashCodeTable_Del(pit->table, interestMessage);
+}
+
+static PitEntry *_pitStandard_GetPitEntry(const PIT *generic,
+                                          const Message *interestMessage) {
+  parcAssertNotNull(generic, "Parameter pit must be non-null");
+  parcAssertNotNull(interestMessage,
+                    "Parameter interestMessage must be non-null");
+
+  StandardPIT *pit = pit_Closure(generic);
+
+  PitEntry *entry = parcHashCodeTable_Get(pit->table, interestMessage);
+  if (entry) {
+    return pitEntry_Acquire(entry);
+  }
+  return NULL;
+}
+
+// ======================================================================
+// Public API
+
+PIT *pitStandard_Create(Forwarder *forwarder) {
+  parcAssertNotNull(forwarder, "Parameter must be non-null");
+
+  size_t allocation = sizeof(PIT) + sizeof(StandardPIT);
+
+  PIT *generic = parcMemory_AllocateAndClear(allocation);
+  parcAssertNotNull(generic, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    allocation);
+  generic->closure = (uint8_t *)generic + sizeof(PIT);
+
+  StandardPIT *pit = pit_Closure(generic);
+  pit->forwarder = forwarder;
+  pit->logger = logger_Acquire(forwarder_GetLogger(forwarder));
+
+  size_t initialSize = 65535;
+  pit->table =
+      parcHashCodeTable_Create_Size(hashTableFunction_MessageNameEquals,
+                                    hashTableFunction_MessageNameHashCode, NULL,
+                                    _pit_PitEntryDestroyer, initialSize);
+
+  if (logger_IsLoggable(pit->logger, LoggerFacility_Processor,
+                        PARCLogLevel_Debug)) {
+    logger_Log(pit->logger, LoggerFacility_Processor, PARCLogLevel_Debug,
+               __func__, "PIT %p created", (void *)pit);
+  }
+
+  generic->getPitEntry = _pitStandard_GetPitEntry;
+  generic->receiveInterest = _pitStandard_ReceiveInterest;
+  generic->release = _pitStandard_Destroy;
+  generic->removeInterest = _pitStandard_RemoveInterest;
+  generic->satisfyInterest = _pitStandard_SatisfyInterest;
+
+  return generic;
+}
diff --git a/hicn-light/src/processor/pitStandard.h b/hicn-light/src/processor/pitStandard.h
new file mode 100755 (executable)
index 0000000..b9ba026
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file pitStandard.h
+ * @brief The Pending Interest Table
+ *
+ * Implements the standard Pending Interest Table.
+ *
+ */
+
+#ifndef pitStandard_h
+#define pitStandard_h
+
+#include <src/processor/pit.h>
+
+/**
+ * Creates a PIT table
+ *
+ * Creates and allocates an emtpy PIT table.  The Forwarder reference is
+ * used for logging and for time functions.
+ *
+ * @param [in] hicn-light The releated Forwarder
+ *
+ * @return non-null a PIT table
+ * @return null An error
+ */
+PIT *pitStandard_Create(Forwarder *forwarder);
+#endif  // pit_h
diff --git a/hicn-light/src/processor/pitVerdict.h b/hicn-light/src/processor/pitVerdict.h
new file mode 100755 (executable)
index 0000000..16631fa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file pitVerdict.h
+ * @brief Adding an entry to the PIT will return NEW or EXISTING
+ *
+ * Adding an entry to the PIT will return NEW or EXISTING
+ *
+ */
+
+#ifndef pitVerdict_h
+#define pitVerdict_h
+
+/**
+ * @typedef PitVerdict
+ * @abstract The verdit of the PIT for receiving a message
+ * @constant PITVerdict_Forward The message made a new PIT entry, the interest
+ * should be forwarded
+ * @constant PITVerdict_Aggregate The Interest was aggregated in the PIT, does
+ * not need to be forwarded
+ */
+typedef enum { PITVerdict_Forward, PITVerdict_Aggregate } PITVerdict;
+#endif  // pitVerdict_h
diff --git a/hicn-light/src/socket/CMakeLists.txt b/hicn-light/src/socket/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..6ea94dc
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+if (UNIX AND NOT APPLE AND NOT ANDROID_API)
+  list(APPEND HEADER_FILES
+    socket/api.h
+    socket/error.h
+    socket/ops.h
+  )
+
+  list(APPEND SOURCE_FILES
+    socket/api.c
+    socket/error.c
+    socket/ops_linux.c
+  )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/socket/api.c b/hicn-light/src/socket/api.c
new file mode 100755 (executable)
index 0000000..aede01e
--- /dev/null
@@ -0,0 +1,604 @@
+#include <arpa/inet.h>  // inet_ntop
+#include <netdb.h>      // ''
+#include <search.h>     // tfind(), tdestroy(), twalk(), preorder...
+#include <stdbool.h>
+#include <stdio.h>       // perror
+#include <stdlib.h>      // calloc
+#include <string.h>      // memcpy
+#include <sys/socket.h>  // ''
+#include <sys/types.h>   // getaddrinfo
+#include <unistd.h>      // close
+
+#include "api.h"
+#include "error.h"
+#include "ops.h"
+
+#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN
+
+#define IF_NAMESIZE 16
+#define MAX_TABLES 256
+
+#define DEFAULT_INTERVAL 1000
+#define DEFAULT_IDENTIFIER "hicn"
+#define DEFAULT_SOCKET_IDENTIFIER "main"
+#define LOCAL_IPV6_PREFIX "fe80"
+
+#define LOCAL_PRIORITY 32000
+
+extern hicn_socket_ops_t ops;
+
+/* Configuration stored as a global variable to allow access from signal
+ * handlers for instance */
+
+static hicn_conf_t hicn_default_conf = {
+    .identifier = DEFAULT_IDENTIFIER,
+    //.format = HF_INET6_TCP
+};
+
+/* Global state */
+// FIXME move into helper state ?
+
+struct ip_rule_state_ {
+  char tun_name[IF_NAMESIZE];
+  ip_address_t ip_address;
+  uint32_t table_id;
+  uint8_t priority;
+  uint8_t address_family;
+};
+
+struct ip_route_state_ {
+  char remote_ip_address[128];  // this is to big, but it is fine for now
+  uint8_t address_family;
+  uint32_t table_id;
+};
+
+typedef struct ip_rule_state_ ip_rule_state;
+typedef struct ip_route_state_ ip_route_state;
+
+int punting_table_id;
+uint16_t rules_counter;
+uint16_t routes_counter;
+static ip_rule_state rules_to_remove[MAX_TABLES];
+static ip_route_state routes_to_remove[MAX_TABLES];
+
+// END FIXME
+
+hicn_socket_helper_t *hicn_create() {
+  int rc;
+
+  punting_table_id = -1;
+  rules_counter = 0;
+
+  hicn_socket_helper_t *hicn = malloc(sizeof(hicn_socket_helper_t));
+  if (!hicn) {
+    goto ERR_MALLOC;
+  }
+
+  hicn->conf = malloc(sizeof(hicn_conf_t));
+  if (hicn->conf < 0) goto ERR_CONF;
+  memcpy(hicn->conf, &hicn_default_conf, sizeof(hicn_conf_t));
+
+  /* Initialize socket tree to empty */
+  hicn->socket_root = NULL;
+
+  // enable forwarding globally. Per-interface forwarding will be enabled when
+  // interfaces are created (TODO)
+  rc = ops.enable_v6_forwarding(NULL);
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  rc = ops.enable_v4_forwarding();
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  // modify priority of table local
+  /* ip -6 rule del from all prio 0 table local */
+  /* ip -6 rule add from all prio 32000 table local */
+
+  rc = ops.del_lo_prio_rule(NULL, AF_INET6, 0);
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  rc = ops.del_lo_prio_rule(NULL, AF_INET, 0);
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  rc = ops.add_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY);
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  rc = ops.add_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY);
+  if (rc < 0) {
+    goto ERR_FW;
+  }
+
+  return hicn;
+
+ERR_FW:
+  free(hicn->conf);
+ERR_CONF:
+  free(hicn);
+ERR_MALLOC:
+  return NULL;
+}
+
+void hicn_destroy() {
+  int rc;
+  uint16_t i;
+
+  /* Restore default rules */
+  printf("Restoring default configuration.\n");
+  rc = ops.del_lo_prio_rule(NULL, AF_INET6, LOCAL_PRIORITY);
+  if (rc < 0) {
+    goto ERR;
+  }
+
+  rc = ops.del_lo_prio_rule(NULL, AF_INET, LOCAL_PRIORITY);
+  if (rc < 0) {
+    goto ERR;
+  }
+
+  rc = ops.add_lo_prio_rule(NULL, AF_INET6, 0);
+  if (rc < 0) {
+    goto ERR;
+  }
+
+  rc = ops.add_lo_prio_rule(NULL, AF_INET, 0);
+  if (rc < 0) {
+    goto ERR;
+  }
+
+  for (i = 0; i < rules_counter; i++) {
+    if (strcmp(rules_to_remove[i].tun_name, "NONE") != 0) {
+      rc = ops.del_rule(rules_to_remove[i].tun_name,
+                        rules_to_remove[i].address_family,
+                        rules_to_remove[i].table_id);
+      if (rc < 0) {
+        goto ERR;
+      }
+    } else {
+      rc = ops.del_prio_rule(
+          &rules_to_remove[i].ip_address, rules_to_remove[i].address_family,
+          rules_to_remove[i].priority, rules_to_remove[i].table_id);
+      if (rc < 0) {
+        goto ERR;
+      }
+    }
+  }
+
+  for (i = 0; i < routes_counter; i++) {
+    rc = ops.del_out_route(routes_to_remove[i].remote_ip_address,
+                           routes_to_remove[i].address_family,
+                           routes_to_remove[i].table_id);
+    if (rc < 0) {
+      goto ERR;
+    }
+  }
+
+ERR:
+  if (rc < 0) printf("Unexpected exit. Some state may not be deleted.\n");
+  return;
+}
+
+void hicn_free(hicn_socket_helper_t *hicn) {
+  // close tun ?
+  free(hicn);
+}
+
+hicn_socket_t *hicn_socket_create() {
+  hicn_socket_t *socket = calloc(1, sizeof(hicn_socket_t));
+  if (!socket) {
+    goto ERR_SOCKET;
+  }
+  socket->type = HS_UNSPEC;
+
+  return socket;
+
+ERR_SOCKET:
+  return NULL;
+}
+
+int hicn_socket_cmp(hicn_socket_t *a, hicn_socket_t *b) {
+  return b->fd - a->fd;
+}
+
+ip_address_t *hicn_socket_get_src_ip(hicn_socket_t *socket) {
+  if (socket->type != HS_CONNECTION) {
+    return NULL;
+  }
+  return &socket->connection.tun_ip_address;
+}
+
+typedef int (*cmp_t)(const void *, const void *);
+
+int hicn_socket_add(hicn_socket_helper_t *hicn, hicn_socket_t *socket) {
+  if (!(tsearch(socket, &hicn->socket_root, (cmp_t)hicn_socket_cmp))) {
+    // ERROR("Could not insert field id into index");
+    return -1;
+  }
+  return 0;
+}
+
+hicn_socket_t *hicn_socket_find(hicn_socket_helper_t *hicn, int fd) {
+  hicn_socket_t search = {
+      .fd = fd,
+  };
+  hicn_socket_t **socket =
+      tfind(&search, &hicn->socket_root, (cmp_t)hicn_socket_cmp);
+  return socket ? *socket : NULL;
+}
+
+/*******************************************************************************
+ * New API
+ *******************************************************************************/
+
+int hicn_set_local_endpoint(hicn_socket_t *socket, const char *local_ip_address,
+                            bool allow_null) {
+  int rc = HICN_SOCKET_ERROR_NONE;
+
+  if (!local_ip_address) {
+    if (!allow_null) {
+      rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_NULL_ADDRESS;
+    }
+    goto end;
+  }
+
+  /* local_ip_address should be a prefix with global scope in which to pick
+   * the locator address to use as the source.
+   * If we expect to pick another IP for the tun, then it needs to be of size
+   * less than 128.
+   */
+
+  /* Copy the local IP address inside the connection */
+  rc = hicn_ip_pton(local_ip_address, &socket->connection.tun_ip_address);
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR;
+    goto end;
+  }
+
+end:
+  return rc;
+}
+
+// XXX This could be used by hicn_set_remote_endpoint
+// XXX This has been introduced for mapme
+int hicn_get_local_address(const ip_address_t *remote_address,
+                           ip_address_t *local_address) {
+  int rc = 0;
+  uint32_t interface_id;
+  char remote_address_str[INET_MAX_ADDRSTRLEN];
+
+  rc = hicn_ip_ntop(remote_address, remote_address_str,
+                    sizeof(remote_address_str));
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
+    goto ERR;
+  }
+
+  rc = ops.get_output_ifid(remote_address_str, remote_address->family,
+                           &interface_id);
+  if (rc < 0 || interface_id == 0) {
+    rc = HICN_SOCKET_ERROR_BIND_REMOTE_INTERFACE;
+    goto ERR;
+  }
+
+  /* Local ip */
+  rc = ops.get_ip_addr(interface_id, remote_address->family, local_address);
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_BIND_REMOTE_NETMASK;
+    goto ERR;
+  }
+
+ERR:
+  return rc;
+}
+
+/**
+ *
+ * sets socket->interface_id
+ */
+int hicn_set_remote_endpoint(hicn_socket_t *socket,
+                             const char *remote_ip_address) {
+  int af, rc = HICN_SOCKET_ERROR_NONE;
+  ip_address_t addr;
+
+  af = get_addr_family(remote_ip_address);
+  if ((af != AF_INET6) && (af != AF_INET)) {
+    return HICN_SOCKET_ERROR_INVALID_IP_ADDRESS;
+  }
+
+  /* Bind local endpoint if not done yet */
+  if (ip_address_empty(&socket->connection.tun_ip_address)) {
+    char local_ip_address[INET_MAX_ADDRSTRLEN];
+
+    /* Local interface id */
+    // INFO("Getting interface_id from gateway IP address %s",
+    // remote_ip_address);
+    /////
+    int addr_family = get_addr_family(remote_ip_address);
+    if (addr_family < 0) {
+      rc = addr_family;
+      goto ERR;
+    }
+
+    rc = ops.get_output_ifid(remote_ip_address, (uint8_t)addr_family,
+                             &socket->connection.interface_id);
+    if (rc < 0 || socket->connection.interface_id == 0) {
+      rc = HICN_SOCKET_ERROR_BIND_REMOTE_INTERFACE;
+      goto ERR;
+    }
+
+    /* Local ip */
+    rc = ops.get_ip_addr(socket->connection.interface_id, (uint8_t)addr_family,
+                         &addr);
+    if (rc < 0) {
+      rc = HICN_SOCKET_ERROR_BIND_REMOTE_NETMASK;
+      goto ERR;
+    }
+    /////
+
+    /* Convert to representation format */
+    rc = hicn_ip_ntop(&addr, local_ip_address, sizeof(local_ip_address));
+    if (rc < 0) {
+      rc = HICN_SOCKET_ERROR_BIND_REMOTE_REPR;
+      goto ERR;
+    }
+
+    rc = hicn_set_local_endpoint(socket, local_ip_address, true);
+    if (rc < 0) {
+      switch (rc) {
+        case HICN_SOCKET_ERROR_SOCKET_LOCAL_NULL_ADDRESS:
+          rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_NULL_ADDR;
+          break;
+        case HICN_SOCKET_ERROR_SOCKET_LOCAL_REPR:
+          rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_REPR;
+          break;
+        case HICN_SOCKET_ERROR_SOCKET_LOCAL_HEURISTIC:
+          rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_HEURISTIC;
+          break;
+        case HICN_SOCKET_ERROR_SOCKET_LOCAL_SET_TUN_IP:
+          rc = HICN_SOCKET_ERROR_BIND_REMOTE_LOCAL_SET_TUN_IP;
+          break;
+      }
+      goto ERR;
+    }
+  }
+  return HICN_SOCKET_ERROR_NONE;
+
+ERR:
+  return rc;
+}
+
+/**
+ *
+ * We need at least an identifier.
+ */
+int hicn_socket(hicn_socket_helper_t *hicn, const char *identifier,
+                const char *local_ip_address) {
+  int rc;
+
+  hicn_socket_t *socket = hicn_socket_create();
+  if (!socket) {
+    rc = -5;
+    goto ERR_SOCKET;
+  }
+
+  ops.get_tun_name(hicn->conf->identifier, identifier, socket->tun_name);
+
+  // register the hicn face on which to bind prefixes, create the in/out TUN
+  // device
+  socket->fd = ops.tun_create(socket->tun_name);
+  if (socket->fd <= 0) {
+    rc = -2;
+    goto ERR_TUN;
+  }
+
+  // INFO("Successfully created listener on TUN device %s", socket->tun_name);
+
+  /* Retrieve interface id */
+  socket->tun_id = ops.get_ifid(socket->tun_name);
+  if (socket->tun_id < 0) {
+    rc = -3;
+    goto ERR_TUNIFID;
+  }
+  // INFO("Interface id=%d", socket->tun_id);
+
+  // WARN("Need to set offload");
+
+  // INFO("Setting interface up");
+  rc = ops.up_if(socket->tun_id);
+  if (rc < 0) {
+    rc = -4;
+    goto ERR_UP;
+  }
+
+  /* Update state */
+  rc = hicn_socket_add(hicn, socket);
+  if (rc < 0) {
+    rc = -5;
+    goto ERR_ADD;
+  }
+
+  rc = hicn_set_local_endpoint(socket, local_ip_address, true);
+  if (rc < 0) {
+    rc = -6;
+    goto ERR_ADJACENCY;
+  }
+
+  return socket->fd;
+
+ERR_ADJACENCY:
+ERR_ADD:
+ERR_UP:
+ERR_TUNIFID:
+ERR_TUN:
+  free(socket);
+ERR_SOCKET:
+  // ERR_PARAMS:
+  return rc;
+}
+
+int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix) {
+  int rc;
+  hicn_socket_t *socket = hicn_socket_find(hicn, fd);
+  if (!socket) {
+    return -1;
+  }
+
+  /* Check socket is not a connection */
+  if (socket->type == HS_CONNECTION) {
+    return -1;
+  }
+
+  rc = ops.add_in_route_s(prefix, socket->tun_id);
+  if (rc < 0) {
+    return rc;
+  }
+
+  ip_address_t ip_address;
+  rc = hicn_ip_pton(prefix, &ip_address);
+  if (rc < 0) {
+    return rc;
+  }
+
+  // ip -6 rule add from b001::/16 prio 0 table 100
+  socket->connection.table_id =
+      socket->tun_id % MAX_TABLES;  // this table should be unused
+
+  if (punting_table_id == -1) punting_table_id = socket->connection.table_id;
+
+  rc = ops.add_prio_rule(&ip_address, ip_address.family, 0,
+                         socket->connection.table_id);
+  if (rc < 0) {
+    return rc;
+  }
+
+  strcpy(rules_to_remove[rules_counter].tun_name, "NONE");
+
+  rules_to_remove[rules_counter].ip_address = ip_address;
+  rules_to_remove[rules_counter].address_family = ip_address.family;
+  rules_to_remove[rules_counter].table_id = socket->connection.table_id;
+  rules_to_remove[rules_counter].priority = 0;
+  ++rules_counter;
+
+  /* Update socket upon success */
+  socket->type = HS_LISTENER;
+
+  return 0;
+}
+
+/**
+ *
+ * We can pass all adjacency parameters but identifier
+ */
+int hicn_bind(hicn_socket_helper_t *hicn, int fd,
+              const char *remote_ip_address) {
+  // uint32_t interface_id;
+  int rc = HICN_SOCKET_ERROR_NONE;
+
+  hicn_socket_t *socket = hicn_socket_find(hicn, fd);
+  if (!socket) {
+    rc = HICN_SOCKET_ERROR_BIND_SOCKET_NOT_FOUND;
+    goto ERR;
+  }
+
+  /* We allow reuse */
+  if (socket->type == HS_CONNECTION) return rc;
+
+  /* Check socket is not a connection */
+  if (socket->type != HS_UNSPEC) {
+    rc = HICN_SOCKET_ERROR_BIND_SOCKET_ALREADY_BOUND;
+    goto ERR;
+  }
+  socket->type = HS_CONNECTION;
+
+  // each connection is associated a table id, let's take it equal to the
+  // tun ID by default (% MAX_TABLES, assuming TUN IDs do not overlap modulo
+  // 256...).
+  // XXX we need to make sure the corresponding table is flushed.
+  socket->connection.table_id =
+      socket->tun_id % MAX_TABLES;  // interface_id; // ops.get_free_table_id();
+
+  // XXX use IP address
+  rc = hicn_set_remote_endpoint(socket, remote_ip_address);
+  if (rc < 0) {
+    goto ERR;
+  }
+
+  // rule
+  // ip -6 rule from all iif eth0 lookup 200
+  // INFO("Adding output rule for %s in table %d", socket->tun_name,
+  //        socket->connection.table_id);
+  int addr_family = get_addr_family(remote_ip_address);
+  if (addr_family < 0) {
+    rc = addr_family;
+    goto ERR;
+  }
+
+  rc = ops.add_rule(socket->tun_name, (uint8_t)addr_family,
+                    socket->connection.table_id);
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_BIND_RULE;
+    goto ERR;
+  }
+
+  strcpy(rules_to_remove[rules_counter].tun_name, socket->tun_name);
+  rules_to_remove[rules_counter].address_family = addr_family;
+  rules_to_remove[rules_counter].table_id = socket->connection.table_id;
+  ++rules_counter;
+
+  // route
+  // ip -6 route add default via 2002::2 table 28
+  // INFO("Adding output route in table %d via gateway %s",
+  // socket->connection.table_id,
+  //        remote_ip_address);
+
+  // if the address is an IPv6 and start with fe80 we need to specify the device
+  // in the route
+  u32 default_interface = ~0;
+  if (addr_family == AF_INET6 && strncmp(LOCAL_IPV6_PREFIX, remote_ip_address,
+                                         strlen(LOCAL_IPV6_PREFIX)) == 0) {
+    rc = ops.get_output_ifid(remote_ip_address, (uint8_t)addr_family,
+                             &default_interface);
+    if (rc < 0) {
+      goto ERR;
+    }
+  }
+
+  rc = ops.add_out_route(remote_ip_address, (uint8_t)addr_family,
+                         socket->connection.table_id, default_interface);
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_BIND_ROUTE;
+    goto ERR;
+  }
+
+  strcpy(routes_to_remove[routes_counter].remote_ip_address, remote_ip_address);
+  routes_to_remove[routes_counter].table_id = socket->connection.table_id;
+  routes_to_remove[routes_counter].address_family = (uint8_t)addr_family;
+  ++routes_counter;
+
+  // add route for data
+  // ip -6 route add 0:1::/64 dev hicn-if0 table 100
+  // this routes are deleted by removing the tun interfaces
+
+  if (punting_table_id == -1) {
+    // the punting_table_id was not initialized beacause no main-tun was created
+    // we use as an id (socket->tun_id - 1) % MAX_TABLES, so that we will hava a
+    // collision only after 255 new interfaces
+    punting_table_id = (socket->tun_id - 1) % MAX_TABLES;
+  }
+  rc = ops.add_in_route_table(&socket->connection.tun_ip_address,
+                              socket->tun_id, punting_table_id);
+  if (rc < 0) {
+    rc = HICN_SOCKET_ERROR_BIND_ROUTE;
+    goto ERR;
+  }
+
+ERR:
+  return rc;
+}
diff --git a/hicn-light/src/socket/api.h b/hicn-light/src/socket/api.h
new file mode 100755 (executable)
index 0000000..e1516eb
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hicn_face.h
+ * @brief hICN socket library
+ *
+ * This module provides an interface to managing so-called hICN sockets,
+ * realizing punting of interest and data packets using a TUN device.
+ */
+
+#ifndef HICN_SOCKET_API_H
+#define HICN_SOCKET_API_H
+
+#include <stdint.h>  // uint*_t
+#include <stdlib.h>
+
+#include <hicn/hicn.h>
+#include "error.h"
+
+#define BUFSIZE 4096
+#define MAX_CONNECTIONS \
+  255  // We currently limit the number of connections we can establish
+#define IF_NAMESIZE 16
+
+/* hICN socket helper */
+
+/** hICN configuration options */
+typedef struct {
+  // uint32_t interval;
+
+  /* Identifier used to name hICN TUN interfaces (should be unique) */
+  char *identifier;
+  // hicn_format_t format;
+
+} hicn_conf_t;
+
+/**
+ * hICN adjacency
+ */
+typedef struct {
+  char *local_ip_address;
+  char *gateway_ip_address;
+} hicn_adjacency_t;
+
+#define EMPTY_HICN_ADJACENCY \
+  (hicn_adjacency_t) { 0, 0 }
+
+/* hICN socket operations */
+
+typedef struct {
+  uint8_t pkbuf[BUFSIZE];
+  uint32_t rb_pkbuf_r;
+  uint32_t rb_pkbuf_w;
+} hicn_buffer_t;
+
+typedef enum { HS_UNSPEC, HS_LISTENER, HS_CONNECTION } hicn_socket_type_t;
+
+typedef struct hicn_socket_s {
+  hicn_socket_type_t type;
+  int fd;
+
+  /* Implementation specific state follows */
+  char tun_name[IF_NAMESIZE];
+  uint32_t tun_id;
+
+  hicn_buffer_t buffer;
+  void (*cb)(struct hicn_socket_s *, void *, uint8_t *, size_t);
+  void *cb_data;
+
+  union {
+    struct {
+      ip_address_t tun_ip_address;
+      uint32_t interface_id;
+
+      /* ID of the corresponding table : avoid default values of 0, 32766 and
+       * 32767 */
+      uint8_t table_id;
+    } connection;
+  };
+} hicn_socket_t;
+
+/**
+ * hICN global state
+ */
+typedef struct {
+  /* Configuration data */
+  hicn_conf_t *conf;
+
+  // We need state associate to each FD, to know what type of socket it is and
+  // its state.
+  void *socket_root; /**< A tree of socket indexed by their fd */
+
+} hicn_socket_helper_t;
+
+/**
+ * Create an hICN instance.
+ *
+ * This is used to configure the state of an hICN router consistently between
+ * a listener and the different connections. It also regroups all the state
+ * related to hICN functionalities.
+ *
+ * @return A pointer to an hICN instance.
+ */
+hicn_socket_helper_t *hicn_create();
+
+void hicn_destroy();
+
+/**
+ * Retrieve hICN configuration.
+ *
+ * Gets the current configuration of an hICN instance for information purposes,
+ * or later update it.
+ *
+ * TODO
+ *  - We might want to prevent configuration updates while the hICN instance is
+ *  running. Define running...
+ *
+ * @param [in] hicn Pointer to hICN instance.
+ * @return Pointer to an hICN configuration data structure.
+ *
+ * @see hicn_set_conf
+ */
+hicn_conf_t *hicn_get_conf(hicn_socket_helper_t *hicn);
+
+/**
+ * Update hICN configuration.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] hicn_conf Pointer to an hICN configuration data structure.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * @see hicn_get_conf
+ */
+int hicn_set_conf(hicn_socket_helper_t *hicn, hicn_conf_t *hicn_conf);
+
+/**
+ * Release hICN state.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ */
+void hicn_free(hicn_socket_helper_t *hicn);
+
+// FIXME doc
+int hicn_get_local_address(const ip_address_t *remote_address,
+                           ip_address_t *local_address);
+
+/* hICN socket */
+
+/**
+ * Create an hICN socket.
+ *
+ * An hICN socket abstracts the underlying implementation and allows hICN
+ * packets to be sent and received independently of the underlying
+ * implementation.
+ *
+ * It is possible to further specialize the socket in a listener socket, and a
+ * connection socket.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] identifier Unique identifier for this socket, used to named the
+ *      TUN device
+ * @param [in] local_ip_address IP address used locally by the socket (or NULL
+ *      for letting the library decide automatically).
+ * @return File descriptor (>0) in case of success, -1 otherwise.
+ *
+ * @see hicn_listen
+ * @see hicn_bind
+ */
+int hicn_socket(hicn_socket_helper_t *hicn, const char *identifier,
+                const char *local_ip_address);
+
+/**
+ * Packet punting.
+ *
+ * Note that we cannot listen on a socket that is already bound.
+ *
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] fd File descriptor identifying the hICN socket.
+ * @param [in] prefix Prefix (IPv4 or IPv6) to be bound to hICN in
+ *    RFC-compliant presentation format.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * @see hicn_socket
+ */
+int hicn_listen(hicn_socket_helper_t *hicn, int fd, const char *prefix);
+
+/**
+ * Packet forwarding
+ * @param [in] hicn Pointer to an hICN instance.
+ * @param [in] fd File descriptor identifying the hICN socket.
+ * @param [in] prefix Prefix (IPv4 or IPv6) to be bound to hICN in
+ *    RFC-compliant presentation format.
+ * @return 0 in case of success, -1 otherwise.
+ *
+ * XXX adjacency does not perform any copy heresofar
+ *
+ * @see hicn_socket
+ */
+int hicn_bind(hicn_socket_helper_t *hicn, int fd,
+              const char *remote_ip_address);
+
+#endif /* HICN_SOCKET_API_H */
diff --git a/hicn-light/src/socket/error.c b/hicn-light/src/socket/error.c
new file mode 100755 (executable)
index 0000000..3dafec8
--- /dev/null
@@ -0,0 +1,7 @@
+#include "error.h"
+
+const char* HICN_SOCKET_ERROR_STRING[] = {
+#define _(a, b, c) [b] = c,
+    foreach_hicn_socket_error
+#undef _
+};
diff --git a/hicn-light/src/socket/error.h b/hicn-light/src/socket/error.h
new file mode 100755 (executable)
index 0000000..8195efd
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef HICN_SOCKET_ERROR_H
+#define HICN_SOCKET_ERROR_H
+
+// FIXME remove unused errors
+#define foreach_hicn_socket_error                                             \
+  _(NONE, 0, "OK")                                                            \
+  _(UNSPEC, 1, "unspecified error")                                           \
+  _(NOT_HICN, 2, "not a hICN paclet")                                         \
+  _(UNKNOWN_ADDRESS, 10, "unknown address")                                   \
+  _(INVALID_PARAMETER, 20, "invalid parameter")                               \
+  _(INVALID_IP_ADDRESS, 21, "invalid IP address")                             \
+  _(CORRUPTED_PACKET, 22, "corrupted packet")                                 \
+  _(UNEXPECTED, 98, "unexpected error")                                       \
+  _(NOT_IMPLEMENTED, 99, "not implemented")                                   \
+  _(SOCKET_LOCAL_NULL_ADDRESS, 101, "empty local address")                    \
+  _(SOCKET_LOCAL_REPR, 102, "cannot represent local address")                 \
+  _(SOCKET_LOCAL_HEURISTIC, 103, "error finding local address")               \
+  _(SOCKET_LOCAL_SET_TUN_IP, 104, "cannot set local IP to TUN")               \
+  _(BIND_SOCKET_NOT_FOUND, 301, "bind: socket not found")                     \
+  _(BIND_SOCKET_ALREADY_BOUND, 302, "bind: socket already bound")             \
+  _(BIND_REMOTE_INTERFACE, 303, "bind: no interface towards gateway")         \
+  _(BIND_REMOTE_NETMASK, 304, "bind: no local IP with netmask < 128")         \
+  _(BIND_REMOTE_REPR, 305, "bind: error representing local IP")               \
+  _(BIND_REMOTE_LOCAL_NULL_ADDR, 306, "bind: could not set local endpoint")   \
+  _(BIND_REMOTE_LOCAL_REPR, 307, "bind: error representing remote IP")        \
+  _(BIND_REMOTE_LOCAL_HEURISTIC, 308, "bind: could not apply heuristic")      \
+  _(BIND_REMOTE_LOCAL_SET_TUN_IP, 309, "bind: error setting local IP to TUN") \
+  _(BIND_NDP, 310, "bind: could not enable NDP proxy")                        \
+  _(BIND_NEIGH_PROXY, 311, "bind: could not neighbour")                       \
+  _(BIND_REPR, 312, "bind: error represeting IP")                             \
+  _(BIND_LO, 313, "bind: could not remove local route")                       \
+  _(BIND_RULE, 314, "bind: could not add rule")                               \
+  _(BIND_ROUTE, 315, "bind: could not add output route")
+
+typedef enum {
+#define _(a, b, c) HICN_SOCKET_ERROR_##a = (-b),
+  foreach_hicn_socket_error
+#undef _
+      HICN_SOCKET_N_ERROR,
+} hicn_socket_error_t;
+
+extern const char *HICN_SOCKET_ERROR_STRING[];
+
+#define hicn_socket_strerror(errno) (char *)(HICN_SOCKET_ERROR_STRING[-errno])
+
+#endif /* HICN_SOCKET_ERROR_H */
diff --git a/hicn-light/src/socket/ops.h b/hicn-light/src/socket/ops.h
new file mode 100755 (executable)
index 0000000..249caf8
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef HICN_SOCKET_OPS_H
+#define HICN_SOCKET_OPS_H
+
+#include <hicn/hicn.h>
+#include <stdint.h>
+
+typedef struct {
+  char *arch;
+  int (*tun_create)(char *name);
+  int (*get_tun_name)(const char *prefix, const char *identifier,
+                      char *tun_name);
+  int (*enable_v6_forwarding)(char *interface_name);
+  int (*enable_v4_forwarding)();
+  int (*enable_ndp_proxy)();
+
+  uint32_t (*get_ifid)(const char *ifname);
+  int (*get_output_ifid)(const char *ip_address, uint8_t address_family,
+                         uint32_t *interface_id);
+  int (*get_ip_addr)(uint32_t interface_id, uint8_t address_family,
+                     ip_address_t *ip_address);
+  int (*set_ip_addr)(uint32_t interface_id, ip_address_t *ip_address);
+  int (*up_if)(uint32_t interface_id);
+  int (*add_in_route_table)(const ip_address_t *prefix,
+                            const uint32_t interface_id,
+                            const uint8_t table_id);
+  int (*add_in_route_table_s)(const char *prefix, const uint32_t interface_id,
+                              const uint8_t table_id);
+  int (*add_in_route_s)(const char *prefix, const uint32_t interface_id);
+  int (*add_out_route)(const char *gateway, const uint8_t address_family,
+                       const uint8_t table_id, int default_route);
+  int (*del_out_route)(const char *gateway, const uint8_t address_family,
+                       const uint8_t table_id);
+  int (*del_lo_route)(const ip_address_t *ip_address);
+  int (*add_rule)(const char *interface_name, const uint8_t address_family,
+                  const uint8_t table_id);
+  int (*del_rule)(const char *interface_name, const uint8_t address_family,
+                  const uint8_t table_id);
+  int (*add_neigh_proxy)(const ip_address_t *ip_address,
+                         const uint32_t interface_id);
+  int (*add_prio_rule)(const ip_address_t *ip_address,
+                       const uint8_t address_family, const uint32_t priority,
+                       const uint8_t table_id);
+  int (*add_lo_prio_rule)(const ip_address_t *ip_address,
+                          const uint8_t address_family,
+                          const uint32_t priority);
+  int (*del_prio_rule)(const ip_address_t *ip_address,
+                       const uint8_t address_family, const uint32_t priority,
+                       const uint8_t table_id);
+  int (*del_lo_prio_rule)(const ip_address_t *ip_address,
+                          const uint8_t address_family,
+                          const uint32_t priority);
+} hicn_socket_ops_t;
+
+#endif /* HICN_SOCKET_OPS_H */
diff --git a/hicn-light/src/socket/ops_linux.c b/hicn-light/src/socket/ops_linux.c
new file mode 100755 (executable)
index 0000000..d085f0d
--- /dev/null
@@ -0,0 +1,1723 @@
+#include <sys/ioctl.h>   // ioctl
+#include <sys/socket.h>  // needed by linux/if.h
+//#include <linux/if.h>
+#include <errno.h>
+#include <fcntl.h>  // ''
+#include <linux/if_tun.h>
+#include <linux/limits.h>  // PATH_MAX
+#include <stdio.h>         // fprintf
+#include <string.h>        // memset
+#include <sys/stat.h>      // open
+#include <sys/uio.h>       // writev
+#include <unistd.h>        // close
+
+#include "error.h"
+#include "ops.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+/******************************************************************************
+ * netlink.h
+ ******************************************************************************/
+
+#ifndef HICN_NETLINK_H
+#define HICN_NETLINK_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+// DEPRECATED|/* Socket */
+// DEPRECATED|int _nl_get_socket();
+// DEPRECATED|int _nl_send(int s, uint8_t * buffer, size_t len);
+// DEPRECATED|size_t _nl_receive(uint8_t * buffer, size_t len);
+// DEPRECATED|
+// DEPRECATED|/* Netlink packet format */
+// DEPRECATED|int _nl_header(int request, uint8_t * buffer, size_t len, uint32_t
+// flags); DEPRECATED|int _nl_payload_rule(uint8_t table_id, uint8_t * buffer,
+// size_t len); DEPRECATED|int _nl_payload_link(uint32_t ifindex, uint8_t *
+// buffer, size_t len); DEPRECATED|int _nl_payload_route(uint8_t table_id,
+// uint8_t dst_len, uint8_t * buffer, size_t len); DEPRECATED| DEPRECATED|int
+// _nl_parse(uint8_t * buffer, size_t len); DEPRECATED|int _nl_parse_ret(uint8_t
+// * buffer, size_t len); DEPRECATED|int _nl_parse_link_ifid(uint8_t * buffer,
+// size_t len, uint32_t * interface_id); DEPRECATED|int
+// _nl_parse_link_ip_addr(uint8_t * buffer, size_t len, struct in6_addr * addr);
+
+/* Public interface */
+
+/**
+ * Get the interface ID of an interface by its name
+ *
+ * @return 32-bit interface identifier in case of success, or 0.
+ *
+ * @see if_nametoindex
+ *
+ */
+uint32_t _nl_get_ifid(const char *ifname);
+
+/**
+ * Retrieve the output interface corresponding to the specified IP address.
+ *
+ * @param [in] addr IP(v6) address in presentation form.
+ * @param [out] Identifier of the corresponding output interface.
+ * @return int 0 in case of success, -1 otherwise
+ */
+int _nl_get_output_ifid(const char *ip_address, uint8_t address_family,
+                        uint32_t *interface_id);
+
+/**
+ * Retrieve the first IP address of an interface (identified by its id) which
+ * has a netmask < 128.
+ *
+ * @param [in] s File descriptor of the netlink socket (deprecated).
+ * @param [in] interface_id Identifier of the interface for which to retrieve
+ *      the IP address.
+ * @param [out] addr IP(v6) address in binary form.
+ * @return int 0 in case of success, -1 otherwise
+ *
+ * @see getifaddrs
+ */
+int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
+                    ip_address_t *ip_address);
+
+int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address);
+
+int _nl_up_if(uint32_t interface_id);
+
+int _nl_add_in_route_table(const ip_address_t *prefix,
+                           const uint32_t interface_id, const uint8_t table_id);
+int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id,
+                             const uint8_t table_id);
+int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id);
+
+int _nl_add_out_route(const char *gateway, const uint8_t address_family,
+                      const uint8_t table_idi, int default_route);
+int _nl_del_out_route(const char *gateway, const uint8_t address_family,
+                      const uint8_t table_id);
+
+int _nl_del_lo_route(const ip_address_t *ip_address);
+
+int _nl_add_rule(const char *interface_name, const uint8_t address_family,
+                 const uint8_t table_id);
+int _nl_del_rule(const char *interface_name, const uint8_t address_family,
+                 const uint8_t table_id);
+
+int _nl_add_neigh_proxy(const ip_address_t *ip_address,
+                        const uint32_t interface_id);
+
+int _nl_add_prio_rule(const ip_address_t *ip_address,
+                      const uint8_t address_family, const uint32_t priority,
+                      const uint8_t table_id);
+int _nl_add_lo_prio_rule(const ip_address_t *ip_address,
+                         const uint8_t address_family, const uint32_t priority);
+int _nl_del_prio_rule(const ip_address_t *ip_address,
+                      const uint8_t address_family, const uint32_t priority,
+                      const uint8_t table_id);
+int _nl_del_lo_prio_rule(const ip_address_t *ip_address,
+                         const uint8_t address_family, const uint32_t priority);
+
+#endif /* HICN_NETLINK_H */
+
+/******************************************************************************
+ * netlink.c
+ ******************************************************************************/
+
+/*
+ * This module offers an interface to the Netlink API appropriate for
+ * implementing punting as required by hICN (1).
+ *
+ * More specifically, it consists of the following functionalities:
+ *  - LINK
+       . map interface name to ID
+       . set and interface up
+ *  - ADDR
+       . get and set ip addresses on a given interface ID
+ *  - ROUTE
+       . get output interface id towards IP (ip route get IP > interface_id)
+       . add input route (ip route add PREFIX dev INTERFACE) for punting
+ interests . add output route (ip route add default GATEWAY table TABLE) for
+ routing interests (2, 3) . delete local route towards IP (ip route del IP table
+ local) for ???
+         /!\ could this be avoided by removing the local attribute in the
+ netlink call ?
+ *  - RULE
+ *     . add output rule (ip rule add iif interface table TABLE) for routing
+ interests (2, 3)
+ *  - ND PROXY
+ *     . enable NDP proxy functionality for IP on interface ID (ip -6 neigh add
+ proxy IP dev INTERFACE)
+ *       for allowing the TUN to be reachable on the reverse data path
+ *
+ * Implementation notes:
+ *  (1) We have not been using the libnl library because it requires
+ *      manipulating too many function and data structures for a simple purpose.
+ *      Currently, many parts of the code are somehow repetitive, but this might
+ *      be improved by a proper API in a future release.
+ *  (2) allows load balancing over different interfaces = multihoming. Please
+ *      note that it is not possible to have load balancing over two faces using
+ *      the same output interface as we are using the underlying IP network !
+ *      This might be mitigated with the use of SR however.
+ *  (3) The implementation of punting heavily uses the policy routing
+ *      functionalities, as we need to hook through a TUN into user space a
+ *      whole prefix used as a destination (for interests) or source (for data
+ *      packets). We thus combine the use of rules to assign routing table IDs,
+ *      and routes inside those tables. As there is no easy way to allocate
+ *      which routing tables we use, we made the choice to index them by the ID
+ *      of the interface, assuming there is no external conflict. This might be
+ *      improved in the future.
+ *
+ *      This hICN implementation uses TUNs in two different ways:
+ *       - a main TUN interface, which receives all punted interests,
+ *       demultiplex them before assigning them an input face (eventually
+ *       dynamically creating it);
+ *       - a set of output TUN interfaces, aka faces, used for routing of
+ *       interests, and for receiving the corresponding data packets on the way
+ *       back. Punting of data packets if based of their destination IP, which
+ *       is the IP of the physical output interface used for the interest, which
+ *       is unique (cf (2)).
+ *
+ *      The corresponding routing tables IDs are :
+ *       MAIN_TUN_ID -> used for punting of data packets
+ *       OUTPUT_TUN_ID_i -> used for routing of interests towards next hop
+ *       (bypassing local IP routing table)
+ *
+ *      Note that punting of interests is done just through a route, and routing
+ *      of data packets is done just through the regular IP routing table on the
+ *      note after the address translation done in the forwarder.
+ *
+ *   - Forging netlink packets
+ *
+ *     A previous implementation used function calls with pointers to populate
+ *     the various header parts in a buffer in order to build a netlink packet.
+ *     A newer implementation uses nested structs and iovecs to build the whole
+ *     packet in a single write call. This should allow a simpler evolution
+ *     towards a cleaner API.
+ */
+
+#include <arpa/inet.h>        // inet_pton
+#include <errno.h>            // errno
+#include <linux/fib_rules.h>  // fib_rule_hdr, FRA_*
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>      // IFF_UP
+#include <netinet/in.h>  // in6addr
+#include <stdio.h>       // perror
+#include <string.h>
+#include <sys/socket.h>  // ''
+#include <sys/types.h>   // socket
+#include <unistd.h>      // read
+
+#include <sys/socket.h>  // ''
+#include <sys/types.h>   // send, recv
+
+//#include "../../hicn.h"
+//#include "../../hicn_util.h"    // ARRAY_SIZE, hicn_packet_dump_iov
+
+#define BUFSIZE 4096
+#define FLAGS_CREATE NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK
+// ??
+#define FLAGS_CREATE_MATCH \
+  NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_MATCH
+
+// XXX putting ACK poses a prolem for the value received by get_if_id.
+#define FLAGS_GET NLM_F_REQUEST
+#define FLAGS_GET_ROOT (NLM_F_REQUEST | NLM_F_ROOT)
+
+#define FLAGS_LIST NLM_F_REQUEST | NLM_F_DUMP
+
+#define IF_NAMESIZE 16
+#define FR_ACT_TO_TBL 1
+#define NLMSG_BOTTOM(nlmsg) \
+  ((struct rtattr *)(((void *)(nlmsg)) + NLMSG_ALIGN((nlmsg)->nlmsg_len)))
+
+int seq = 1;
+
+static inline size_t iov_length(const struct iovec *iov,
+                                unsigned long nr_segs) {
+  unsigned long seg;
+  size_t ret = 0;
+
+  for (seg = 0; seg < nr_segs; seg++) ret += iov[seg].iov_len;
+  return ret;
+}
+
+typedef struct {
+  struct nlmsghdr hdr;
+  struct nlmsgerr payload;
+} nl_err_hdr_t;
+
+/* Low level : nl header */
+
+int _nl_get_socket() { return socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); }
+
+int _nl_header(int request, uint8_t *buffer, size_t len, uint32_t flags) {
+  struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+
+  nl->nlmsg_len = 0;  // NLMSG_LENGTH(sizeof(struct ifinfomsg));
+  nl->nlmsg_type = request;
+  nl->nlmsg_flags = flags;
+  nl->nlmsg_seq = seq++;  //
+  nl->nlmsg_pid = 0;      // getpid();
+
+  return 0;
+}
+
+/* Low level : nl protocols */
+
+/* Low level : attributes */
+
+int addAttr(struct nlmsghdr *nl, int maxlen, int type, void *data,
+            int attr_len) {
+  struct rtattr *rta;
+  int len = RTA_LENGTH(attr_len);
+
+  if (NLMSG_ALIGN(nl->nlmsg_len) + len > maxlen) {
+    exit(EXIT_FAILURE);
+  }
+
+  rta = (struct rtattr *)((char *)nl + NLMSG_ALIGN(nl->nlmsg_len));
+  rta->rta_type = type;
+  rta->rta_len = len;
+  memcpy(RTA_DATA(rta), data, attr_len);
+  nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + len;
+  return 0;
+}
+
+int _nl_payload_rule(uint8_t table_id, uint8_t address_family, uint8_t *buffer,
+                     size_t len) {
+  struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+  struct fib_rule_hdr *frh = (struct fib_rule_hdr *)(NLMSG_DATA(buffer));
+
+  memset(frh, 0, sizeof(struct fib_rule_hdr));
+  frh->family = address_family;
+  frh->table = table_id;
+  frh->action = FR_ACT_TO_TBL,
+  frh->flags = NLM_F_REPLACE;  // 0
+  frh->tos = 0;
+
+  nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
+
+  return 0;
+}
+
+int _nl_payload_link(uint32_t ifindex, uint8_t *buffer, size_t len) {
+  struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+  struct ifinfomsg *ifi = (struct ifinfomsg *)(NLMSG_DATA(buffer));
+
+  memset(ifi, 0, sizeof(struct ifinfomsg));
+  ifi->ifi_family = AF_UNSPEC;
+  // ifi->ifi_type = 0;
+  ifi->ifi_index =
+      ifindex;  // new interface, could be specified since linux 3.7
+  ifi->ifi_flags = 0;
+  // ifi->ifi_change = 0xffffffff;
+
+  nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+  return 0;
+}
+
+int _nl_payload_addr(uint32_t ifindex, uint8_t *buffer, size_t len) {
+  struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+  struct ifaddrmsg *addr = (struct ifaddrmsg *)(NLMSG_DATA(buffer));
+
+  memset(addr, 0, sizeof(struct ifaddrmsg));
+  addr->ifa_family = AF_UNSPEC;  // INET6;
+  /*
+     addr->ifa_prefixlen = 128;
+     addr->ifa_flags = 0;
+     addr->ifa_scope = RT_SCOPE_LINK; //IFA_ADDRESS;
+     addr->ifa_index = ifindex;
+     */
+
+  nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct ifaddrmsg)) - 4;
+
+  return 0;
+}
+
+int _nl_payload_route(uint8_t table_id, uint8_t addr_family, uint8_t dst_len,
+                      uint8_t *buffer, size_t len) {
+  struct nlmsghdr *nl = (struct nlmsghdr *)buffer;
+  struct rtmsg *raddr = (struct rtmsg *)(NLMSG_DATA(buffer));
+
+  raddr->rtm_family = addr_family;
+  raddr->rtm_dst_len = dst_len;
+  raddr->rtm_src_len = 0;
+  raddr->rtm_tos = 0;
+
+  raddr->rtm_table = table_id;
+  raddr->rtm_protocol = RTPROT_BOOT;
+  raddr->rtm_scope = RT_SCOPE_UNIVERSE;
+  raddr->rtm_type = RTN_UNICAST;
+
+  raddr->rtm_flags = 0;
+
+  nl->nlmsg_len += NLMSG_LENGTH(sizeof(struct rtmsg));
+
+  return 0;
+}
+
+uint32_t _nl_get_ifid(const char *interface_name) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+  size_t len = interface_name ? strlen(interface_name) + 1 : 0;
+  uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0};
+
+  if (len == 0) {
+    goto ERR_IF;
+  }
+
+  struct {
+    struct nlmsghdr hdr;
+    struct ifinfomsg payload;
+  } msg = {//.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+           .hdr.nlmsg_type = RTM_GETLINK,
+           .hdr.nlmsg_flags = FLAGS_GET,
+           .payload.ifi_family = AF_UNSPEC,
+           .payload.ifi_index = 0};
+  struct rtattr a_ifname = {RTA_LENGTH(strlen(interface_name) + 1),
+                            IFLA_IFNAME};
+
+  struct iovec iov[] = {{&msg, sizeof(msg)},
+                        {&a_ifname, sizeof(a_ifname)},
+                        {(char *)interface_name, len},
+                        {padding, RTA_SPACE(len) - RTA_LENGTH(len)}};
+  msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+  n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0; /* Unexpected */
+  }
+
+  for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+    struct ifinfomsg *payload = (struct ifinfomsg *)NLMSG_DATA(hdr);
+    return payload->ifi_index;
+  }
+  return 0;
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+ERR_IF:
+  return 0;
+}
+
+int _nl_get_output_ifid(const char *ip_address, uint8_t family_address,
+                        uint32_t *interface_id) {
+  int rc;
+
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  if (family_address == AF_INET6) {
+    struct in6_addr addr;  // V6SPECIFIC
+
+    struct {
+      struct nlmsghdr hdr;
+      struct rtmsg payload;
+    } msg = {
+        .hdr.nlmsg_type = RTM_GETROUTE,
+        .hdr.nlmsg_flags = NLM_F_REQUEST,
+        .hdr.nlmsg_seq = seq++,
+        .payload.rtm_family = AF_INET6,
+        .payload.rtm_dst_len = IPV6_ADDR_LEN_BITS,
+        .payload.rtm_src_len = 0,
+        .payload.rtm_tos = 0,
+        .payload.rtm_table = RT_TABLE_UNSPEC,
+        .payload.rtm_protocol = RTPROT_UNSPEC,
+        .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+        .payload.rtm_type = RTN_UNSPEC,
+        .payload.rtm_flags = 0  // RTM_F_NOTIFY in 'ip route get'
+    };
+
+    /* Convert the IP address to binary form */
+    rc = inet_pton(AF_INET6, ip_address, &addr);
+    if (rc <= 0) {
+      goto ERR;
+    }
+
+    /* Set attribute = length/type/value */
+    struct rtattr a_dst = {RTA_LENGTH(16), RTA_DST};
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        {&a_dst, sizeof(a_dst)},  // attribute
+        {&addr, sizeof(addr)}     // value
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+  } else if (family_address == AF_INET) {
+    struct in_addr addr;
+
+    struct {
+      struct nlmsghdr hdr;
+      struct rtmsg payload;
+    } msg = {
+        .hdr.nlmsg_type = RTM_GETROUTE,
+        .hdr.nlmsg_flags = NLM_F_REQUEST,
+        .hdr.nlmsg_seq = seq++,
+        .payload.rtm_family = AF_INET,
+        .payload.rtm_dst_len = IPV4_ADDR_LEN_BITS,
+        .payload.rtm_src_len = 0,
+        .payload.rtm_tos = 0,
+        .payload.rtm_table = RT_TABLE_UNSPEC,
+        .payload.rtm_protocol = RTPROT_UNSPEC,
+        .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+        .payload.rtm_type = RTN_UNSPEC,
+        .payload.rtm_flags = 0  // RTM_F_NOTIFY in 'ip route get'
+    };
+
+    /* Convert the IP address to binary form */
+    rc = inet_pton(AF_INET, ip_address, &addr);
+    if (rc <= 0) {
+      goto ERR;
+    }
+
+    /* Set attribute = length/type/value */
+    struct rtattr a_dst = {RTA_LENGTH(4), RTA_DST};
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        {&a_dst, sizeof(a_dst)},  // attribute
+        {&addr, sizeof(addr)}     // value
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+  } else {
+    goto ERR;
+  }
+
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR;
+    }
+    return HICN_SOCKET_ERROR_UNEXPECTED; /* Unexpected */
+  }
+
+  for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+    struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(hdr);
+    int attrlen = RTM_PAYLOAD(hdr);
+    struct rtattr *rta;
+    for (rta = RTM_RTA(rtm); RTA_OK(rta, attrlen);
+         rta = RTA_NEXT(rta, attrlen)) {
+      if (rta->rta_type == RTA_OIF) {
+        *interface_id = *(uint32_t *)RTA_DATA(rta);
+        return HICN_SOCKET_ERROR_NONE;
+      }
+    }
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_get_ip_addr(uint32_t interface_id, uint8_t address_family,
+                    ip_address_t *ip_address) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  struct {
+    struct nlmsghdr hdr;
+    struct ifaddrmsg payload;
+  } msg = {.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+           .hdr.nlmsg_type = RTM_GETADDR,
+           .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT,  // | NLM_F_MATCH,
+           .payload.ifa_family = address_family,
+           .payload.ifa_index = 0};
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  n = send(fd, &msg, sizeof(msg), 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return -99; /* Unexpected */
+  }
+
+  for (; NLMSG_OK(hdr, n); hdr = NLMSG_NEXT(hdr, n)) {
+    struct ifaddrmsg *payload = (struct ifaddrmsg *)NLMSG_DATA(hdr);
+
+    if (address_family == AF_INET6) {
+      if ((payload->ifa_index == interface_id) &&
+          (payload->ifa_prefixlen < IPV6_ADDR_LEN * 8)) {
+        printf("got ip address\n");
+        memcpy(ip_address->buffer, RTA_DATA(payload + 1), IPV6_ADDR_LEN);
+        ip_address->family = AF_INET6;
+        ip_address->prefix_len = IPV6_ADDR_LEN_BITS;
+        printf("returning %d\n", HICN_SOCKET_ERROR_NONE);
+        return HICN_SOCKET_ERROR_NONE;
+      }
+    } else if (address_family == AF_INET) {
+      if ((payload->ifa_index == interface_id) &&
+          (payload->ifa_prefixlen < IPV4_ADDR_LEN * 8)) {
+        printf("got ip address\n");
+        memcpy(ip_address->buffer, RTA_DATA(payload + 1), IPV4_ADDR_LEN);
+        ip_address->family = AF_INET;
+        ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
+        printf("returning %d\n", HICN_SOCKET_ERROR_NONE);
+        return HICN_SOCKET_ERROR_NONE;
+      }
+    } else {
+      return -99;
+    }
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  printf("error getting ip address\n");
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_set_ip_addr(uint32_t interface_id, ip_address_t *ip_address) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  struct {
+    struct nlmsghdr hdr;
+    struct ifaddrmsg payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_NEWADDR,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC,
+      .hdr.nlmsg_seq = seq++,
+      .payload.ifa_family = ip_address->family,
+      .payload.ifa_prefixlen = ip_address->prefix_len,
+      .payload.ifa_flags = 0,
+      .payload.ifa_scope = RT_SCOPE_UNIVERSE,
+      .payload.ifa_index = interface_id};
+
+  /* Set attributes = length/type/value */
+  struct rtattr ifa_address = {RTA_LENGTH(ip_address_len(ip_address)),
+                               IFA_ADDRESS};
+  // XXX maybe the reason why we have a local route ?
+  // struct rtattr ifa_local   = { RTA_LENGTH(ip_address_len(ip_address)),
+  // IFA_LOCAL };
+  struct iovec iov[] = {
+      {&msg, sizeof(msg)},
+      {&ifa_address, sizeof(ifa_address)},
+      {(void *)&ip_address->buffer, sizeof(ip_address->buffer)},
+      //        { &ifa_local, sizeof(ifa_local) },
+      //        { (void*)&ip_address->buffer, sizeof(ip_address->buffer) },
+  };
+  msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  // hicn_packet_dump_iov(iov, ARRAY_SIZE(iov));
+
+  n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+  }
+
+  return 0;
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+int _nl_up_if(uint32_t interface_id) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  struct {
+    struct nlmsghdr hdr;
+    struct ifinfomsg payload;
+  } msg = {
+      .hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+      .hdr.nlmsg_type = RTM_NEWLINK,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+      .payload.ifi_family = AF_UNSPEC,
+      .payload.ifi_index = interface_id,
+      .payload.ifi_flags = IFF_UP,
+      .payload.ifi_change = IFF_UP  // 0xffffffff
+  };
+
+  n = send(fd, &msg, sizeof(msg), 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0;
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+struct route_info {
+  char *dst_addr;
+  char *src_addr;
+  char *gateway;
+  char ifName[IF_NAMESIZE];
+};
+
+/*
+ * ip -6 route add PREFIX dev INTERFACE_NAME
+ */
+#if 0
+int _nl_add_in_route(const char * prefix, const uint32_t interface_id)
+{
+    char buffer[BUFSIZE];
+    struct nlmsghdr * hdr = (struct nlmsghdr *)buffer;
+    size_t n;
+    int fd;
+
+    int pton_fd;
+    unsigned char dst[sizeof(struct in6_addr)];
+    char * p;
+    char * eptr;
+    char addr[strlen(prefix)];
+    uint32_t dst_len;
+
+    strncpy(addr, prefix, strlen(prefix));
+
+    p = strchr(addr, '/');
+    if (!p) {
+        dst_len = IPV6_ADDR_LEN;
+    } else {
+        dst_len = strtoul(p + 1, &eptr, 10);
+        if (dst_len > IPV6_ADDR_LEN * 8) {
+            printf("E: Netmask > IPV6_ADDR_LEN");
+            return -1;
+        }
+        *p = 0;
+    }
+
+    pton_fd = inet_pton(AF_INET6, addr, dst);
+    if (pton_fd <= 0) {
+        if (pton_fd == 0)
+            ;//ERROR("Not in presentation format");
+        else
+            perror("inet_pton");
+        return -2;
+    }
+
+    _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE_MATCH);
+    _nl_payload_route(RT_TABLE_MAIN, dst_len, (uint8_t *)buffer, BUFSIZE);
+
+    addAttr(hdr, BUFSIZE, RTA_DST, dst, IPV6_ADDR_LEN);
+    addAttr(hdr, BUFSIZE, RTA_OIF, (void*)&interface_id, sizeof(uint32_t));
+
+    fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+    if (fd < 0) {
+        goto ERR_SOCKET;
+    }
+
+    n = send(fd, buffer, hdr->nlmsg_len, 0);
+    if (n == -1) {
+        goto ERR_SEND;
+    }
+    n = recv(fd, buffer, BUFSIZE, 0);
+    if (n == -1) {
+        goto ERR_RECV;
+    }
+
+    if (hdr->nlmsg_type == NLMSG_ERROR) {
+        struct nlmsgerr * err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+        if (err->error < 0) {
+            errno = -err->error;
+            goto ERR_NL;
+        }
+        return 0;
+    }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+    return -1;
+
+}
+#endif
+
+/*
+ * ip -6 route add local default via GATEWAY_IP table TABLE_ID
+ */
+int _nl_add_out_route(const char *gateway, uint8_t address_family,
+                      const uint8_t table_id, int default_route) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  int pton_fd;
+
+  if (address_family == AF_INET) {
+    struct in_addr gw;
+
+    pton_fd = inet_pton(AF_INET, gateway, (struct in_addr *)&gw);
+    if (pton_fd < 0) {
+      return -1;
+    }
+
+    _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE,
+               NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+    _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+    /* gw */
+    addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+  } else if (address_family == AF_INET6) {
+    struct in6_addr gw;
+
+    pton_fd = inet_pton(AF_INET6, gateway, (struct in6_addr *)&gw);
+    if (pton_fd < 0) {
+      return -1;
+    }
+
+    _nl_header(RTM_NEWROUTE, (uint8_t *)buffer, BUFSIZE,
+               NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+    _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+    /* gw */
+    addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+    if (default_route != -1) {
+      addAttr(hdr, BUFSIZE, RTA_OIF, &default_route, sizeof(default_route));
+    }
+
+  } else {
+    return -1;
+  }
+
+  // For more than 255 tables
+  // addAttr(msg, BUFSIZE, RTA_TABLE, &table_id, sizeof(uint32_t));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  n = send(fd, buffer, hdr->nlmsg_len, 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0;
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+/*
+ * ip -6 route del local default via GATEWAY_IP table TABLE_ID
+ */
+int _nl_del_out_route(const char *gateway, const uint8_t address_family,
+                      const uint8_t table_id) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  int pton_fd;
+
+  if (address_family == AF_INET) {
+    struct in_addr gw;
+
+    pton_fd = inet_pton(AF_INET, gateway, (struct in_addr *)&gw);
+    if (pton_fd < 0) {
+      return -1;
+    }
+
+    _nl_header(RTM_DELROUTE, (uint8_t *)buffer, BUFSIZE,
+               NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+    _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+    /* gw */
+    addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+  } else if (address_family == AF_INET6) {
+    struct in6_addr gw;
+
+    pton_fd = inet_pton(AF_INET6, gateway, (struct in6_addr *)&gw);
+    if (pton_fd < 0) {
+      return -1;
+    }
+
+    _nl_header(RTM_DELROUTE, (uint8_t *)buffer, BUFSIZE,
+               NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC);
+    _nl_payload_route(table_id, address_family, 0, (uint8_t *)buffer, BUFSIZE);
+
+    /* gw */
+    addAttr(hdr, BUFSIZE, RTA_GATEWAY, &gw, sizeof(gw));
+
+  } else {
+    return -1;
+  }
+
+  // For more than 255 tables
+  // addAttr(msg, BUFSIZE, RTA_TABLE, &table_id, sizeof(uint32_t));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  n = send(fd, buffer, hdr->nlmsg_len, 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0;
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+/*
+ * ip route del 1:2::2 dev lo table local
+ *
+ */
+int _nl_del_lo_route(const ip_address_t *ip_address) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  struct {
+    struct nlmsghdr hdr;
+    struct rtmsg payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_DELROUTE,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+      .hdr.nlmsg_seq = seq++,
+      .payload.rtm_family = ip_address->family,
+      .payload.rtm_dst_len = ip_address->prefix_len,
+      .payload.rtm_src_len = 0,
+      .payload.rtm_tos = 0,
+      .payload.rtm_table = RT_TABLE_LOCAL,
+      .payload.rtm_protocol = RTPROT_UNSPEC,
+      .payload.rtm_scope = RT_SCOPE_UNIVERSE,
+      .payload.rtm_type = RTN_UNSPEC,
+      .payload.rtm_flags = 0  // RTM_F_NOTIFY in 'ip route get'
+  };
+
+  /* Set attribute = length/type/value */
+  uint32_t one = 1;
+  struct rtattr a_dst = {RTA_LENGTH(ip_address_len(ip_address)), RTA_DST};
+  struct rtattr a_ifid_lo = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF};
+  struct iovec iov[] = {
+      {&msg, sizeof(msg)},
+      /* Ip address */
+      {&a_dst, sizeof(a_dst)},
+      {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+      /* Interface id */
+      {&a_ifid_lo, sizeof(a_ifid_lo)},
+      {&one, sizeof(one)}};
+  msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+  if (n == -1) {
+    goto ERR;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR;
+    }
+    return 0;
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/*
+ * ip -6 rule add iif INTERFACE_NAME lookup TABLE_ID
+ */
+int _nl_add_rule(const char *interface_name, uint8_t address_family,
+                 const uint8_t table_id) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  _nl_header(RTM_NEWRULE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE);
+  _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE);
+
+  /* XXX iif */
+  addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name,
+          strlen(interface_name));
+  // attr1 = addNestedAttr(hdr, IFLA_LINKINFO);
+  // endNestedAttr(hdr, attr1);
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  n = send(fd, buffer, hdr->nlmsg_len, 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0;
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+/*
+ * ip -6 rule del iif INTERFACE_NAME //lookup TABLE_ID
+ */
+int _nl_del_rule(const char *interface_name, uint8_t address_family,
+                 const uint8_t table_id) {
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+  size_t n;
+  int fd;
+
+  _nl_header(RTM_DELRULE, (uint8_t *)buffer, BUFSIZE, FLAGS_CREATE);
+  _nl_payload_rule(table_id, address_family, (uint8_t *)buffer, BUFSIZE);
+
+  /* XXX iif */
+  addAttr(hdr, BUFSIZE, FRA_IIFNAME, (void *)interface_name,
+          strlen(interface_name));
+
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR_SOCKET;
+  }
+
+  n = send(fd, buffer, hdr->nlmsg_len, 0);
+  if (n == -1) {
+    goto ERR_SEND;
+  }
+
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR_RECV;
+  }
+
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR_NL;
+    }
+    return 0;
+  }
+
+ERR_NL:
+ERR_RECV:
+ERR_SEND:
+ERR_SOCKET:
+  return -1;
+}
+
+/*
+ * ip -6 neigh add proxy 1:2::2 dev hicnc-cons-eth0 2>&1 | grep nei
+ *
+ */
+int _nl_add_neigh_proxy(const ip_address_t *ip_address,
+                        const uint32_t interface_id) {
+  /* Buffer for holding the response, with appropriate casting on the header */
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+  /* Used for send and receive operations on netlink socket */
+  int fd;
+  size_t n;
+
+  /* Packet header */
+  struct {
+    struct nlmsghdr hdr;
+    struct ndmsg payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_NEWNEIGH,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+      .hdr.nlmsg_seq = seq++,
+      .payload.ndm_family = ip_address->family,
+      .payload.ndm_ifindex = interface_id,
+      .payload.ndm_state = NUD_PERMANENT,
+      .payload.ndm_flags = NTF_PROXY,
+  };
+
+  /* Message attributes = length/type/value */
+  struct rtattr a_dst = {RTA_LENGTH(ip_address_len(ip_address)), NDA_DST};
+
+  /* Iovec describing the packets */
+  struct iovec iov[] = {
+      {&msg, sizeof(msg)},
+      /* Ip address */
+      {&a_dst, sizeof(a_dst)},
+      {(void *)&ip_address->buffer, sizeof(ip_address->buffer)},
+  };
+  msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+  /* Open netlink socket */
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  /* Send packet */
+  n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Receive answer */
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Parse answer */
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR;
+    }
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/* ip -6 route add 0:1::/64 dev hicn-if0 table 100 */
+/* ip -6 route add 0:2::/64 dev hicn-if1 table 100 */
+int _nl_add_in_route_table(const ip_address_t *prefix,
+                           const uint32_t interface_id,
+                           const uint8_t table_id) {
+  /* Buffer for holding the response, with appropriate casting on the header */
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+  /* Used for send and receive operations on netlink socket */
+  int fd;
+  size_t n;
+
+  /* Packet header */
+  struct {
+    struct nlmsghdr hdr;
+    struct rtmsg payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_NEWROUTE,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+      .hdr.nlmsg_seq = seq++,
+      .payload.rtm_family = prefix->family,
+      .payload.rtm_dst_len = prefix->prefix_len,  // XXX ? XXX dst_len,
+      .payload.rtm_src_len = 0,
+      .payload.rtm_tos = 0,
+      .payload.rtm_table = table_id, /* RT_TABLE_MAIN, etc. */
+      .payload.rtm_protocol = RTPROT_BOOT,
+      .payload.rtm_scope =
+          prefix->family == AF_INET6 ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+      .payload.rtm_type = RTN_UNICAST,
+      .payload.rtm_flags = 0,
+  };
+
+  /* Message attributes = length/type/value */
+  // XXX This could be put directly inside the iovec maybe ? XXX
+  struct rtattr a_dst = {RTA_LENGTH(ip_address_len(prefix)), RTA_DST};
+  struct rtattr a_oif = {RTA_LENGTH(sizeof(uint32_t)), RTA_OIF};
+
+  /* Iovec describing the packets */
+  struct iovec iov[] = {
+      {&msg, sizeof(msg)},
+      /* Destination prefix / ip address */
+      {&a_dst, sizeof(a_dst)},
+      {(void *)&prefix->buffer, ip_address_len(prefix)},
+      /* Output interface */
+      {&a_oif, sizeof(a_oif)},
+      {(void *)&interface_id, sizeof(uint32_t)},
+  };
+  msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+  /* Open netlink socket */
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  /* Send packet */
+  n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Receive answer */
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Parse answer */
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR;
+    }
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+/* Additional helper functions */
+
+int _nl_add_in_route_table_s(const char *prefix, const uint32_t interface_id,
+                             const uint8_t table_id) {
+  int rc;
+  ip_address_t ip_address;
+
+  rc = hicn_ip_pton(prefix, &ip_address);
+  if (rc < 0) {
+    return rc;
+  }
+
+  return _nl_add_in_route_table(&ip_address, interface_id, table_id);
+}
+
+int _nl_add_in_route_s(const char *prefix, const uint32_t interface_id) {
+  return _nl_add_in_route_table_s(prefix, interface_id, RT_TABLE_MAIN);
+}
+
+////////* ip -6 rule add from all prio 10 table local */
+/* ip -6 rule add from b001::/16 prio 0 table 100 */
+int _nl_add_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+                      const uint32_t priority, const uint8_t table_id) {
+  /* Buffer for holding the response, with appropriate casting on the header */
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+  /* Used for send and receive operations on netlink socket */
+  int fd;
+  size_t n;
+
+  /* Packet header */
+  struct {
+    struct nlmsghdr hdr;
+    struct fib_rule_hdr payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_NEWRULE,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+      .hdr.nlmsg_seq = seq++,
+      .payload.family = address_family,
+      //.payload.dst_len = ,
+      .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+      .payload.tos = 0,
+      .payload.table = table_id,
+      .payload.action = FR_ACT_TO_TBL,
+      .payload.flags = NLM_F_REPLACE,  // 0
+  };
+
+  /* Open netlink socket */
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  if (ip_address) {
+    /* Message attributes = length/type/value */
+    struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), FRA_SRC};
+    struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+    /* Iovec describing the packets */
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        /* Source prefix / ip_address */
+        {&a_src, sizeof(a_src)},
+        {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+        /* Priority */
+        {&a_prio, sizeof(a_prio)},
+        {(void *)&priority, sizeof(uint32_t)},
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    /* Send packet */
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+  } else {
+    struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+    /* Iovec describing the packets */
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        /* Priority */
+        {&a_prio, sizeof(a_prio)},
+        {(void *)&priority, sizeof(uint32_t)},
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    /* Send packet */
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+  }
+
+  /* Receive answer */
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Parse answer */
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0) {
+      errno = -err->error;
+      goto ERR;
+    }
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_add_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+                         const uint32_t priority) {
+  return _nl_add_prio_rule(ip_address, address_family, priority,
+                           RT_TABLE_LOCAL);
+}
+
+/* ip -6 rule del from all prio 0 table local */
+int _nl_del_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+                      const uint32_t priority, const uint8_t table_id) {
+  /* Buffer for holding the response, with appropriate casting on the header */
+  char buffer[BUFSIZE];
+  struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+
+  /* Used for send and receive operations on netlink socket */
+  int fd;
+  size_t n;
+
+  /* Packet header */
+  struct {
+    struct nlmsghdr hdr;
+    struct fib_rule_hdr payload;
+  } msg = {
+      .hdr.nlmsg_type = RTM_DELRULE,
+      .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL,
+      .hdr.nlmsg_seq = seq++,
+      .payload.family = address_family,
+      //.payload.dst_len = ,
+      .payload.src_len = ip_address ? ip_address->prefix_len : 0,
+      .payload.tos = 0,
+      .payload.table = table_id,
+      .payload.action = FR_ACT_TO_TBL,
+      .payload.flags = NLM_F_REPLACE,  // 0
+  };
+
+  /* Open netlink socket */
+  fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+  if (fd < 0) {
+    goto ERR;
+  }
+
+  /* Message attributes = length/type/value */
+  if (ip_address) {
+    struct rtattr a_src = {RTA_LENGTH(ip_address_len(ip_address)), FRA_SRC};
+    struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+    /* Iovec describing the packets */
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        /* Source prefix / ip_address */
+        {&a_src, sizeof(a_src)},
+        {(void *)&ip_address->buffer, ip_address_len(ip_address)},
+        /* Priority */
+        {&a_prio, sizeof(a_prio)},
+        {(void *)&priority, sizeof(uint32_t)},
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    /* Send packet */
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+
+  } else {
+    struct rtattr a_prio = {RTA_LENGTH(sizeof(uint32_t)), FRA_PRIORITY};
+
+    /* Iovec describing the packets */
+    struct iovec iov[] = {
+        {&msg, sizeof(msg)},
+        /* Priority */
+        {&a_prio, sizeof(a_prio)},
+        {(void *)&priority, sizeof(uint32_t)},
+    };
+    msg.hdr.nlmsg_len = iov_length(iov, ARRAY_SIZE(iov));
+
+    /* Send packet */
+    n = writev(fd, (struct iovec *)&iov, ARRAY_SIZE(iov));
+    if (n == -1) {
+      goto ERR;
+    }
+  }
+
+  /* Receive answer */
+  n = recv(fd, buffer, BUFSIZE, 0);
+  if (n == -1) {
+    goto ERR;
+  }
+
+  /* Parse answer */
+  if (hdr->nlmsg_type == NLMSG_ERROR) {
+    struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(hdr);
+    if (err->error < 0 &&
+        err->error != -2) {  //-2 is not such file or directory
+      errno = -err->error;
+      goto ERR;
+    }
+  }
+
+  return HICN_SOCKET_ERROR_NONE;
+ERR:
+  return HICN_SOCKET_ERROR_UNSPEC;
+}
+
+int _nl_del_lo_prio_rule(const ip_address_t *ip_address, uint8_t address_family,
+                         const uint32_t priority) {
+  return _nl_del_prio_rule(ip_address, address_family, priority,
+                           RT_TABLE_LOCAL);
+}
+
+/******************************************************************************/
+
+// #include <net/if.h>
+// duplicate declarations, in the meantime
+#define IF_NAMESIZE 16
+
+//#define WITH_TUN_PI 1
+
+#ifdef WITH_TUN_PI
+#define TUN_FLAGS IFF_TUN
+#else
+#define TUN_FLAGS IFF_TUN | IFF_NO_PI
+#endif
+
+/*
+ * Taken from Kernel Documentation/networking/tuntap.txt
+ */
+
+int tun_alloc(char *dev, int flags) {
+  struct ifreq ifr;
+  int fd, err;
+  char *clonedev = "/dev/net/tun";
+
+  /* Arguments taken by the function:
+   *
+   * char *dev: the name of an interface (or '\0'). MUST have enough
+   *   space to hold the interface name if '\0' is passed
+   * int flags: interface flags (eg, IFF_TUN etc.)
+   */
+
+  /* open the clone device */
+  if ((fd = open(clonedev, O_RDWR)) < 0) {
+    return fd;
+  }
+
+  /* preparation of the struct ifr, of type "struct ifreq" */
+  memset(&ifr, 0, sizeof(ifr));
+
+  ifr.ifr_flags = flags;
+
+  if (*dev) {
+    /* if a device name was specified, put it in the structure; otherwise,
+     * the kernel will try to allocate the "next" device of the
+     * specified type */
+    strncpy(ifr.ifr_name, dev, IF_NAMESIZE - 1);
+  }
+
+  /* try to create the device */
+  if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
+    close(fd);
+    return err;
+  }
+
+  /* if the operation was successful, write back the name of the
+   * interface to the variable "dev", so the caller can know
+   * it. Note that the caller MUST reserve space in *dev (see calling
+   * code below) */
+  strcpy(dev, ifr.ifr_name);
+
+  /* this is the special file descriptor that the caller will use to talk
+   * with the virtual interface */
+  return fd;
+}
+
+int linux_get_tun_name(const char *prefix, const char *identifier,
+                       char *tun_name) {
+  snprintf(tun_name, IF_NAMESIZE, "%s-%s", prefix,
+           identifier ? identifier : "main");
+  return 0;
+}
+
+int linux_tun_enable_offload(int fd) {
+  unsigned int offload = 0, tso4 = 1, tso6 = 1, ecn = 1, ufo = 1, csum = 1;
+
+  /* Check if our kernel supports TUNSETOFFLOAD */
+  if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) {
+    goto ERR_TUN;
+  }
+
+  if (csum) {
+    offload |= TUN_F_CSUM;
+    if (tso4) offload |= TUN_F_TSO4;
+    if (tso6) offload |= TUN_F_TSO6;
+    if ((tso4 || tso6) && ecn) offload |= TUN_F_TSO_ECN;
+    if (ufo) offload |= TUN_F_UFO;
+  }
+
+  if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+    offload &= ~TUN_F_UFO;
+    if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
+      fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n", strerror(errno));
+    }
+  }
+
+  return 0;
+
+ERR_TUN:
+  return -1;
+}
+
+int linux_tun_create(char *name) {
+  int fd, rc;
+
+  fd = tun_alloc(name, TUN_FLAGS);
+  if (fd < 0) {
+    // ERROR("Error connecting to tun/tap interface %s!", name);
+    errno = -2;
+    goto ERR_TUN;
+  }
+
+  rc = linux_tun_enable_offload(fd);
+  if (rc < 0) {
+    // WARN("Could not enable hardware offload on TUN device");
+  } else {
+    // INFO("Enabled hardware offload on TUN device");
+  }
+
+  return fd;
+
+ERR_TUN:
+  return -1;
+}
+
+/*
+ *
+ * interface name can be NULL for all interfaces
+ */
+int linux_enable_proc(char *path) {
+  int ret = 0;
+  int fd;
+
+  fd = open(path, O_WRONLY);
+  if (fd < 0) {
+    return -1;
+  }
+
+  if (write(fd, "1", 1) != 1) {
+    ret = -2;
+  }
+
+  close(fd);
+  return ret;
+}
+
+int linux_enable_v4_forwarding() {
+  return linux_enable_proc("/proc/sys/net/ipv4/ip_forward");
+}
+
+int linux_enable_v6_forwarding(char *interface_name) {
+  char path[PATH_MAX];
+  snprintf(path, PATH_MAX, "/proc/sys/net/ipv6/conf/%s/forwarding",
+           (interface_name) ? interface_name : "all");
+
+  return linux_enable_proc(path);
+}
+
+int linux_enable_ndp_proxy() {
+  return linux_enable_proc("/proc/sys/net/ipv6/conf/all/proxy_ndp");
+}
+
+const hicn_socket_ops_t ops = {
+    .arch = "linux",
+    .get_tun_name = linux_get_tun_name,
+    .tun_create = linux_tun_create,
+    .enable_v4_forwarding = linux_enable_v4_forwarding,
+    .enable_v6_forwarding = linux_enable_v6_forwarding,
+    .enable_ndp_proxy = linux_enable_ndp_proxy,
+    .get_ifid = _nl_get_ifid,
+    .get_output_ifid = _nl_get_output_ifid,
+    .get_ip_addr = _nl_get_ip_addr,
+    .set_ip_addr = _nl_set_ip_addr,
+    .up_if = _nl_up_if,
+    .add_in_route_table = _nl_add_in_route_table,
+    .add_in_route_table_s = _nl_add_in_route_table_s,
+    .add_in_route_s = _nl_add_in_route_s,
+    .add_out_route = _nl_add_out_route,
+    .del_out_route = _nl_del_out_route,
+    .del_lo_route = _nl_del_lo_route,
+    .add_rule = _nl_add_rule,
+    .del_rule = _nl_del_rule,
+    .add_neigh_proxy = _nl_add_neigh_proxy,
+    .add_prio_rule = _nl_add_prio_rule,
+    .add_lo_prio_rule = _nl_add_lo_prio_rule,
+    .del_prio_rule = _nl_del_prio_rule,
+    .del_lo_prio_rule = _nl_del_lo_prio_rule,
+};
diff --git a/hicn-light/src/strategies/CMakeLists.txt b/hicn-light/src/strategies/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..7f0730b
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/strategyImpl.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancerWithPD.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateWithPD.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rnd.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rndSegment.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancer.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/loadBalancerWithPD.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/nexthopState.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/nexthopStateWithPD.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/rnd.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/rndSegment.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/hicn-light/src/strategies/loadBalancer.c b/hicn-light/src/strategies/loadBalancer.c
new file mode 100755 (executable)
index 0000000..14e9077
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Unsigned.h>
+
+#include <src/strategies/loadBalancer.h>
+#include <src/strategies/nexthopState.h>
+
+static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy,
+                                                const NumberSet *egressId,
+                                                const Message *objectMessage,
+                                                Ticks rtt);
+static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy,
+                                            const NumberSet *egressId);
+static NumberSet *_strategyLoadBalancer_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy);
+static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy,
+                                             unsigned connectionId);
+static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy,
+                                                unsigned connectionId);
+static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+    .context = NULL,
+    .receiveObject = &_strategyLoadBalancer_ReceiveObject,
+    .onTimeout = &_strategyLoadBalancer_OnTimeout,
+    .lookupNexthop = &_strategyLoadBalancer_LookupNexthop,
+    .returnNexthops = &_strategyLoadBalancer_ReturnNexthops,
+    .countNexthops = &_strategyLoadBalancer_CountNexthops,
+    .addNexthop = &_strategyLoadBalancer_AddNexthop,
+    .removeNexthop = &_strategyLoadBalancer_RemoveNexthop,
+    .destroy = &_strategyLoadBalancer_ImplDestroy,
+    .getStrategy = &_strategyLoadBalancer_GetStrategy,
+};
+
+struct strategy_load_balancer;
+typedef struct strategy_load_balancer StrategyLoadBalancer;
+
+struct strategy_load_balancer {
+  double weights_sum;
+  // hash map from connectionId to StrategyNexthopState
+  PARCHashMap *strategy_state;
+  NumberSet *nexthops;
+};
+
+StrategyImpl *strategyLoadBalancer_Create() {
+  StrategyLoadBalancer *strategy =
+      parcMemory_AllocateAndClear(sizeof(StrategyLoadBalancer));
+  parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyLoadBalancer));
+
+  strategy->weights_sum = 0.0;
+  strategy->strategy_state = parcHashMap_Create();
+  strategy->nexthops = numberSet_Create();
+  srand(time(NULL));
+
+  StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+  parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyImpl));
+  memcpy(impl, &_template, sizeof(StrategyImpl));
+  impl->context = strategy;
+
+  return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyLoadBalancer_GetStrategy(StrategyImpl *strategy) {
+  return SET_STRATEGY_LOADBALANCER;
+}
+
+static void _update_Stats(StrategyLoadBalancer *strategy,
+                          StrategyNexthopState *state, bool inc) {
+  const double ALPHA = 0.9;
+  double w = strategyNexthopState_GetWeight(state);
+  strategy->weights_sum -= w;
+  w = strategyNexthopState_UpdateState(state, inc, ALPHA);
+  strategy->weights_sum += w;
+}
+
+static unsigned _select_Nexthop(StrategyLoadBalancer *strategy) {
+  double rnd = (double)rand() / (double)RAND_MAX;
+  double start_range = 0.0;
+
+  PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state);
+
+  unsigned nexthop = 100000;
+  while (parcIterator_HasNext(it)) {
+    PARCUnsigned *cid = parcIterator_Next(it);
+    const StrategyNexthopState *elem =
+        parcHashMap_Get(strategy->strategy_state, cid);
+
+    double w = strategyNexthopState_GetWeight(elem);
+
+    double prob = w / strategy->weights_sum;
+    if ((rnd >= start_range) && (rnd < (start_range + prob))) {
+      nexthop = parcUnsigned_GetUnsigned(cid);
+      break;
+    } else {
+      start_range += prob;
+    }
+  }
+
+  parcIterator_Release(&it);
+
+  // if no face is selected by the algorithm (for example because of a wrong
+  // round in the weights) we may always select the last face here. Double check
+  // this!
+  return nexthop;
+}
+
+static void _strategyLoadBalancer_ReceiveObject(StrategyImpl *strategy,
+                                                const NumberSet *egressId,
+                                                const Message *objectMessage,
+                                                Ticks rtt) {
+  _strategyLoadBalancer_OnTimeout(strategy, egressId);
+}
+
+static void _strategyLoadBalancer_OnTimeout(StrategyImpl *strategy,
+                                            const NumberSet *egressId) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+  for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+    unsigned outId = numberSet_GetItem(egressId, i);
+    PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+    const StrategyNexthopState *state =
+        parcHashMap_Get(lb->strategy_state, cid);
+    if (state != NULL) {
+      _update_Stats(lb, (StrategyNexthopState *)state, false);
+    } else {
+      // this may happen if we remove a face/route while downloading a file
+      // we should ignore this timeout
+    }
+    parcUnsigned_Release(&cid);
+  }
+}
+
+static NumberSet *_strategyLoadBalancer_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+  unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+  PARCUnsigned *in = parcUnsigned_Create(in_connection);
+
+  unsigned mapSize = parcHashMap_Size(lb->strategy_state);
+  NumberSet *outList = numberSet_Create();
+
+  if ((mapSize == 0) ||
+      ((mapSize == 1) && parcHashMap_Contains(lb->strategy_state, in))) {
+    // there are no output faces or the input face is also the only output face.
+    // return null to avoid loops
+    parcUnsigned_Release(&in);
+    return outList;
+  }
+
+  unsigned out_connection;
+  do {
+    out_connection = _select_Nexthop(lb);
+  } while (out_connection == in_connection);
+
+  PARCUnsigned *out = parcUnsigned_Create(out_connection);
+
+  const StrategyNexthopState *state = parcHashMap_Get(lb->strategy_state, out);
+  if (state == NULL) {
+    // this is an error and should not happen!
+    parcTrapNotImplemented(
+        "Try to send an interest on a face that does not exists");
+  }
+
+  _update_Stats(lb, (StrategyNexthopState *)state, true);
+
+  parcUnsigned_Release(&in);
+  parcUnsigned_Release(&out);
+
+  numberSet_Add(outList, out_connection);
+  return outList;
+}
+
+static NumberSet *_strategyLoadBalancer_ReturnNexthops(StrategyImpl *strategy) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+  return lb->nexthops;
+}
+
+unsigned _strategyLoadBalancer_CountNexthops(StrategyImpl *strategy) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+  return numberSet_Length(lb->nexthops);
+}
+
+static void _strategyLoadBalancer_resetState(StrategyImpl *strategy) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+  lb->weights_sum = 0.0;
+  PARCIterator *it = parcHashMap_CreateKeyIterator(lb->strategy_state);
+
+  while (parcIterator_HasNext(it)) {
+    PARCUnsigned *cid = parcIterator_Next(it);
+    StrategyNexthopState *elem =
+        (StrategyNexthopState *)parcHashMap_Get(lb->strategy_state, cid);
+
+    strategyNexthopState_Reset(elem);
+    lb->weights_sum += strategyNexthopState_GetWeight(elem);
+  }
+
+  parcIterator_Release(&it);
+}
+
+static void _strategyLoadBalancer_AddNexthop(StrategyImpl *strategy,
+                                             unsigned connectionId) {
+  StrategyNexthopState *state = strategyNexthopState_Create();
+
+  PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+  if (!parcHashMap_Contains(lb->strategy_state, cid)) {
+    parcHashMap_Put(lb->strategy_state, cid, state);
+    numberSet_Add(lb->nexthops, connectionId);
+    _strategyLoadBalancer_resetState(strategy);
+  }
+}
+
+static void _strategyLoadBalancer_RemoveNexthop(StrategyImpl *strategy,
+                                                unsigned connectionId) {
+  StrategyLoadBalancer *lb = (StrategyLoadBalancer *)strategy->context;
+
+  PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+  if (parcHashMap_Contains(lb->strategy_state, cid)) {
+    parcHashMap_Remove(lb->strategy_state, cid);
+    numberSet_Remove(lb->nexthops, connectionId);
+    _strategyLoadBalancer_resetState(strategy);
+  }
+
+  parcUnsigned_Release(&cid);
+}
+
+static void _strategyLoadBalancer_ImplDestroy(StrategyImpl **strategyPtr) {
+  parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*strategyPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  StrategyImpl *impl = *strategyPtr;
+  StrategyLoadBalancer *strategy = (StrategyLoadBalancer *)impl->context;
+
+  parcHashMap_Release(&(strategy->strategy_state));
+  numberSet_Release(&(strategy->nexthops));
+
+  parcMemory_Deallocate((void **)&strategy);
+  parcMemory_Deallocate((void **)&impl);
+  *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/loadBalancer.h b/hicn-light/src/strategies/loadBalancer.h
new file mode 100755 (executable)
index 0000000..1178c30
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Forward on the less loaded path
+ */
+
+#ifndef loadBalancer_h
+#define loadBalancer_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl *strategyLoadBalancer_Create();
+#endif  // loadBalancer_h
diff --git a/hicn-light/src/strategies/loadBalancerWithPD.c b/hicn-light/src/strategies/loadBalancerWithPD.c
new file mode 100755 (executable)
index 0000000..1aad8fd
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2017-2019 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 <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Unsigned.h>
+
+#include <src/strategies/loadBalancerWithPD.h>
+#include <src/strategies/nexthopStateWithPD.h>
+
+const unsigned PROBE_FREQUENCY = 1024;
+
+static void _strategyLoadBalancerWithPD_ReceiveObject(
+    StrategyImpl *strategy, const NumberSet *egressId,
+    const Message *objectMessage, Ticks rtt);
+static void _strategyLoadBalancerWithPD_OnTimeout(StrategyImpl *strategy,
+                                                  const NumberSet *egressId);
+static NumberSet *_strategyLoadBalancerWithPD_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyLoadBalancerWithPD_ReturnNexthops(
+    StrategyImpl *strategy);
+static unsigned _strategyLoadBalancerWithPD_CountNexthops(
+    StrategyImpl *strategy);
+static void _strategyLoadBalancerWithPD_AddNexthop(StrategyImpl *strategy,
+                                                   unsigned connectionId);
+static void _strategyLoadBalancerWithPD_RemoveNexthop(StrategyImpl *strategy,
+                                                      unsigned connectionId);
+static void _strategyLoadBalancerWithPD_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyLoadBalancerWithPD_GetStrategy(
+    StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+    .context = NULL,
+    .receiveObject = &_strategyLoadBalancerWithPD_ReceiveObject,
+    .onTimeout = &_strategyLoadBalancerWithPD_OnTimeout,
+    .lookupNexthop = &_strategyLoadBalancerWithPD_LookupNexthop,
+    .returnNexthops = &_strategyLoadBalancerWithPD_ReturnNexthops,
+    .countNexthops = &_strategyLoadBalancerWithPD_CountNexthops,
+    .addNexthop = &_strategyLoadBalancerWithPD_AddNexthop,
+    .removeNexthop = &_strategyLoadBalancerWithPD_RemoveNexthop,
+    .destroy = &_strategyLoadBalancerWithPD_ImplDestroy,
+    .getStrategy = &_strategyLoadBalancerWithPD_GetStrategy,
+};
+
+struct strategy_load_balancer_with_pd;
+typedef struct strategy_load_balancer_with_pd StrategyLoadBalancerWithPD;
+
+struct strategy_load_balancer_with_pd {
+  double weights_sum;
+  unsigned min_delay;
+  // hash map from connectionId to StrategyNexthopState
+  PARCHashMap *strategy_state;
+  NumberSet *nexthops;
+  ConnectionTable *connTable;
+  bool toInit;
+  unsigned int fwdPackets;
+};
+
+StrategyImpl *strategyLoadBalancerWithPD_Create() {
+  StrategyLoadBalancerWithPD *strategy =
+      parcMemory_AllocateAndClear(sizeof(StrategyLoadBalancerWithPD));
+  parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyLoadBalancerWithPD));
+
+  strategy->weights_sum = 0.0;
+  strategy->min_delay = INT_MAX;
+  strategy->strategy_state = parcHashMap_Create();
+  strategy->nexthops = numberSet_Create();
+  srand(time(NULL));
+
+  StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+  parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyImpl));
+  memcpy(impl, &_template, sizeof(StrategyImpl));
+  impl->context = strategy;
+  strategy->connTable = NULL;
+  strategy->fwdPackets = 0;
+  strategy->toInit = true;
+
+  return impl;
+}
+
+void strategyLoadBalancerWithPD_SetConnectionTable(StrategyImpl *strategy,
+                                                   ConnectionTable *connTable) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+  lb->connTable = connTable;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyLoadBalancerWithPD_GetStrategy(StrategyImpl *strategy) {
+  return SET_STRATEGY_LOADBALANCER_WITH_DELAY;
+}
+
+static void _update_Stats(StrategyLoadBalancerWithPD *strategy,
+                          StrategyNexthopStateWithPD *state, bool inc,
+                          Ticks rtt) {
+  const double ALPHA = 0.9;
+  double w = strategyNexthopStateWithPD_GetWeight(state);
+  strategy->weights_sum -= w;
+  w = strategyNexthopStateWithPD_UpdateState(state, inc, strategy->min_delay,
+                                             ALPHA);
+  strategy->weights_sum += w;
+}
+
+static void _sendProbes(StrategyLoadBalancerWithPD *strategy) {
+  unsigned size = numberSet_Length(strategy->nexthops);
+  for (unsigned i = 0; i < size; i++) {
+    unsigned nhop = numberSet_GetItem(strategy->nexthops, i);
+    Connection *conn =
+        (Connection *)connectionTable_FindById(strategy->connTable, nhop);
+    if (conn != NULL) {
+      connection_Probe(conn);
+      unsigned delay = connection_GetDelay(conn);
+      PARCUnsigned *cid = parcUnsigned_Create(nhop);
+      StrategyNexthopStateWithPD *elem =
+          (StrategyNexthopStateWithPD *)parcHashMap_Get(
+              strategy->strategy_state, cid);
+      strategyNexthopStateWithPD_SetDelay(elem, delay);
+      if (delay < strategy->min_delay && delay != 0) {
+        strategy->min_delay = delay;
+      }
+
+      parcUnsigned_Release(&cid);
+    }
+  }
+}
+
+static unsigned _select_Nexthop(StrategyLoadBalancerWithPD *strategy) {
+  strategy->fwdPackets++;
+  if (strategy->toInit || strategy->fwdPackets == PROBE_FREQUENCY) {
+    strategy->toInit = false;
+    strategy->fwdPackets = 0;
+    _sendProbes(strategy);
+  }
+  double rnd = (double)rand() / (double)RAND_MAX;
+  double start_range = 0.0;
+
+  PARCIterator *it = parcHashMap_CreateKeyIterator(strategy->strategy_state);
+
+  unsigned nexthop = 100000;
+  while (parcIterator_HasNext(it)) {
+    PARCUnsigned *cid = parcIterator_Next(it);
+    const StrategyNexthopStateWithPD *elem =
+        parcHashMap_Get(strategy->strategy_state, cid);
+
+    double w = strategyNexthopStateWithPD_GetWeight(elem);
+
+    // printf("next = %u .. pi %u avgpi %f w %f avgrtt
+    // %f\n",parcUnsigned_GetUnsigned(cid),
+    // strategyNexthopStateWithPD_GetPI(elem),
+    //        strategyNexthopStateWithPD_GetWeight(elem),
+    //        strategyNexthopStateWithPD_GetWeight(elem),
+    //        strategyNexthopStateWithPD_GetAvgRTT(elem));
+
+    double prob = w / strategy->weights_sum;
+    if ((rnd >= start_range) && (rnd < (start_range + prob))) {
+      nexthop = parcUnsigned_GetUnsigned(cid);
+      break;
+    } else {
+      start_range += prob;
+    }
+  }
+
+  parcIterator_Release(&it);
+
+  // if no face is selected by the algorithm (for example because of a wrong
+  // round in the weights) we may always select the last face here. Double check
+  // this!
+  return nexthop;
+}
+
+static void _strategyLoadBalancerWithPD_ReceiveObject(
+    StrategyImpl *strategy, const NumberSet *egressId,
+    const Message *objectMessage, Ticks rtt) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+
+  for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+    unsigned outId = numberSet_GetItem(egressId, i);
+    PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+    const StrategyNexthopStateWithPD *state =
+        parcHashMap_Get(lb->strategy_state, cid);
+    if (state != NULL) {
+      _update_Stats(lb, (StrategyNexthopStateWithPD *)state, false, 0);
+    } else {
+      // this may happen if we remove a face/route while downloading a file
+      // we should ignore this timeout
+    }
+    parcUnsigned_Release(&cid);
+  }
+}
+
+static void _strategyLoadBalancerWithPD_OnTimeout(StrategyImpl *strategy,
+                                                  const NumberSet *egressId) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+
+  for (unsigned i = 0; i < numberSet_Length(egressId); i++) {
+    unsigned outId = numberSet_GetItem(egressId, i);
+    PARCUnsigned *cid = parcUnsigned_Create(outId);
+
+    const StrategyNexthopStateWithPD *state =
+        parcHashMap_Get(lb->strategy_state, cid);
+    if (state != NULL) {
+      _update_Stats(lb, (StrategyNexthopStateWithPD *)state, false, 0);
+    } else {
+      // this may happen if we remove a face/route while downloading a file
+      // we should ignore this timeout
+    }
+    parcUnsigned_Release(&cid);
+  }
+}
+
+// ATTENTION!! This interface force us to create a NumberSet which need to be
+// delited somewhere The specification in the interface requires that this
+// function never returns NULL. in case we have no output face we need to return
+// an empty NumberSet
+static NumberSet *_strategyLoadBalancerWithPD_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+
+  unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+  PARCUnsigned *in = parcUnsigned_Create(in_connection);
+
+  unsigned mapSize = parcHashMap_Size(lb->strategy_state);
+  NumberSet *outList = numberSet_Create();
+
+  if ((mapSize == 0) ||
+      ((mapSize == 1) && parcHashMap_Contains(lb->strategy_state, in))) {
+    // there are no output faces or the input face is also the only output face.
+    // return null to avoid loops
+    parcUnsigned_Release(&in);
+    return outList;
+  }
+
+  unsigned out_connection;
+  do {
+    out_connection = _select_Nexthop(lb);
+  } while (out_connection == in_connection);
+
+  PARCUnsigned *out = parcUnsigned_Create(out_connection);
+
+  const StrategyNexthopStateWithPD *state =
+      parcHashMap_Get(lb->strategy_state, out);
+  if (state == NULL) {
+    // this is an error and should not happen!
+    parcTrapNotImplemented(
+        "Try to send an interest on a face that does not exists");
+  }
+
+  _update_Stats(lb, (StrategyNexthopStateWithPD *)state, true, 0);
+
+  parcUnsigned_Release(&in);
+  parcUnsigned_Release(&out);
+
+  numberSet_Add(outList, out_connection);
+  return outList;
+}
+
+static NumberSet *_strategyLoadBalancerWithPD_ReturnNexthops(
+    StrategyImpl *strategy) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+  return lb->nexthops;
+}
+
+unsigned _strategyLoadBalancerWithPD_CountNexthops(StrategyImpl *strategy) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+  return numberSet_Length(lb->nexthops);
+}
+
+static void _strategyLoadBalancerWithPD_resetState(StrategyImpl *strategy) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+  lb->weights_sum = 0.0;
+  lb->min_delay = INT_MAX;
+  lb->toInit = true;
+  PARCIterator *it = parcHashMap_CreateKeyIterator(lb->strategy_state);
+
+  while (parcIterator_HasNext(it)) {
+    PARCUnsigned *cid = parcIterator_Next(it);
+    StrategyNexthopStateWithPD *elem =
+        (StrategyNexthopStateWithPD *)parcHashMap_Get(lb->strategy_state, cid);
+
+    strategyNexthopStateWithPD_Reset(elem);
+    lb->weights_sum += strategyNexthopStateWithPD_GetWeight(elem);
+  }
+
+  parcIterator_Release(&it);
+}
+
+static void _strategyLoadBalancerWithPD_AddNexthop(StrategyImpl *strategy,
+                                                   unsigned connectionId) {
+  StrategyNexthopStateWithPD *state = strategyNexthopStateWithPD_Create();
+
+  PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+
+  if (!parcHashMap_Contains(lb->strategy_state, cid)) {
+    parcHashMap_Put(lb->strategy_state, cid, state);
+    numberSet_Add(lb->nexthops, connectionId);
+    _strategyLoadBalancerWithPD_resetState(strategy);
+  }
+}
+
+static void _strategyLoadBalancerWithPD_RemoveNexthop(StrategyImpl *strategy,
+                                                      unsigned connectionId) {
+  StrategyLoadBalancerWithPD *lb =
+      (StrategyLoadBalancerWithPD *)strategy->context;
+
+  PARCUnsigned *cid = parcUnsigned_Create(connectionId);
+
+  if (parcHashMap_Contains(lb->strategy_state, cid)) {
+    parcHashMap_Remove(lb->strategy_state, cid);
+    numberSet_Remove(lb->nexthops, connectionId);
+    _strategyLoadBalancerWithPD_resetState(strategy);
+  }
+
+  parcUnsigned_Release(&cid);
+}
+
+static void _strategyLoadBalancerWithPD_ImplDestroy(
+    StrategyImpl **strategyPtr) {
+  parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*strategyPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  StrategyImpl *impl = *strategyPtr;
+  StrategyLoadBalancerWithPD *strategy =
+      (StrategyLoadBalancerWithPD *)impl->context;
+
+  parcHashMap_Release(&(strategy->strategy_state));
+  numberSet_Release(&(strategy->nexthops));
+
+  parcMemory_Deallocate((void **)&strategy);
+  parcMemory_Deallocate((void **)&impl);
+  *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/loadBalancerWithPD.h b/hicn-light/src/strategies/loadBalancerWithPD.h
new file mode 100755 (executable)
index 0000000..6ea7f07
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Forward on the less loaded path taking into account the propagation delay of
+ * the first hop
+ */
+
+#ifndef loadBalancerWithPD_h
+#define loadBalancerWithPD_h
+
+#include <src/core/connectionTable.h>
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl *strategyLoadBalancerWithPD_Create();
+void strategyLoadBalancerWithPD_SetConnectionTable(StrategyImpl *strategy,
+                                                   ConnectionTable *connTable);
+#endif  // loadBalancerWithPD_h
diff --git a/hicn-light/src/strategies/nexthopState.c b/hicn-light/src/strategies/nexthopState.c
new file mode 100755 (executable)
index 0000000..ef0ffe9
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/strategies/nexthopState.h>
+
+struct strategy_nexthop_state {
+  unsigned int pi;
+  double avg_pi;
+  double weight;
+};
+
+static bool _strategyNexthopState_Destructor(
+    StrategyNexthopState **instancePtr) {
+  return true;
+}
+
+parcObject_ImplementAcquire(strategyNexthopState, StrategyNexthopState);
+
+parcObject_ImplementRelease(strategyNexthopState, StrategyNexthopState);
+
+parcObject_Override(
+    StrategyNexthopState, PARCObject,
+    .destructor = (PARCObjectDestructor *)_strategyNexthopState_Destructor,
+    .copy = (PARCObjectCopy *)strategyNexthopState_Copy,
+    .display = (PARCObjectDisplay *)strategyNexthopState_Display,
+    .toString = (PARCObjectToString *)strategyNexthopState_ToString,
+    .equals = (PARCObjectEquals *)strategyNexthopState_Equals,
+    .compare = (PARCObjectCompare *)strategyNexthopState_Compare,
+    .hashCode = (PARCObjectHashCode *)strategyNexthopState_HashCode,
+    .display = (PARCObjectDisplay *)strategyNexthopState_Display);
+
+void strategyNexthopState_AssertValid(const StrategyNexthopState *instance) {
+  parcAssertTrue(strategyNexthopState_IsValid(instance),
+                 "StrategyNexthopState is not valid.");
+}
+
+StrategyNexthopState *strategyNexthopState_Create() {
+  StrategyNexthopState *result =
+      parcObject_CreateInstance(StrategyNexthopState);
+  if (result != NULL) {
+    result->pi = 0;
+    result->avg_pi = 0.0;
+    result->weight = 1;
+  }
+  return result;
+}
+
+void strategyNexthopState_Reset(StrategyNexthopState *x) {
+  x->pi = 0;
+  x->avg_pi = 0.0;
+  x->weight = 1;
+}
+
+int strategyNexthopState_Compare(const StrategyNexthopState *val,
+                                 const StrategyNexthopState *other) {
+  if (val == NULL) {
+    if (other != NULL) {
+      return -1;
+    }
+  } else if (other == NULL) {
+    return 1;
+  } else {
+    strategyNexthopState_OptionalAssertValid(val);
+    strategyNexthopState_OptionalAssertValid(other);
+
+    if (val->pi < other->pi) {
+      return -1;
+    } else if (val->pi > other->pi) {
+      return 1;
+    }
+
+    if (val->avg_pi < other->avg_pi) {
+      return -1;
+    } else if (val->avg_pi > other->avg_pi) {
+      return 1;
+    }
+
+    if (val->weight < other->weight) {
+      return -1;
+    } else if (val->weight > other->weight) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+StrategyNexthopState *strategyNexthopState_Copy(
+    const StrategyNexthopState *original) {
+  StrategyNexthopState *result = strategyNexthopState_Create();
+  result->pi = original->pi;
+  result->avg_pi = original->avg_pi;
+  result->weight = original->weight;
+
+  return result;
+}
+
+void strategyNexthopState_Display(const StrategyNexthopState *instance,
+                                  int indentation) {
+  parcDisplayIndented_PrintLine(indentation, "StrategyNexthopState@%p {",
+                                instance);
+  parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi);
+  parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi);
+  parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight);
+  parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool strategyNexthopState_Equals(const StrategyNexthopState *x,
+                                 const StrategyNexthopState *y) {
+  bool result = false;
+
+  if (x == y) {
+    result = true;
+  } else if (x == NULL || y == NULL) {
+    result = false;
+  } else {
+    strategyNexthopState_OptionalAssertValid(x);
+    strategyNexthopState_OptionalAssertValid(y);
+
+    if (strategyNexthopState_Compare(x, y) == 0) {
+      result = true;
+    }
+  }
+
+  return result;
+}
+
+PARCHashCode strategyNexthopState_HashCode(const StrategyNexthopState *x) {
+  PARCHashCode result = 0;
+  char str[128];
+  sprintf(str, "PI:%d: AVG_PI:%f: W:%f", x->pi, x->avg_pi, x->weight);
+  result = parcHashCode_Hash((uint8_t *)&str, strlen(str));
+  return result;
+}
+
+bool strategyNexthopState_IsValid(const StrategyNexthopState *x) {
+  bool result = false;
+
+  if (x != NULL) {
+    result = true;
+  }
+
+  return result;
+}
+
+char *strategyNexthopState_ToString(const StrategyNexthopState *x) {
+  // this is not implemented
+  parcTrapNotImplemented("strategyNexthopState_ToString is not implemented");
+  return NULL;
+}
+
+unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x) {
+  strategyNexthopState_OptionalAssertValid(x);
+
+  return x->pi;
+}
+
+double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x) {
+  strategyNexthopState_OptionalAssertValid(x);
+
+  return x->avg_pi;
+}
+
+double strategyNexthopState_GetWeight(const StrategyNexthopState *x) {
+  strategyNexthopState_OptionalAssertValid(x);
+
+  return x->weight;
+}
+
+double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc,
+                                        double alpha) {
+  if (inc) {
+    x->pi++;
+  } else {
+    if (x->pi > 0) {
+      x->pi--;
+    }
+  }
+  x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha));
+  if (x->avg_pi == 0.0) {
+    x->avg_pi = 0.1;
+  }
+  x->weight = 1 / x->avg_pi;
+
+  return x->weight;
+}
diff --git a/hicn-light/src/strategies/nexthopState.h b/hicn-light/src/strategies/nexthopState.h
new file mode 100755 (executable)
index 0000000..35a9f49
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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 nexthopstate_h
+#define nexthopstate_h
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+
+struct strategy_nexthop_state;
+typedef struct strategy_nexthop_state StrategyNexthopState;
+extern parcObjectDescriptor_Declaration(StrategyNexthopState);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Acquire(
+    const StrategyNexthopState *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+#define strategyNexthopState_OptionalAssertValid(_instance_)
+#else
+#define strategyNexthopState_OptionalAssertValid(_instance_) \
+  strategyNexthopState_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void strategyNexthopState_AssertValid(const StrategyNexthopState *instance);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Create();
+
+void strategyNexthopState_Reset(StrategyNexthopState *x);
+/**
+ */
+int strategyNexthopState_Compare(const StrategyNexthopState *instance,
+                                 const StrategyNexthopState *other);
+
+/**
+ */
+StrategyNexthopState *strategyNexthopState_Copy(
+    const StrategyNexthopState *original);
+
+/**
+ */
+void strategyNexthopState_Display(const StrategyNexthopState *instance,
+                                  int indentation);
+
+/**
+ */
+bool strategyNexthopState_Equals(const StrategyNexthopState *x,
+                                 const StrategyNexthopState *y);
+
+/**
+ */
+PARCHashCode strategyNexthopState_HashCode(
+    const StrategyNexthopState *instance);
+
+/**
+ */
+bool strategyNexthopState_IsValid(const StrategyNexthopState *instance);
+
+/**
+ */
+void strategyNexthopState_Release(StrategyNexthopState **instancePtr);
+
+/**
+ */
+char *strategyNexthopState_ToString(const StrategyNexthopState *instance);
+
+/**
+ */
+unsigned strategyNexthopState_GetPI(const StrategyNexthopState *x);
+
+double strategyNexthopState_GetAvgPI(const StrategyNexthopState *x);
+
+double strategyNexthopState_GetWeight(const StrategyNexthopState *x);
+
+double strategyNexthopState_UpdateState(StrategyNexthopState *x, bool inc,
+                                        double alpha);
+#endif
diff --git a/hicn-light/src/strategies/nexthopStateWithPD.c b/hicn-light/src/strategies/nexthopStateWithPD.c
new file mode 100755 (executable)
index 0000000..2eecb0c
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017-2019 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 <float.h>
+#include <limits.h>
+#include <src/config.h>
+#include <stdio.h>
+
+#include <parc/algol/parc_DisplayIndented.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/assert/parc_Assert.h>
+
+#include <src/strategies/nexthopStateWithPD.h>
+
+struct strategy_nexthop_state_with_pd {
+  unsigned int pi;
+  unsigned delay;
+  double weight;
+  double avg_pi;
+};
+
+static bool _strategyNexthopStateWithPD_Destructor(
+    StrategyNexthopStateWithPD **instancePtr) {
+  return true;
+}
+
+parcObject_ImplementAcquire(strategyNexthopStateWithPD,
+                            StrategyNexthopStateWithPD);
+
+parcObject_ImplementRelease(strategyNexthopStateWithPD,
+                            StrategyNexthopStateWithPD);
+
+parcObject_Override(
+    StrategyNexthopStateWithPD, PARCObject,
+    .destructor = (PARCObjectDestructor *)
+        _strategyNexthopStateWithPD_Destructor,
+    .copy = (PARCObjectCopy *)strategyNexthopStateWithPD_Copy,
+    .display = (PARCObjectDisplay *)strategyNexthopStateWithPD_Display,
+    .toString = (PARCObjectToString *)strategyNexthopStateWithPD_ToString,
+    .equals = (PARCObjectEquals *)strategyNexthopStateWithPD_Equals,
+    .compare = (PARCObjectCompare *)strategyNexthopStateWithPD_Compare,
+    .hashCode = (PARCObjectHashCode *)strategyNexthopStateWithPD_HashCode,
+    .display = (PARCObjectDisplay *)strategyNexthopStateWithPD_Display);
+
+void strategyNexthopStateWithPD_AssertValid(
+    const StrategyNexthopStateWithPD *instance) {
+  parcAssertTrue(strategyNexthopStateWithPD_IsValid(instance),
+                 "StrategyNexthopStateWithPD is not valid.");
+}
+
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Create() {
+  StrategyNexthopStateWithPD *result =
+      parcObject_CreateInstance(StrategyNexthopStateWithPD);
+  if (result != NULL) {
+    result->pi = 0;
+    result->avg_pi = 1.0;
+    result->weight = 1;
+    result->delay = 0;
+  }
+  return result;
+}
+
+void strategyNexthopStateWithPD_Reset(StrategyNexthopStateWithPD *x) {
+  x->pi = 0;
+  x->avg_pi = 1.0;
+  x->weight = 1;
+  x->delay = 0;
+}
+
+int strategyNexthopStateWithPD_Compare(
+    const StrategyNexthopStateWithPD *val,
+    const StrategyNexthopStateWithPD *other) {
+  if (val == NULL) {
+    if (other != NULL) {
+      return -1;
+    }
+  } else if (other == NULL) {
+    return 1;
+  } else {
+    strategyNexthopStateWithPD_OptionalAssertValid(val);
+    strategyNexthopStateWithPD_OptionalAssertValid(other);
+
+    if (val->pi < other->pi) {
+      return -1;
+    } else if (val->pi > other->pi) {
+      return 1;
+    }
+
+    if (val->avg_pi < other->avg_pi) {
+      return -1;
+    } else if (val->avg_pi > other->avg_pi) {
+      return 1;
+    }
+
+    if (val->weight < other->weight) {
+      return -1;
+    } else if (val->weight > other->weight) {
+      return 1;
+    }
+
+    if (val->delay < other->delay) {
+      return -1;
+    } else if (val->delay > other->delay) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Copy(
+    const StrategyNexthopStateWithPD *original) {
+  StrategyNexthopStateWithPD *result = strategyNexthopStateWithPD_Create();
+  result->pi = original->pi;
+  result->avg_pi = original->avg_pi;
+  result->weight = original->weight;
+  result->delay = original->delay;
+
+  return result;
+}
+
+void strategyNexthopStateWithPD_Display(
+    const StrategyNexthopStateWithPD *instance, int indentation) {
+  parcDisplayIndented_PrintLine(indentation, "StrategyNexthopStateWithPD@%p {",
+                                instance);
+  parcDisplayIndented_PrintLine(indentation + 1, "%d", instance->pi);
+  parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->avg_pi);
+  parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->weight);
+  parcDisplayIndented_PrintLine(indentation + 1, "%f", instance->delay);
+  parcDisplayIndented_PrintLine(indentation, "}");
+}
+
+bool strategyNexthopStateWithPD_Equals(const StrategyNexthopStateWithPD *x,
+                                       const StrategyNexthopStateWithPD *y) {
+  bool result = false;
+
+  if (x == y) {
+    result = true;
+  } else if (x == NULL || y == NULL) {
+    result = false;
+  } else {
+    strategyNexthopStateWithPD_OptionalAssertValid(x);
+    strategyNexthopStateWithPD_OptionalAssertValid(y);
+
+    if (strategyNexthopStateWithPD_Compare(x, y) == 0) {
+      result = true;
+    }
+  }
+
+  return result;
+}
+
+PARCHashCode strategyNexthopStateWithPD_HashCode(
+    const StrategyNexthopStateWithPD *x) {
+  PARCHashCode result = 0;
+  char str[128];
+  sprintf(str, "PI:%d: AVG_PI:%f: W:%f D:%d", x->pi, x->avg_pi, x->weight,
+          x->delay);
+  result = parcHashCode_Hash((uint8_t *)&str, strlen(str));
+  return result;
+}
+
+bool strategyNexthopStateWithPD_IsValid(const StrategyNexthopStateWithPD *x) {
+  bool result = false;
+
+  if (x != NULL) {
+    result = true;
+  }
+
+  return result;
+}
+
+char *strategyNexthopStateWithPD_ToString(const StrategyNexthopStateWithPD *x) {
+  // this is not implemented
+  parcTrapNotImplemented(
+      "strategyNexthopStateWithPD_ToString is not implemented");
+  return NULL;
+}
+
+unsigned strategyNexthopStateWithPD_GetPI(const StrategyNexthopStateWithPD *x) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+  return x->pi;
+}
+
+double strategyNexthopStateWithPD_GetAvgPI(
+    const StrategyNexthopStateWithPD *x) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+  return x->avg_pi;
+}
+
+double strategyNexthopStateWithPD_GetWeight(
+    const StrategyNexthopStateWithPD *x) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+  return x->weight;
+}
+
+unsigned strategyNexthopStateWithPD_GetDelay(
+    const StrategyNexthopStateWithPD *x) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+  return x->delay;
+}
+
+void strategyNexthopStateWithPD_SetDelay(StrategyNexthopStateWithPD *x,
+                                         unsigned delay) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+  if (delay != 0) {
+    x->delay = delay;
+  }
+}
+
+double strategyNexthopStateWithPD_UpdateState(StrategyNexthopStateWithPD *x,
+                                              bool inc, unsigned min_delay,
+                                              double alpha) {
+  strategyNexthopStateWithPD_OptionalAssertValid(x);
+
+  if (inc) {
+    x->pi++;
+  } else {
+    if (x->pi > 0) {
+      x->pi--;
+    }
+  }
+
+  x->avg_pi = (x->avg_pi * alpha) + (x->pi * (1 - alpha));
+  if (x->avg_pi == 0.0) {
+    x->avg_pi = 0.1;
+  }
+
+  double factor = 1.0;
+  if (min_delay != INT_MAX && x->delay != 0) {
+    factor = ((double)min_delay / (double)x->delay);
+  }
+
+  x->weight = 1 / (x->avg_pi * factor);
+
+  return x->weight;
+}
diff --git a/hicn-light/src/strategies/nexthopStateWithPD.h b/hicn-light/src/strategies/nexthopStateWithPD.h
new file mode 100755 (executable)
index 0000000..4d8bd6d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2017-2019 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 nexthopstatewithpd_h
+#define nexthopstatewithpd_h
+
+#include <parc/algol/parc_HashCode.h>
+#include <parc/algol/parc_Object.h>
+
+struct strategy_nexthop_state_with_pd;
+typedef struct strategy_nexthop_state_with_pd StrategyNexthopStateWithPD;
+extern parcObjectDescriptor_Declaration(StrategyNexthopStateWithPD);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Acquire(
+    const StrategyNexthopStateWithPD *instance);
+
+#ifdef PARCLibrary_DISABLE_VALIDATION
+#define strategyNexthopStateWithPD_OptionalAssertValid(_instance_)
+#else
+#define strategyNexthopStateWithPD_OptionalAssertValid(_instance_) \
+  strategyNexthopStateWithPD_AssertValid(_instance_)
+#endif
+
+/**
+ */
+void strategyNexthopStateWithPD_AssertValid(
+    const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Create();
+
+void strategyNexthopStateWithPD_Reset(StrategyNexthopStateWithPD *x);
+/**
+ */
+int strategyNexthopStateWithPD_Compare(
+    const StrategyNexthopStateWithPD *instance,
+    const StrategyNexthopStateWithPD *other);
+
+/**
+ */
+StrategyNexthopStateWithPD *strategyNexthopStateWithPD_Copy(
+    const StrategyNexthopStateWithPD *original);
+
+/**
+ */
+void strategyNexthopStateWithPD_Display(
+    const StrategyNexthopStateWithPD *instance, int indentation);
+
+/**
+ */
+bool strategyNexthopStateWithPD_Equals(const StrategyNexthopStateWithPD *x,
+                                       const StrategyNexthopStateWithPD *y);
+
+/**
+ */
+PARCHashCode strategyNexthopStateWithPD_HashCode(
+    const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+bool strategyNexthopStateWithPD_IsValid(
+    const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+void strategyNexthopStateWithPD_Release(
+    StrategyNexthopStateWithPD **instancePtr);
+
+/**
+ */
+char *strategyNexthopStateWithPD_ToString(
+    const StrategyNexthopStateWithPD *instance);
+
+/**
+ */
+unsigned strategyNexthopStateWithPD_GetPI(const StrategyNexthopStateWithPD *x);
+
+double strategyNexthopStateWithPD_GetAvgPI(const StrategyNexthopStateWithPD *x);
+
+double strategyNexthopStateWithPD_GetWeight(
+    const StrategyNexthopStateWithPD *x);
+
+unsigned strategyNexthopStateWithPD_GetDelay(
+    const StrategyNexthopStateWithPD *x);
+void strategyNexthopStateWithPD_SetDelay(StrategyNexthopStateWithPD *x,
+                                         unsigned delay);
+
+double strategyNexthopStateWithPD_UpdateState(StrategyNexthopStateWithPD *x,
+                                              bool inc, unsigned min_delay,
+                                              double alpha);
+#endif
diff --git a/hicn-light/src/strategies/rnd.c b/hicn-light/src/strategies/rnd.c
new file mode 100755 (executable)
index 0000000..37f3f6f
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <src/strategies/rnd.h>
+
+static void _strategyRnd_ReceiveObject(StrategyImpl *strategy,
+                                       const NumberSet *egressId,
+                                       const Message *objectMessage, Ticks rtt);
+static void _strategyRnd_OnTimeout(StrategyImpl *strategy,
+                                   const NumberSet *egressId);
+static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy,
+                                             const Message *interestMessage);
+static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy);
+static void _strategyRnd_AddNexthop(StrategyImpl *strategy,
+                                    unsigned connectionId);
+static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy,
+                                       unsigned connectionId);
+static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+    .context = NULL,
+    .receiveObject = &_strategyRnd_ReceiveObject,
+    .onTimeout = &_strategyRnd_OnTimeout,
+    .lookupNexthop = &_strategyRnd_LookupNexthop,
+    .returnNexthops = &_strategyRnd_ReturnNexthops,
+    .countNexthops = &_strategyRnd_CountNexthops,
+    .addNexthop = &_strategyRnd_AddNexthop,
+    .removeNexthop = &_strategyRnd_RemoveNexthop,
+    .destroy = &_strategyRnd_ImplDestroy,
+    .getStrategy = &_strategyRnd_GetStrategy,
+};
+
+struct strategy_rnd;
+typedef struct strategy_rnd StrategyRnd;
+
+struct strategy_rnd {
+  NumberSet *nexthops;
+};
+
+StrategyImpl *strategyRnd_Create() {
+  StrategyRnd *strategy = parcMemory_AllocateAndClear(sizeof(StrategyRnd));
+  parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyRnd));
+
+  strategy->nexthops = numberSet_Create();
+  srand(time(NULL));
+
+  StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+  parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyImpl));
+  memcpy(impl, &_template, sizeof(StrategyImpl));
+  impl->context = strategy;
+  return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyRnd_GetStrategy(StrategyImpl *strategy) {
+  return SET_STRATEGY_RANDOM;
+}
+
+static int _select_Nexthop(StrategyRnd *strategy) {
+  unsigned len = numberSet_Length(strategy->nexthops);
+  if (len == 0) {
+    return -1;
+  }
+
+  int rnd = (rand() % len);
+  return numberSet_GetItem(strategy->nexthops, rnd);
+}
+
+static void _strategyRnd_ReceiveObject(StrategyImpl *strategy,
+                                       const NumberSet *egressId,
+                                       const Message *objectMessage,
+                                       Ticks rtt) {}
+
+static void _strategyRnd_OnTimeout(StrategyImpl *strategy,
+                                   const NumberSet *egressId) {}
+
+static NumberSet *_strategyRnd_LookupNexthop(StrategyImpl *strategy,
+                                             const Message *interestMessage) {
+  StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+
+  unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+  unsigned nexthopSize = numberSet_Length(srnd->nexthops);
+
+  NumberSet *out = numberSet_Create();
+  if ((nexthopSize == 0) ||
+      ((nexthopSize == 1) &&
+       numberSet_Contains(srnd->nexthops, in_connection))) {
+    // there are no output faces or the input face is also the only output face.
+    // return null to avoid loops
+    return out;
+  }
+
+  unsigned out_connection;
+  do {
+    out_connection = _select_Nexthop(srnd);
+  } while (out_connection == in_connection);
+
+  if (out_connection == -1) {
+    return out;
+  }
+
+  numberSet_Add(out, out_connection);
+  return out;
+}
+
+static NumberSet *_strategyRnd_ReturnNexthops(StrategyImpl *strategy) {
+  StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+  return srnd->nexthops;
+}
+
+unsigned _strategyRnd_CountNexthops(StrategyImpl *strategy) {
+  StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+  return numberSet_Length(srnd->nexthops);
+}
+
+static void _strategyRnd_AddNexthop(StrategyImpl *strategy,
+                                    unsigned connectionId) {
+  StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+  if (!numberSet_Contains(srnd->nexthops, connectionId)) {
+    numberSet_Add(srnd->nexthops, connectionId);
+  }
+}
+
+static void _strategyRnd_RemoveNexthop(StrategyImpl *strategy,
+                                       unsigned connectionId) {
+  StrategyRnd *srnd = (StrategyRnd *)strategy->context;
+
+  if (numberSet_Contains(srnd->nexthops, connectionId)) {
+    numberSet_Remove(srnd->nexthops, connectionId);
+  }
+}
+
+static void _strategyRnd_ImplDestroy(StrategyImpl **strategyPtr) {
+  parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*strategyPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  StrategyImpl *impl = *strategyPtr;
+  StrategyRnd *strategy = (StrategyRnd *)impl->context;
+
+  numberSet_Release(&(strategy->nexthops));
+
+  parcMemory_Deallocate((void **)&strategy);
+  parcMemory_Deallocate((void **)&impl);
+  *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/rnd.h b/hicn-light/src/strategies/rnd.h
new file mode 100755 (executable)
index 0000000..69bedc1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Forward randomly
+ */
+
+#ifndef rnd_h
+#define rnd_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl* strategyRnd_Create();
+#endif  // rnd_h
diff --git a/hicn-light/src/strategies/rndSegment.c b/hicn-light/src/strategies/rndSegment.c
new file mode 100755 (executable)
index 0000000..2000ed7
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_HashMap.h>
+#include <parc/algol/parc_Memory.h>
+#include <src/core/nameBitvector.h>
+#include <src/strategies/rndSegment.h>
+
+static void _strategyRndSegment_ReceiveObject(StrategyImpl *strategy,
+                                              const NumberSet *egressId,
+                                              const Message *objectMessage,
+                                              Ticks rtt);
+static void _strategyRndSegment_OnTimeout(StrategyImpl *strategy,
+                                          const NumberSet *egressId);
+static NumberSet *_strategyRndSegment_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage);
+static NumberSet *_strategyRndSegment_ReturnNexthops(StrategyImpl *strategy);
+static unsigned _strategyRndSegment_CountNexthops(StrategyImpl *strategy);
+static void _strategyRndSegment_AddNexthop(StrategyImpl *strategy,
+                                           unsigned connectionId);
+static void _strategyRndSegment_RemoveNexthop(StrategyImpl *strategy,
+                                              unsigned connectionId);
+static void _strategyRndSegment_ImplDestroy(StrategyImpl **strategyPtr);
+static strategy_type _strategyRndSegment_GetStrategy(StrategyImpl *strategy);
+
+static StrategyImpl _template = {
+    .context = NULL,
+    .receiveObject = &_strategyRndSegment_ReceiveObject,
+    .onTimeout = &_strategyRndSegment_OnTimeout,
+    .lookupNexthop = &_strategyRndSegment_LookupNexthop,
+    .returnNexthops = &_strategyRndSegment_ReturnNexthops,
+    .countNexthops = &_strategyRndSegment_CountNexthops,
+    .addNexthop = &_strategyRndSegment_AddNexthop,
+    .removeNexthop = &_strategyRndSegment_RemoveNexthop,
+    .destroy = &_strategyRndSegment_ImplDestroy,
+    .getStrategy = &_strategyRndSegment_GetStrategy,
+};
+
+struct strategy_rnd_segment;
+typedef struct strategy_rnd_segment StrategyRndSegment;
+
+struct strategy_rnd_segment {
+  NumberSet *nexthops;
+  NameBitvector *segmentName;
+  int last_used_face;
+};
+
+StrategyImpl *strategyRndSegment_Create() {
+  StrategyRndSegment *strategy =
+      parcMemory_AllocateAndClear(sizeof(StrategyRndSegment));
+  parcAssertNotNull(strategy, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyRndSegment));
+
+  strategy->nexthops = numberSet_Create();
+  strategy->segmentName = NULL;
+  strategy->last_used_face = 0;
+  srand(time(NULL));
+
+  StrategyImpl *impl = parcMemory_AllocateAndClear(sizeof(StrategyImpl));
+  parcAssertNotNull(impl, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(StrategyImpl));
+  memcpy(impl, &_template, sizeof(StrategyImpl));
+  impl->context = strategy;
+
+  return impl;
+}
+
+// =======================================================
+// Dispatch API
+
+strategy_type _strategyRndSegment_GetStrategy(StrategyImpl *strategy) {
+  return SET_STRATEGY_RANDOM_PER_DASH_SEGMENT;
+}
+
+static int _select_Nexthop(StrategyRndSegment *strategy) {
+  unsigned len = numberSet_Length(strategy->nexthops);
+  if (len == 0) {
+    return -1;
+  }
+
+  int rnd = (rand() % len);
+  return numberSet_GetItem(strategy->nexthops, rnd);
+}
+
+static void _strategyRndSegment_ReceiveObject(StrategyImpl *strategy,
+                                              const NumberSet *egressId,
+                                              const Message *objectMessage,
+                                              Ticks rtt) {}
+
+static void _strategyRndSegment_OnTimeout(StrategyImpl *strategy,
+                                          const NumberSet *egressId) {}
+
+static NumberSet *_strategyRndSegment_LookupNexthop(
+    StrategyImpl *strategy, const Message *interestMessage) {
+  StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+
+  unsigned in_connection = message_GetIngressConnectionId(interestMessage);
+  unsigned nexthopSize = numberSet_Length(srnd->nexthops);
+
+  NumberSet *out = numberSet_Create();
+  if ((nexthopSize == 0) ||
+      ((nexthopSize == 1) &&
+       numberSet_Contains(srnd->nexthops, in_connection))) {
+    // there are no output faces or the input face is also the only output face.
+    // return null to avoid loops
+    return out;
+  }
+
+  NameBitvector *interestName =
+      name_GetContentName(message_GetName(interestMessage));
+
+  if (srnd->segmentName == NULL) {
+    srnd->segmentName = nameBitvector_Copy(interestName);
+  } else if (!nameBitvector_Equals(srnd->segmentName, interestName)) {
+    nameBitvector_Destroy(&srnd->segmentName);
+    srnd->segmentName = nameBitvector_Copy(interestName);
+  } else {
+    // here we need to check if the output face still exists or if someone erase
+    // it
+    if (numberSet_Contains(srnd->nexthops, srnd->last_used_face)) {
+      // face exists, so keep using it!
+      numberSet_Add(out, srnd->last_used_face);
+      return out;
+    } else {
+      // the face does not exists anymore, try to find a new face but keep the
+      // name of the dash segment
+    }
+  }
+
+  int out_connection;
+  do {
+    out_connection = _select_Nexthop(srnd);
+  } while (out_connection == in_connection);
+
+  if (out_connection == -1) {
+    return out;
+  }
+
+  srnd->last_used_face = out_connection;
+  numberSet_Add(out, out_connection);
+  return out;
+}
+
+static NumberSet *_strategyRndSegment_ReturnNexthops(StrategyImpl *strategy) {
+  StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+  return srnd->nexthops;
+}
+
+unsigned _strategyRndSegment_CountNexthops(StrategyImpl *strategy) {
+  StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+  return numberSet_Length(srnd->nexthops);
+}
+
+static void _strategyRndSegment_AddNexthop(StrategyImpl *strategy,
+                                           unsigned connectionId) {
+  StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+  if (!numberSet_Contains(srnd->nexthops, connectionId)) {
+    numberSet_Add(srnd->nexthops, connectionId);
+  }
+}
+
+static void _strategyRndSegment_RemoveNexthop(StrategyImpl *strategy,
+                                              unsigned connectionId) {
+  StrategyRndSegment *srnd = (StrategyRndSegment *)strategy->context;
+
+  if (numberSet_Contains(srnd->nexthops, connectionId)) {
+    numberSet_Remove(srnd->nexthops, connectionId);
+  }
+}
+
+static void _strategyRndSegment_ImplDestroy(StrategyImpl **strategyPtr) {
+  parcAssertNotNull(strategyPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*strategyPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  StrategyImpl *impl = *strategyPtr;
+  StrategyRndSegment *strategy = (StrategyRndSegment *)impl->context;
+
+  numberSet_Release(&(strategy->nexthops));
+  if (strategy->segmentName != NULL) {
+    nameBitvector_Destroy(&strategy->segmentName);
+  }
+
+  parcMemory_Deallocate((void **)&strategy);
+  parcMemory_Deallocate((void **)&impl);
+  *strategyPtr = NULL;
+}
diff --git a/hicn-light/src/strategies/rndSegment.h b/hicn-light/src/strategies/rndSegment.h
new file mode 100755 (executable)
index 0000000..0749692
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * Forward randomly, selects a path every time the client ask for a new dash
+ * segment
+ */
+
+#ifndef rnd_Segment_h
+#define rnd_Segment_h
+
+#include <src/strategies/strategyImpl.h>
+
+StrategyImpl* strategyRndSegment_Create();
+#endif  // rnd_Segment_h
diff --git a/hicn-light/src/strategies/strategyImpl.h b/hicn-light/src/strategies/strategyImpl.h
new file mode 100755 (executable)
index 0000000..c089e0b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file strategyImpl.h
+ * @brief Defines the function structure for a Strategy implementation
+ *
+ * <#Detailed Description#>
+ *
+ */
+
+/**
+ * A dispatch structure for a concrete implementation of a forwarding strategy.
+ */
+
+#ifndef strategyImpl_h
+#define strategyImpl_h
+
+#include <src/core/message.h>
+#include <src/core/numberSet.h>
+
+struct strategy_impl;
+typedef struct strategy_impl StrategyImpl;
+
+/**
+ * @typedef StrategyImpl
+ * @abstract Forwarding strategy implementation
+ * @constant receiveObject is called when we receive an object and have a
+ * measured round trip time.  This allows a strategy to update its performance
+ * data.
+ * @constant lookupNexthop Find the set of nexthops to use for the Interest.
+ *           May be empty, should not be NULL.  Must be destroyed.
+ * @constant addNexthop Add a nexthop to the list of available nexthops with a
+ * routing protocol-specific cost.
+ * @constant destroy cleans up the strategy, freeing all memory and state.  A
+ * strategy is reference counted, so the final destruction only happens after
+ * the last reference is released.
+ * @discussion <#Discussion#>
+ */
+struct strategy_impl {
+  void *context;
+  void (*receiveObject)(StrategyImpl *strategy, const NumberSet *egressId,
+                        const Message *objectMessage, Ticks rtt);
+  void (*onTimeout)(StrategyImpl *strategy, const NumberSet *egressId);
+  NumberSet *(*lookupNexthop)(StrategyImpl *strategy,
+                              const Message *interestMessage);
+  NumberSet *(*returnNexthops)(StrategyImpl *strategy);
+  unsigned (*countNexthops)(StrategyImpl *strategy);
+  void (*addNexthop)(StrategyImpl *strategy, unsigned connectionId);
+  void (*removeNexthop)(StrategyImpl *strategy, unsigned connectionId);
+  void (*destroy)(StrategyImpl **strategyPtr);
+  strategy_type (*getStrategy)(StrategyImpl *strategy);
+};
+#endif  // strategyImpl_h
diff --git a/hicn-light/src/utils/CMakeLists.txt b/hicn-light/src/utils/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..7d438d1
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/address.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/addressList.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/commands.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/interface.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/punting.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/utils.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/address.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/addressList.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/interface.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/interfaceSet.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/punting.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/utils.c
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/hicn-light/src/utils/address.c b/hicn-light/src/utils/address.c
new file mode 100755 (executable)
index 0000000..3f6fe25
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2017-2019 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 <arpa/inet.h>
+#include <errno.h>
+#include <src/config.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <src/utils/address.h>
+
+#include <parc/algol/parc_Base64.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Hash.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/algol/parc_Object.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct address {
+  address_type addressType;
+  PARCBuffer *blob;
+};
+
+static struct address_type_str {
+  address_type type;
+  const char *str;
+} addressTypeString[] = {
+    {.type = ADDR_INET, .str = "INET"}, {.type = ADDR_INET6, .str = "INET6"},
+    {.type = ADDR_LINK, .str = "LINK"}, {.type = ADDR_IFACE, .str = "IFACE"},
+    {.type = ADDR_UNIX, .str = "UNIX"}, {.type = 0, .str = NULL}};
+
+void addressDestroy(Address **addressPtr) {
+  parcAssertNotNull(addressPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*addressPtr,
+                    "Parameter must dereference to non-null pointer");
+
+  Address *address = *addressPtr;
+  parcBuffer_Release(&address->blob);
+  parcMemory_Deallocate((void **)&address);
+  *addressPtr = NULL;
+}
+
+void addressAssertValid(const Address *address) {
+  parcAssertNotNull(address, "Parameter must be non-null Address *");
+}
+
+const char *addressTypeToString(address_type type) {
+  for (int i = 0; addressTypeString[i].str != NULL; i++) {
+    if (addressTypeString[i].type == type) {
+      return addressTypeString[i].str;
+    }
+  }
+  parcTrapIllegalValue(type, "Unknown value: %d", type);
+  const char *result = NULL;
+  return result;
+}
+
+address_type addressStringToType(const char *str) {
+  for (int i = 0; addressTypeString[i].str != NULL; i++) {
+    if (strcasecmp(addressTypeString[i].str, str) == 0) {
+      return addressTypeString[i].type;
+    }
+  }
+  parcTrapIllegalValue(str, "Unknown type '%s'", str);
+  return 0;
+}
+
+static Address *_addressCreate(address_type addressType, PARCBuffer *buffer) {
+  Address *result = parcMemory_AllocateAndClear(sizeof(Address));
+
+  parcAssertNotNull(result, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Address));
+  if (result != NULL) {
+    result->addressType = addressType;
+    result->blob = buffer;
+  }
+  return result;
+}
+
+Address *addressCreateFromInet(struct sockaddr_in *addr_in) {
+  parcAssertNotNull(addr_in, "Parameter must be non-null");
+
+  addr_in->sin_family = AF_INET;
+
+  PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in));
+  parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in), (uint8_t *)addr_in);
+  parcBuffer_Flip(buffer);
+
+  Address *result = _addressCreate(ADDR_INET, buffer);
+
+  return result;
+}
+
+Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6) {
+  parcAssertNotNull(addr_in6, "Parameter must be non-null");
+
+  PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+  parcBuffer_PutArray(buffer, sizeof(struct sockaddr_in6), (uint8_t *)addr_in6);
+  parcBuffer_Flip(buffer);
+
+  Address *result = _addressCreate(ADDR_INET6, buffer);
+
+  return result;
+}
+
+Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length) {
+  parcAssertNotNull(linkaddr, "Parameter must be non-null");
+
+  PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_in6));
+  parcBuffer_PutArray(buffer, length, linkaddr);
+  parcBuffer_Flip(buffer);
+
+  Address *result = _addressCreate(ADDR_LINK, buffer);
+  return result;
+}
+
+Address *addressCreateFromInterface(unsigned interfaceIndex) {
+  unsigned netbyteorder = htonl(interfaceIndex);
+
+  PARCBuffer *buffer = parcBuffer_Allocate(sizeof(netbyteorder));
+  parcBuffer_PutArray(buffer, sizeof(netbyteorder), (uint8_t *)&netbyteorder);
+  parcBuffer_Flip(buffer);
+
+  Address *result = _addressCreate(ADDR_IFACE, buffer);
+  return result;
+}
+
+Address *addressCreateFromUnix(struct sockaddr_un *addr_un) {
+  parcAssertNotNull(addr_un, "Parameter must be non-null");
+
+  PARCBuffer *buffer = parcBuffer_Allocate(sizeof(struct sockaddr_un));
+  parcBuffer_PutArray(buffer, sizeof(struct sockaddr_un), (uint8_t *)addr_un);
+  parcBuffer_Flip(buffer);
+
+  Address *result = _addressCreate(ADDR_UNIX, buffer);
+  return result;
+}
+
+Address *addressCopy(const Address *original) {
+  addressAssertValid(original);
+
+  Address *result =
+      _addressCreate(original->addressType, parcBuffer_Copy(original->blob));
+  return result;
+}
+
+bool addressEquals(const Address *a, const Address *b) {
+  if (a == b) {
+    return true;
+  }
+
+  if (a == NULL || b == NULL) {
+    return false;
+  }
+
+  if (a->addressType == b->addressType) {
+    if (parcBuffer_Equals(a->blob, b->blob)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+address_type addressGetType(const Address *address) {
+  addressAssertValid(address);
+
+  return address->addressType;
+}
+
+// The Get functions need better names, what they do (Get from what? Put to
+// what?) is not clear from their names.  Case 1028
+bool addressGetInet(const Address *address, struct sockaddr_in *addr_in) {
+  addressAssertValid(address);
+  parcAssertNotNull(addr_in, "Parameter addr_in must be non-null");
+
+  if (address->addressType == ADDR_INET) {
+    parcAssertTrue(
+        parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in),
+        "Address corrupted. Expected length %zu, actual length %zu",
+        sizeof(struct sockaddr_in), parcBuffer_Remaining(address->blob));
+
+    memcpy(addr_in, parcBuffer_Overlay(address->blob, 0),
+           sizeof(struct sockaddr_in));
+    return true;
+  }
+  return false;
+}
+
+bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6) {
+  addressAssertValid(address);
+  parcAssertNotNull(addr_in6, "Parameter addr_in6 must be non-null");
+
+  if (address->addressType == ADDR_INET6) {
+    parcAssertTrue(
+        parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_in6),
+        "Address corrupted. Expected length %zu, actual length %zu",
+        sizeof(struct sockaddr_in6), parcBuffer_Remaining(address->blob));
+
+    memcpy(addr_in6, parcBuffer_Overlay(address->blob, 0),
+           sizeof(struct sockaddr_in6));
+    return true;
+  }
+  return false;
+}
+
+bool addressGetUnix(const Address *address, struct sockaddr_un *addr_un) {
+  addressAssertValid(address);
+  parcAssertNotNull(addr_un, "Parameter addr_in6 must be non-null");
+
+  if (address->addressType == ADDR_UNIX) {
+    parcAssertTrue(
+        parcBuffer_Remaining(address->blob) == sizeof(struct sockaddr_un),
+        "Address corrupted. Expected length %zu, actual length %zu",
+        sizeof(struct sockaddr_un), parcBuffer_Remaining(address->blob));
+
+    memcpy(addr_un, parcBuffer_Overlay(address->blob, 0),
+           sizeof(struct sockaddr_un));
+    return true;
+  }
+  return false;
+}
+
+bool addressGetInterfaceIndex(const Address *address, uint32_t *ifidx) {
+  addressAssertValid(address);
+  parcAssertNotNull(ifidx, "Parameter ifidx must be non-null");
+
+  if (address->addressType == ADDR_IFACE) {
+    parcAssertTrue(parcBuffer_Remaining(address->blob) == sizeof(uint32_t),
+                   "Address corrupted. Expected length %zu, actual length %zu",
+                   sizeof(uint32_t), parcBuffer_Remaining(address->blob));
+
+    uint32_t netbyteorder;
+    memcpy(&netbyteorder, parcBuffer_Overlay(address->blob, 0),
+           sizeof(uint32_t));
+    *ifidx = ntohl(netbyteorder);
+    return true;
+  }
+  return false;
+}
+
+PARCBuffer *addressGetLinkAddress(const Address *address) {
+  addressAssertValid(address);
+  if (address->addressType == ADDR_LINK) {
+    return address->blob;
+  }
+  return NULL;
+}
+
+static PARCBufferComposer *_Inet_BuildString(const Address *address,
+                                             PARCBufferComposer *composer) {
+  addressAssertValid(address);
+
+  struct sockaddr_in *saddr =
+      (struct sockaddr_in *)parcBuffer_Overlay(address->blob, 0);
+  return parcNetwork_SockInet4Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *_Inet6_BuildString(const Address *address,
+                                              PARCBufferComposer *composer) {
+  addressAssertValid(address);
+
+  struct sockaddr_in6 *saddr =
+      (struct sockaddr_in6 *)parcBuffer_Overlay(address->blob, 0);
+  return parcNetwork_SockInet6Address_BuildString(saddr, composer);
+}
+
+static PARCBufferComposer *_Link_BuildString(const Address *address,
+                                             PARCBufferComposer *composer) {
+  addressAssertValid(address);
+
+  const unsigned char *addr = parcBuffer_Overlay(address->blob, 0);
+
+  size_t length = parcBuffer_Remaining(address->blob);
+
+  return parcNetwork_LinkAddress_BuildString(addr, length, composer);
+}
+
+static ssize_t _UnixToString(char *output, size_t remaining_size,
+                             const PARCBuffer *addr) {
+  parcAssertNotNull(output, "parameter output must be non-null");
+  parcBuffer_AssertValid(addr);
+
+  parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(struct sockaddr_un),
+                 "Address corrupted. Expected %zu actual %zu",
+                 sizeof(struct sockaddr_un), parcBuffer_Remaining(addr));
+
+  // sockaddr length for the path, 16 for the ascii stuff, 3 for the length
+  // number
+  struct sockaddr_un *saddr =
+      (struct sockaddr_un *)parcBuffer_Overlay((PARCBuffer *)addr, 0);
+  size_t min_remaining = strlen(saddr->sun_path) + 16 + 3;
+  parcAssertTrue(remaining_size >= min_remaining,
+                 "Remaining size too small, need at least %zu", min_remaining);
+
+  ssize_t output_length = sprintf(output, "{ .path=%s, .len=%zu }",
+                                  saddr->sun_path, strlen(saddr->sun_path));
+  return output_length;
+}
+
+static ssize_t _IfaceToString(char *output, size_t remaining_size,
+                              const PARCBuffer *addr) {
+  parcAssertNotNull(output, "parameter output must be non-null");
+  parcBuffer_AssertValid(addr);
+
+  parcAssertTrue(parcBuffer_Remaining(addr) == sizeof(uint32_t),
+                 "Address corrupted. Expected %zu actual %zu", sizeof(uint32_t),
+                 parcBuffer_Remaining(addr));
+
+  uint32_t *ifidx = (uint32_t *)parcBuffer_Overlay((PARCBuffer *)addr, 0);
+
+  ssize_t output_length = sprintf(output, "{ .ifidx=%u }", ntohl(*ifidx));
+
+  return output_length;
+}
+
+PARCBufferComposer *addressBuildString(const Address *address,
+                                       PARCBufferComposer *composer) {
+  if (address != NULL) {
+    char *str = addressToString(address);
+    parcBufferComposer_PutString(composer, str);
+    parcMemory_Deallocate((void **)&str);
+  }
+  return composer;
+}
+
+char *addressToString(const Address *address) {
+  addressAssertValid(address);
+
+  char addrstr[256];
+
+  switch (address->addressType) {
+    case ADDR_INET: {
+      PARCBufferComposer *composer = parcBufferComposer_Create();
+      PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+          _Inet_BuildString(address, composer));
+      char *result = parcBuffer_ToString(tempBuffer);
+      parcBuffer_Release(&tempBuffer);
+      parcBufferComposer_Release(&composer);
+      return result;
+    } break;
+
+    case ADDR_INET6: {
+      PARCBufferComposer *composer = parcBufferComposer_Create();
+
+      PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+          _Inet6_BuildString(address, composer));
+      char *result = parcBuffer_ToString(tempBuffer);
+      parcBuffer_Release(&tempBuffer);
+
+      parcBufferComposer_Release(&composer);
+      return result;
+    } break;
+
+    case ADDR_LINK:
+      _UnixToString(addrstr, 256, address->blob);
+      break;
+
+    case ADDR_IFACE: {
+      PARCBufferComposer *composer = parcBufferComposer_Create();
+
+      PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+          _Link_BuildString(address, composer));
+      char *result = parcBuffer_ToString(tempBuffer);
+      parcBuffer_Release(&tempBuffer);
+
+      parcBufferComposer_Release(&composer);
+      return result;
+    } break;
+
+    case ADDR_UNIX:
+      _IfaceToString(addrstr, 256, address->blob);
+      break;
+
+    default:
+      sprintf(addrstr, "UNKNOWN type = %d", address->addressType);
+      break;
+  }
+
+  ssize_t alloc_size = 1024;
+  char *output = parcMemory_Allocate(alloc_size);
+  parcAssertNotNull(output, "parcMemory_Allocate(%zu) returned NULL",
+                    alloc_size);
+  ssize_t output_length =
+      snprintf(output, alloc_size, "{ .type=%s, .data=%s }",
+               addressTypeToString(address->addressType), addrstr);
+
+  parcAssertTrue(output_length < alloc_size,
+                 "allocated size too small, needed %zd", output_length);
+  parcAssertFalse(output_length < 0, "snprintf error: (%d) %s", errno,
+                  strerror(errno));
+
+  return output;
+}
+
+PARCHashCode addressHashCode(const Address *address) {
+  addressAssertValid(address);
+
+  PARCHashCode hash = parcBuffer_HashCode(address->blob);
+  hash = parcHashCode_HashImpl((uint8_t *)&address->addressType,
+                               sizeof(address->addressType), hash);
+
+  return hash;
+}
diff --git a/hicn-light/src/utils/address.h b/hicn-light/src/utils/address.h
new file mode 100755 (executable)
index 0000000..a98d150
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief Represents an endpoint address.
+ *
+ * Represents an endpoint address.  May be INET, INET6, or a multi-byte LINK,
+ * or an Interface Index.
+ *
+ * INET and INET6 must contain the .sa_addr member, and other members as needed
+ * by the use of the address.
+ *
+ * The Interface Index address is essentially a pointer to a device.
+ *
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+#ifndef address_h
+#define address_h
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <sys/un.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <src/utils/commands.h>
+
+/**
+ * Return a string representation of the given `address_type`
+ *
+ * @param [in] type A valid address_type value.
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a static string representation of the
+ * `address_type`.
+ *
+ * Example:
+ * @code
+ * {
+ *     const char *typeAsString = addressTypeToString(commandAddrType_INET);
+ * }
+ * @endcode
+ *
+ * @see addressStringToType
+ */
+const char *addressTypeToString(address_type type);
+
+/**
+ * Return a `address_type` from the given nul-terminated C string.
+ *
+ * @param [in] typeAsString A nul-terminated, C string representation of a
+ * `address_type`.
+ *
+ * @return A address_type
+ *
+ * Example:
+ * @code
+ * {
+ *     address_type type = addressTypeToString("INET");
+ * }
+ * @endcode
+ *
+ * @see addressTypeToString
+ */
+address_type addressStringToType(const char *typeAsString);
+
+struct address;
+typedef struct address Address;
+
+/**
+ * Create a new `Address` instance from an IPv4 IP address, the port is
+ * optional.
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created
+ * instance must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] addr_in The `sockaddr_in` representing the IPv4 IP address with
+ * which to initialize the new `Address` instance.
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}().
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *dest = addressCreateFromInet(
+ *                                                  &(struct sockaddr_in) {
+ *                                                      .sa_addr =
+ * inet_addr("foo.bar.com"), .sa_port = htons(9695) } ); addressDestroy(&dest);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInet(struct sockaddr_in *addr_in);
+
+/**
+ * Create a new `Address` instance from an IPv6 IP address, the port is
+ * optional.
+ *
+ *
+ * The sockaddr_in should be filled in network byte order. The newly created
+ * instance must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] addr_in6 A `sockaddr_in6` from which to initialize a new instance
+ * of Address
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ *     struct sockaddr_in6 addr_in6;
+ *     memset(&addr_in6, 0, sizeof(struct sockaddr_in6));
+ *
+ *     inet_pton(AF_INET6, "2001:720:1500:1::a100", &(addr_in6.sin6_addr));
+ *     addr_in6.sin6_family = AF_INET6;
+ *     addr_in6.sin6_port = 0x0A0B;
+ *     addr_in6.sin6_flowinfo = 0x01020304;
+ *
+ *     Address *address = addressCreateFromInet6(&addr_in6);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInet6(struct sockaddr_in6 *addr_in6);
+
+/**
+ * Create a new `Address` instance, initialized from a Link address.
+ *
+ * User must know the link address format (i.e. token ring vs ethernet) and have
+ * the address in a byte array. The array is encoded in left-to-right order. The
+ * newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] linkaddr A byte array containing the link address
+ * @param [in] length The length of the link address byte array
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ *     uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ *     Address *address = addressCreateFromLink(mac, sizeof(mac));
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromLink(const uint8_t *linkaddr, size_t length);
+
+/**
+ * Create a new `Address` instance from a network interface index.
+ *
+ * The interfaceIndex should be in host byte order. The newly created instance
+ * must eventually be destroyed by calling {@link addressDestroy}().
+ *
+ * @param [in] interfaceIndex The index of the interface to encode
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(2);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromInterface(uint32_t interfaceIndex);
+
+/**
+ * Create a new Address instance from a PF_UNIX address domain.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] addr_un The `struct sockaddr_un` specifying the local PF_UNIX
+ * socket address
+ * @return A new instance of `Address` that must eventually be destroyed by
+ * calling {@link addressDestroy}()
+ *
+ * Example:
+ * @code
+ * {
+ *     struct sockaddr_un addr_unix;
+ *     memset(&addr_unix, 0, sizeof(struct sockaddr_un));
+ *     char path[] = "/Hello/Cruel/World";
+ *     strcpy(addr_un.sun_path, path);
+ *     addr_un.sun_family = AF_UNIX;
+ *
+ *     Address *address = addressCreateFromUnix(&addr_un);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCreateFromUnix(struct sockaddr_un *addr_un);
+
+/**
+ * Create a deep copy of an instance of a `Address`. A completely new,
+ * indedependent instance is created.
+ *
+ * The newly created instance must eventually be destroyed by calling {@link
+ * addressDestroy}().
+ *
+ * @param [in] original A pointer to a `Address` instance to be copied.
+ * @return A new instance of a Address, deep copied from the `original`
+ * instance.
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(2);
+ *
+ *     Address *copy = addressCopy(address);
+ *
+ *     addressDestroy(&address);
+ *     addressDestroy(&copy);
+ * }
+ * @endcode
+ * @see addressDestroy
+ */
+Address *addressCopy(const Address *original);
+
+/**
+ * Deallocate an instance of a Address.
+ *
+ * The Address instance is deallocated, and any referenced data is also
+ * deallocated. The referenced pointer is set to NULL upon return.
+ *
+ * @param [in] addressPtr A pointer to a pointer to an instance of Address.
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(2);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ */
+void addressDestroy(Address **addressPtr);
+
+/**
+ * Determine if two Address instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `Address` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x, `addressEquals(x, x)`
+ *      must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `addressEquals(x, y)` must return true if and only if
+ *        `addressEquals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `addressEquals(x, y)` returns true and
+ *        `addressEquals(y, z)` returns true,
+ *        then  `addressEquals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `addressEquals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `addressEquals(x, NULL)` must
+ *      return false.
+ *
+ * If one address specifies more information than other,
+ * e.g. a is INET with a port and b is not, they are not equal.
+ *
+ * `a` and `b` may be NULL, and NULL == NULL.
+ *
+ * @param a A pointer to a Address instance
+ * @param b A pointer to a Address instance
+ * @return true if the two instances are equal
+ * @return false if the two instances are not equal
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(2);
+ *     Address *copy = addressCopy(address);
+ *
+ *     if (addressEquals(address, copy)) {
+ *         // true
+ *     }  else {
+ *         // false
+ *     }
+ *
+ *     addressDestroy(&address);
+ *     addressDestroy(&copy);
+ * }
+ * @endcode
+ */
+bool addressEquals(const Address *a, const Address *b);
+
+/**
+ * Return the {@link address_type} from a specified Address.
+ *
+ * @param [in] A pointer to a Address instance
+ *
+ * @return the {@link address_type} of the specified Address instance
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(2);
+ *
+ *     address_type type = addressGetType(address);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ *
+ * @see address_type
+ */
+address_type addressGetType(const Address *address);
+
+/**
+ * Fills in the output parameter with an INET address.
+ *
+ * @param addr_in must be non-NULL
+ * @return true if INET address and output filled in, false otherwise.
+ *
+ */
+bool addressGetInet(const Address *address, struct sockaddr_in *addr_in);
+
+/**
+ * Retrieve the INET6 address associated with a `Address` instance.
+ *
+ * If the specified Address instance is of type {@link commandAddrType_INET6},
+ * then populate the supplied `struct sockaddr_in6` from the Address and return
+ * true. If the Address is not of type `commandAddrType_INET6`, this function
+ * returns false.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_INET6}.
+ * @param [in] addr_in6 A pointer to a `struct sockaddr_in6`. Must be non-NULL.
+ * @return true If the Address instance is of type `commandAddrType_INET6` and
+ * `addr_in6` was filled in
+ * @return false If the Address instance was not of type `commandAddrType_INET6`
+ * or `addr_in6` could not be filled in.
+ *
+ * @see addressGetType
+ */
+bool addressGetInet6(const Address *address, struct sockaddr_in6 *addr_in6);
+
+/**
+ * Retrieve the interface index associated with a `Address` instance.
+ *
+ * If the specified `Address` instance is of type {@link commandAddrType_IFACE},
+ * then populate the supplied `uint32_t` from the Address and return true. If
+ * the `Address` is not of type `commandAddrType_INET6`, this function returns
+ * false.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_IFACE}.
+ * @param [in] interfaceIndex A pointer to a `uint32_t` to fill in. Must be
+ * non-NULL.
+ * @return true If the Address instance is of type `commandAddrType_IFACE` and
+ * `interfaceIndex` was filled in.
+ * @return false If the Address instance was not of type `commandAddrType_IFACE`
+ * or `interfaceIndex` could not be filled in.
+ *
+ * @see addressGetType
+ */
+bool addressGetInterfaceIndex(const Address *address, uint32_t *interfaceIndex);
+
+/**
+ * Retrieve the link address associated with a `Address` instance.
+ *
+ * If the specified `Address` instance is of type {@link commandAddrType_LINK},
+ * then return a pointer to the {@link PARCBuffer} containing the link address.
+ * If the `Address` is not of type {@link commandAddrType_LINK}, then return
+ * NULL. The returned PARCBuffer pointer points to memory managed by the Address
+ * instance, and does not need to be destroyed or released on its own.
+ *
+ * @param [in] address A pointer to a `Address` instance of type {@link
+ * commandAddrType_LINK}.
+ * @return A pointer to the {@link PARCBuffer} containing the link address.
+ *
+ * Example:
+ * @code
+ * {
+ *     uint8_t mac[] = { 0x14, 0x10, 0x9f, 0xd7, 0x0b, 0x89 };
+ *     Address *address = addressCreateFromLink(mac, sizeof(mac));
+ *
+ *     PARCBuffer *macBuffer = addressGetLinkAddress(address);
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see addressGetType
+ */
+PARCBuffer *addressGetLinkAddress(const Address *address);
+
+/**
+ * Append the string representation of a `Address` to a specified
+ * `PARCBufferComposer`.
+ *
+ * @param [in] address A pointer to a `Address` instance.
+ * @param [in] composer A pointer to a `PARCBufferComposer` instance to which to
+ * append the string.
+ *
+ * @return The `PARCBufferComposer` instance that was passed in.
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(1);
+ *     PARCBufferComposer *composer = addressBuildString(address,
+ * parcBufferComposer_Create()); parcBufferComposer_Release(&composer);
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ *
+ * @see PARCBufferComposer
+ */
+PARCBufferComposer *addressBuildString(const Address *address,
+                                       PARCBufferComposer *composer);
+
+/**
+ * Produce a nil-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] interest A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, nul-terminated C string that must
+ * be deallocated via {@link parcMemory_Deallocate}().
+ *
+ * Example:
+ * @code
+ * {
+ *     Address *address = addressCreateFromInterface(1);
+ *
+ *     char *string = addressToString(address);
+ *
+ *     if (string != NULL) {
+ *         printf("Address looks like: %s\n", string);
+ *         parcMemory_Deallocate(string);
+ *     } else {
+ *         printf("Cannot allocate memory\n");
+ *     }
+ *
+ *     addressDestroy(&address);
+ * }
+ * @endcode
+ * @see parcMemory_Deallocate
+ * @see addressBuildString
+ */
+char *addressToString(const Address *address);
+
+/**
+ * Return a non-cryptographic hash code consistent with Equals
+ *
+ * If commandAddrA == commandAddrB, then addressHashCode(commandAddrA) ==
+ * addressHashCode(commandAddrB)
+ *
+ * @param [in] address A pointer to a Address instance.
+ * @return A 32-bit hashcode for the specified Address instance.
+ *
+ * Example:
+ * @code
+ *     Address *address = addressCreateFromInterface(1);
+ *
+ *     uint32_t hashCode = addressHashCode(address);
+ *
+ *     addressDestroy(&address);
+ * @endcode
+ */
+PARCHashCode addressHashCode(const Address *address);
+#endif  // address_h
diff --git a/hicn-light/src/utils/addressList.c b/hicn-light/src/utils/addressList.c
new file mode 100755 (executable)
index 0000000..4f51a11
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <src/utils/addressList.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Buffer.h>
+#include <parc/algol/parc_Memory.h>
+
+struct address_list {
+  PARCArrayList *listOfAddress;
+};
+
+static void _addressListFreeAddress(void **addressVoidPtr) {
+  Address **addressPtr = (Address **)addressVoidPtr;
+  addressDestroy(addressPtr);
+}
+
+AddressList *addressListCreate() {
+  AddressList *list = parcMemory_AllocateAndClear(sizeof(AddressList));
+  parcAssertNotNull(list, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(AddressList));
+  list->listOfAddress = parcArrayList_Create(_addressListFreeAddress);
+  parcAssertNotNull(list->listOfAddress, "Got null from parcArrayList_Create");
+
+  return list;
+}
+
+void addressListDestroy(AddressList **addressListPtr) {
+  parcAssertNotNull(addressListPtr,
+                    "Parameter must be non-null double pointer");
+  parcAssertNotNull(*addressListPtr,
+                    "Parameter must dereference to non-null pointer");
+  AddressList *list = *addressListPtr;
+
+  parcArrayList_Destroy(&list->listOfAddress);
+  parcMemory_Deallocate((void **)&list);
+  *addressListPtr = NULL;
+}
+
+AddressList *addressListAppend(AddressList *list, Address *address) {
+  parcAssertNotNull(list, "Parameter list must be non-null");
+  parcAssertNotNull(address, "Parameter address must be non-null");
+
+  parcArrayList_Add(list->listOfAddress, (PARCObject *)address);
+  return list;
+}
+
+AddressList *addressListCopy(const AddressList *original) {
+  parcAssertNotNull(original, "Parameter must be non-null");
+
+  AddressList *copy = addressListCreate();
+  for (int i = 0; i < parcArrayList_Size(original->listOfAddress); i++) {
+    Address *address = (Address *)parcArrayList_Get(original->listOfAddress, i);
+    parcArrayList_Add(copy->listOfAddress, (PARCObject *)addressCopy(address));
+  }
+
+  return copy;
+}
+
+bool addressListEquals(const AddressList *a, const AddressList *b) {
+  parcAssertNotNull(a, "Parameter a must be non-null");
+  parcAssertNotNull(b, "Parameter b must be non-null");
+
+  if (a == b) {
+    return true;
+  }
+
+  if (parcArrayList_Size(a->listOfAddress) !=
+      parcArrayList_Size(b->listOfAddress)) {
+    return false;
+  }
+
+  for (size_t i = 0; i < parcArrayList_Size(a->listOfAddress); i++) {
+    const Address *addr_a = (Address *)parcArrayList_Get(a->listOfAddress, i);
+    const Address *addr_b = (Address *)parcArrayList_Get(b->listOfAddress, i);
+    if (!addressEquals(addr_a, addr_b)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+size_t addressListLength(const AddressList *list) {
+  parcAssertNotNull(list, "Parameter must be non-null");
+  return parcArrayList_Size(list->listOfAddress);
+}
+
+const Address *addressListGetItem(const AddressList *list, size_t item) {
+  parcAssertNotNull(list, "Parameter must be non-null");
+  parcAssertTrue(item < addressListLength(list),
+                 "Asked for item %zu beyond end of list %zu", item,
+                 addressListLength(list));
+
+  return (Address *)parcArrayList_Get(list->listOfAddress, item);
+}
+
+char *addressListToString(const AddressList *list) {
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+
+  for (size_t i = 0; i < addressListLength(list); i++) {
+    char *addressString = addressToString(addressListGetItem(list, i));
+    parcBufferComposer_PutString(composer, addressString);
+    if (i < (addressListLength(list) - 1)) {
+      parcBufferComposer_PutString(composer, " ");
+    }
+    parcMemory_Deallocate((void **)&addressString);
+  }
+
+  PARCBuffer *buffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(buffer);
+  parcBuffer_Release(&buffer);
+  parcBufferComposer_Release(&composer);
+
+  return result;
+}
diff --git a/hicn-light/src/utils/addressList.h b/hicn-light/src/utils/addressList.h
new file mode 100755 (executable)
index 0000000..bcb312c
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief A list of Address instances.
+ *
+ * An AddressList is a list of addresses.
+ * It wraps a PARCLinkedList for type saftey with Address.
+ *
+ */
+#ifndef address_list_h
+#define address_list_h
+
+#include <src/utils/address.h>
+
+struct address_list;
+/**
+ * @typedef AddressList
+ * @abstract A list of Address instance pointers.
+ */
+typedef struct address_list AddressList;
+
+/**
+ * Create an instance of {@link AddressList}
+ *
+ * @return NULL An error occurred
+ * @return non-NULL A pointer to a valid AddressList instance.
+ *
+ * Example:
+ * @code
+ * {
+ *     AddressList *list = addressListCreate();
+ *
+ * }
+ * @endcode
+ *
+ * @see addressListDestroy
+ */
+AddressList *addressListCreate(void);
+
+/**
+ * Dellocate and destroy a AddressList instance.
+ *
+ * @param [in] addressListPtr A pointer to a pointer to a valid {@link
+ * AddressList}.
+ *
+ *
+ * Example:
+ * @code
+ * {
+ *     AddressList *list = addressListCreate(void);
+ *     addressListDestroy(&list);
+ * }
+ * @endcode
+ *
+ * @see addressListCreate
+ */
+void addressListDestroy(AddressList **addressListPtr);
+
+/**
+ * Appends the address, taking ownership of the memory
+ *
+ * @param list A pointer to a AddressList.
+ * @param address must be non-null
+ * @return The input list
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+AddressList *addressListAppend(AddressList *list, Address *address);
+
+/**
+ * Creates a reference counted copy
+ *
+ * @param list A pointer to a valid {@link AddressList}.
+ *
+ * @return An allocated list, you must destroy it.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+AddressList *addressListCopy(const AddressList *list);
+
+/**
+ * Determine if two AddressList instances are equal.
+ *
+ * Two AddressList instances are equal if, and only if, they have the same
+ * length, with the same elements in the same order.
+ *
+ *
+ * The following equivalence relations on non-null `AddressList` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x,
+ * `AddressList_Equals(x, x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `AddressList_Equals(x, y)` must return true if and only if
+ *        `addressListEquals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `addressListEquals(x, y)` returns true and
+ *        `addressListEquals(y, z)` returns true,
+ *        then  `addressListEquals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `addressListEquals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `addressListEquals(x, NULL)` must
+ *      return false.
+ *
+ * @param a A pointer to a `AddressList` instance.
+ * @param b A pointer to a `AddressList` instance.
+ * @return true if the two `AddressList` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ *    AddressList *a = addressListCreate();
+ *    AddressList *b = addressListCreate();
+ *
+ *    if (addressListEquals(a, b)) {
+ *        // true
+ *    } else {
+ *        // false
+ *    }
+ * }
+ * @endcode
+ */
+bool addressListEquals(const AddressList *a, const AddressList *b);
+
+/**
+ * Get the number of items in the list
+ *
+ * @param list A pointer to a {@link AddressList}.
+ * @return The number of items in the list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t addressListLength(const AddressList *list);
+
+/**
+ * Returns a const reference to an item.
+ * Use addressCopy if needed.
+ *
+ * Do not free or modify the returned value.
+ * Use addressCopy if you   need a mutable instance.
+ *
+ * @param list A pointer to a AddressList.
+ * @param item A value less than the number of items in the given {@link
+ * AddressList}.
+ * @return Asserts if item off end of list.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const Address *addressListGetItem(const AddressList *list, size_t item);
+
+/**
+ * Get a nul-terminated, C-string representation of the given {@link
+ * AddressList}.
+ *
+ * @param list A pointer to a valid {@link AddressList} instance.
+ *
+ * @return An allocate string representation of the {@link AddressList} that
+ * must be freed via `parcMemory_Deallocate()`.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *addressListToString(const AddressList *list);
+#endif  // address_list_h
diff --git a/hicn-light/src/utils/commands.h b/hicn-light/src/utils/commands.h
new file mode 100755 (executable)
index 0000000..2f8ebcb
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * @file commands.h
+ * @brief All hicn-light commands: 14 in total.
+ *
+ * Header and payload in binary format.
+ */
+
+#ifndef commands_h
+#define commands_h
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+typedef struct in6_addr ipv6_addr_t;
+typedef uint32_t ipv4_addr_t;
+
+union commandAddr {
+  ipv4_addr_t ipv4;
+  ipv6_addr_t ipv6;
+};
+
+typedef enum {
+  REQUEST_LIGHT = 100,
+  RESPONSE_LIGHT,
+  ACK_LIGHT,
+  NACK_LIGHT,
+  LAST_MSG_TYPE_VALUE
+} message_type;
+
+typedef enum {
+  ADD_LISTENER,
+  ADD_CONNECTION,
+  LIST_CONNECTIONS,
+  ADD_ROUTE,
+  LIST_ROUTES,
+  REMOVE_CONNECTION,
+  REMOVE_ROUTE,
+  CACHE_STORE,
+  CACHE_SERVE,
+  CACHE_CLEAR,
+  SET_STRATEGY,
+  SET_WLDR,
+  ADD_PUNTING,
+  LIST_LISTENERS,
+  MAPME_ENABLE,
+  MAPME_DISCOVERY,
+  MAPME_TIMESCALE,
+  MAPME_RETX,
+  LAST_COMMAND_VALUE
+} command_id;
+
+typedef enum {
+  ADDR_INET = 1,
+  ADDR_INET6,
+  ADDR_LINK,
+  ADDR_IFACE,
+  ADDR_UNIX /* PF_UNIX */
+} address_type;
+
+typedef enum {
+  UDP_CONN,
+  TCP_CONN,
+  GRE_CONN,  // not implemented
+  HICN_CONN
+} connection_type;
+
+typedef enum { ACTIVATE_ON, ACTIVATE_OFF } activate_type;
+
+//==========    HEADER    ==========
+
+typedef struct {
+  uint8_t messageType;
+  uint8_t commandID;
+  uint16_t length;  // tells the number of structures in the payload
+  uint32_t seqNum;
+} header_control_message;
+// for the moment has to be at least 8 bytes
+
+// SIZE=8
+
+//==========  [00]  ADD LISTENER    ==========
+
+typedef enum { ETHER_MODE, IP_MODE, HICN_MODE } listener_mode;
+
+typedef struct {
+  char symbolic[16];
+  // char interfaceName[16];
+  union commandAddr address;
+  uint16_t port;
+  // uint16_t etherType;
+  uint8_t addressType;
+  uint8_t listenerMode;
+  uint8_t connectionType;
+} add_listener_command;
+
+// SIZE=40
+
+//==========  [01]  ADD CONNECTION    ==========
+
+typedef struct {
+  char symbolic[16];
+  union commandAddr remoteIp;
+  union commandAddr localIp;
+  uint16_t remotePort;
+  uint16_t localPort;
+  uint8_t ipType;
+  uint8_t connectionType;
+} add_connection_command;
+
+// SIZE=56
+
+//==========  [02]  LIST CONNECTIONS    ==========
+
+typedef enum {
+  CONN_GRE,
+  CONN_TCP,
+  CONN_UDP,
+  CONN_MULTICAST,
+  CONN_L2,
+  CONN_HICN
+} list_connections_type;
+
+typedef enum {
+  IFACE_UP = 0,
+  IFACE_DOWN = 1,
+  IFACE_UNKNOWN = 2  // not used actually
+} connection_state;
+
+typedef struct {
+  add_connection_command connectionData;
+  uint32_t connid;
+  uint8_t state;
+} list_connections_command;
+
+// SIZE=64
+
+//==========  [03]  ADD ROUTE    ==========
+
+typedef struct {
+  char symbolicOrConnid[16];
+  union commandAddr address;
+  uint16_t cost;
+  uint8_t addressType;
+  uint8_t len;
+} add_route_command;
+
+// SIZE=36
+
+//==========  [04]  LIST ROUTE    ==========
+
+typedef struct {
+  union commandAddr address;
+  uint32_t connid;
+  uint16_t cost;
+  uint8_t addressType;
+  uint8_t len;
+} list_routes_command;
+
+// SIZE=24
+
+//==========  [05]  REMOVE CONNECTION    ==========
+
+typedef struct {
+  char symbolicOrConnid[16];
+} remove_connection_command;
+
+// SIZE=16
+
+//==========  [06]  REMOVE ROUTE    ==========
+
+typedef struct {
+  char symbolicOrConnid[16];
+  union commandAddr address;
+  uint8_t addressType;
+  uint8_t len;
+} remove_route_command;
+
+// SIZE=36
+
+//==========  [07]  CACHE STORE    ==========
+
+typedef struct {
+  uint8_t activate;
+} cache_store_command;
+
+// SIZE=1
+
+//==========  [08]  CACHE SERVE    ==========
+
+typedef struct {
+  uint8_t activate;
+} cache_serve_command;
+
+// SIZE=1
+
+//==========  [09]  SET STRATEGY    ==========
+
+typedef enum {
+  SET_STRATEGY_LOADBALANCER,
+  SET_STRATEGY_RANDOM,
+  SET_STRATEGY_RANDOM_PER_DASH_SEGMENT,
+  SET_STRATEGY_LOADBALANCER_WITH_DELAY,
+  SET_STRATEGY_LOADBALANCER_BY_RATE,
+  SET_STRATEGY_LOADBALANCER_BEST_ROUTE,
+  LAST_STRATEGY_VALUE
+} strategy_type;
+
+typedef struct {
+  union commandAddr address;
+  uint8_t strategyType;
+  uint8_t addressType;
+  uint8_t len;
+} set_strategy_command;
+
+// SIZE=20
+
+//==========  [11]  SET WLDR    ==========
+
+typedef struct {
+  char symbolicOrConnid[16];
+  uint8_t activate;
+} set_wldr_command;
+
+// SIZE=17
+
+//==========  [12]  ADD PUNTING    ==========
+
+typedef struct {
+  char symbolicOrConnid[16];
+  union commandAddr address;
+  uint8_t addressType;
+  uint8_t len;
+} add_punting_command;
+
+// SIZE=36
+
+//==========  [13]  LIST LISTENER    ==========
+
+typedef struct {
+  union commandAddr address;
+  uint32_t connid;
+  uint16_t port;
+  uint8_t addressType;
+  uint8_t encapType;
+} list_listeners_command;
+
+// SIZE=24
+
+//==========  [14]  MAPME    ==========
+
+//  (enable/discovery/timescale/retx)
+
+typedef struct {
+  uint8_t activate;
+} mapme_activator_command;
+
+// SIZE=1
+
+typedef struct {
+  uint32_t timePeriod;
+} mapme_timing_command;
+
+// SIZE=1
+
+#endif
diff --git a/hicn-light/src/utils/interface.c b/hicn-light/src/utils/interface.c
new file mode 100755 (executable)
index 0000000..ab7a88f
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <src/utils/addressList.h>
+#include <src/utils/interface.h>
+
+#include <parc/assert/parc_Assert.h>
+#include <src/utils/commands.h>
+
+struct interface {
+  char *name;
+  unsigned interfaceIndex;
+  bool loopback;
+  bool supportMulticast;
+  unsigned mtu;
+
+  AddressList *addressList;
+};
+
+char *interfaceToString(const Interface *interface) {
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+
+  parcBufferComposer_Format(
+      composer, "%3u %10s %1s%1s %8u ", interface->interfaceIndex,
+      interface->name, interface->loopback ? "l" : " ",
+      interface->supportMulticast ? "m" : " ", interface->mtu);
+
+  for (size_t i = 0; i < addressListLength(interface->addressList); i++) {
+    addressBuildString(addressListGetItem(interface->addressList, i), composer);
+    if (i < (addressListLength(interface->addressList) - 1)) {
+      parcBufferComposer_PutStrings(composer, "\n", NULL);
+    }
+  }
+
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(composer);
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  parcBufferComposer_Release(&composer);
+  return result;
+}
+
+Interface *interfaceCreate(const char *name, unsigned interfaceIndex,
+                           bool loopback, bool supportMulticast, unsigned mtu) {
+  Interface *iface = parcMemory_AllocateAndClear(sizeof(Interface));
+
+  parcAssertNotNull(iface, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(Interface));
+  iface->name = parcMemory_StringDuplicate(name, 64);
+  iface->interfaceIndex = interfaceIndex;
+  iface->loopback = loopback;
+  iface->supportMulticast = supportMulticast;
+  iface->mtu = mtu;
+  iface->addressList = addressListCreate();
+
+  return iface;
+}
+
+void interfaceDestroy(Interface **interfacePtr) {
+  parcAssertNotNull(interfacePtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*interfacePtr,
+                    "Parameter must dereference to non-null pointer");
+
+  Interface *iface = *interfacePtr;
+  parcMemory_Deallocate((void **)&iface->name);
+  addressListDestroy(&iface->addressList);
+  parcMemory_Deallocate((void **)&iface);
+  interfacePtr = NULL;
+}
+
+void interfaceAddAddress(Interface *iface, Address *address) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+  size_t length = addressListLength(iface->addressList);
+  for (size_t i = 0; i < length; i++) {
+    const Address *a = addressListGetItem(iface->addressList, i);
+    if (addressEquals(a, address)) {
+      return;
+    }
+  }
+
+  addressListAppend(iface->addressList, address);
+}
+
+const AddressList *interfaceGetAddresses(const Interface *iface) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+  return iface->addressList;
+}
+
+unsigned interfaceGetInterfaceIndex(const Interface *iface) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+  return iface->interfaceIndex;
+}
+
+bool interfaceNameEquals(const Interface *iface, const char *name) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+  if (strcasecmp(iface->name, name) == 0) {
+    return true;
+  }
+  return false;
+}
+
+bool interfaceEquals(const Interface *a, const Interface *b) {
+  if (a == NULL && b == NULL) {
+    return true;
+  }
+
+  if (a == NULL || b == NULL) {
+    return false;
+  }
+
+  if (a->interfaceIndex == b->interfaceIndex) {
+    if (a->loopback == b->loopback) {
+      if (a->supportMulticast == b->supportMulticast) {
+        if (a->mtu == b->mtu) {
+          if (strcasecmp(a->name, b->name) == 0) {
+            if (addressListEquals(a->addressList, b->addressList)) {
+              return true;
+            }
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
+// static const char light_Iface[] = "Interface";
+// static const char light_IfName[] = "Name";
+// static const char light_IFIDX[] = "Index";
+// static const char light_IsLoopback[] = "Loopback";
+// static const char light_Multicast[] = "Multicast";
+// static const char light_MTU[] = "MTU";
+
+// static const char light_True[] = "true";
+// static const char light_False[] = "false";
+// static const char light_Addrs[] = "Addrs";
+
+const char *interfaceGetName(const Interface *iface) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+  return iface->name;
+}
+
+unsigned interfaceGetMTU(const Interface *iface) {
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+  return iface->mtu;
+}
diff --git a/hicn-light/src/utils/interface.h b/hicn-light/src/utils/interface.h
new file mode 100755 (executable)
index 0000000..0810ec0
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef interface_h
+#define interface_h
+
+#include <src/utils/address.h>
+#include <src/utils/addressList.h>
+
+struct interface;
+typedef struct interface Interface;
+
+/**
+ * Creates a representation of an interface
+ *
+ *   The name is copied.  Creates a representation of a system interface.
+ *
+ * @param <#param1#>
+ * @return An allocated object, you must call <code>interfaceDestroy()</code>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceCreate(const char *name, unsigned interfaceIndex,
+                           bool loopback, bool supportMulticast, unsigned mtu);
+
+void interfaceDestroy(Interface **interfacePtr);
+
+/**
+ * Adds an address to an interface
+ *
+ *   Does not allow duplicates, if already exists is not added again
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void interfaceAddAddress(Interface *iface, Address *address);
+
+/**
+ * Retrieves a list of interface addresses
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return Will not be NULL, but may be empty
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const AddressList *interfaceGetAddresses(const Interface *iface);
+
+/**
+ * The interface index
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+unsigned interfaceGetInterfaceIndex(const Interface *iface);
+
+/**
+ * Returns the interface name, e.g. "eth0"
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated Interface
+ *
+ * @return non-null The interface Name as a C-string
+ * @return null An error
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const char *interfaceGetName(const Interface *iface);
+
+/**
+ * Returns the Maximum Transmission Unit (MTU) of the interface
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in] iface An allocated Interface
+ *
+ * @return number The MTU as reported by the kernel
+ *
+ * Example:
+ * @code
+ * {
+ *     <#example#>
+ * }
+ * @endcode
+ */
+unsigned interfaceGetMTU(const Interface *iface);
+
+/**
+ * Determine if two InterfaceName instances are equal.
+ *
+ *
+ * The following equivalence relations on non-null `InterfaceName` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x,
+ * `InterfaceName_Equals(x, x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `InterfaceName_Equals(x, y)` must return true if and only if
+ *        `InterfaceName_Equals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `InterfaceName_Equals(x, y)` returns true and
+ *        `InterfaceName_Equals(y, z)` returns true,
+ *        then  `InterfaceName_Equals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `InterfaceName_Equals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `InterfaceName_Equals(x, NULL)` must
+ *      return false.
+ *
+ * @param a A pointer to a `InterfaceName` instance.
+ * @param b A pointer to a `InterfaceName` instance.
+ * @return true if the two `InterfaceName` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ *    InterfaceName *a = InterfaceName_Create();
+ *    InterfaceName *b = InterfaceName_Create();
+ *
+ *    if (InterfaceName_Equals(a, b)) {
+ *        // true
+ *    } else {
+ *        // false
+ *    }
+ * }
+ * @endcode
+ */
+bool interfaceNameEquals(const Interface *iface, const char *name);
+
+/**
+ * Two Interfaces are idential
+ *
+ *   All properties must be the same.  The order of addresses matters, and
+ *   they must have been added to the address list in the same order.
+ *
+ *   The interface name match is case in-sensitive.
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool interfaceEquals(const Interface *a, const Interface *b);
+
+/**
+ * <#OneLineDescription#>
+ *
+ *   <#Discussion#>
+ *
+ * @param interface A Interface structure pointer.
+ * @return An allocate string representation of the Interface that must be freed
+ * via parcMemory_Deallocate().
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+char *interfaceToString(const Interface *interface);
+#endif  // interface_h
diff --git a/hicn-light/src/utils/interfaceSet.c b/hicn-light/src/utils/interfaceSet.c
new file mode 100755 (executable)
index 0000000..3f56ec1
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <src/utils/interfaceSet.h>
+
+#include <parc/algol/parc_ArrayList.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/assert/parc_Assert.h>
+
+struct interfaceSet {
+  PARCArrayList *listOfInterfaces;
+};
+
+static void _destroyInterface(void **ifaceVoidPtr) {
+  interfaceDestroy((Interface **)ifaceVoidPtr);
+}
+
+InterfaceSet *interfaceSetCreate(void) {
+  InterfaceSet *set = parcMemory_AllocateAndClear(sizeof(InterfaceSet));
+  parcAssertNotNull(set, "parcMemory_AllocateAndClear(%zu) returned NULL",
+                    sizeof(InterfaceSet));
+  set->listOfInterfaces = parcArrayList_Create(_destroyInterface);
+  return set;
+}
+
+void interfaceSetDestroy(InterfaceSet **setPtr) {
+  parcAssertNotNull(setPtr, "Parameter must be non-null double pointer");
+  parcAssertNotNull(*setPtr, "Parameter must dereference to non-null pointer");
+
+  InterfaceSet *set = *setPtr;
+  parcArrayList_Destroy(&set->listOfInterfaces);
+  parcMemory_Deallocate((void **)&set);
+  *setPtr = NULL;
+}
+
+bool interfaceSetAdd(InterfaceSet *set, Interface *iface) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  parcAssertNotNull(iface, "Parameter iface must be non-null");
+
+  unsigned ifaceIndex = interfaceGetInterfaceIndex(iface);
+  size_t length = parcArrayList_Size(set->listOfInterfaces);
+  for (size_t i = 0; i < length; i++) {
+    Interface *listEntry =
+        (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+    unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry);
+    if (entryInterfaceIndex == ifaceIndex) {
+      return false;
+    }
+  }
+
+  parcArrayList_Add(set->listOfInterfaces, (PARCObject *)iface);
+  return true;
+}
+
+size_t interfaceSetLength(const InterfaceSet *set) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  return parcArrayList_Size(set->listOfInterfaces);
+}
+
+Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set,
+                                         size_t ordinalIndex) {
+  parcAssertNotNull(set, "Parameter set must be non-null");
+  return (Interface *)parcArrayList_Get(set->listOfInterfaces, ordinalIndex);
+}
+
+Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set,
+                                           unsigned interfaceIndex) {
+  size_t length = parcArrayList_Size(set->listOfInterfaces);
+  for (size_t i = 0; i < length; i++) {
+    Interface *listEntry =
+        (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+    unsigned entryInterfaceIndex = interfaceGetInterfaceIndex(listEntry);
+    if (entryInterfaceIndex == interfaceIndex) {
+      return listEntry;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByName(InterfaceSet *set, const char *name) {
+  size_t length = parcArrayList_Size(set->listOfInterfaces);
+  for (size_t i = 0; i < length; i++) {
+    Interface *listEntry =
+        (Interface *)parcArrayList_Get(set->listOfInterfaces, i);
+    if (interfaceNameEquals(listEntry, name)) {
+      return listEntry;
+    }
+  }
+  return NULL;
+}
+
+bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b) {
+  if (a == NULL && b == NULL) {
+    return true;
+  }
+
+  if (a == NULL || b == NULL) {
+    return false;
+  }
+
+  size_t length_a = parcArrayList_Size(a->listOfInterfaces);
+  size_t length_b = parcArrayList_Size(b->listOfInterfaces);
+
+  if (length_a == length_b) {
+    for (size_t i = 0; i < length_a; i++) {
+      Interface *iface_a =
+          (Interface *)parcArrayList_Get(a->listOfInterfaces, i);
+
+      // the set is unique by interface id, so if it exists in set b, it
+      // exists there by interface id
+      Interface *iface_b = interfaceSetGetByInterfaceIndex(
+          b, interfaceGetInterfaceIndex(iface_a));
+      if (!interfaceEquals(iface_b, iface_b)) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
diff --git a/hicn-light/src/utils/interfaceSet.h b/hicn-light/src/utils/interfaceSet.h
new file mode 100755 (executable)
index 0000000..8eb8397
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef InterfaceSet_h
+#define InterfaceSet_h
+
+#include <src/utils/interface.h>
+
+struct interfaceSet;
+/**
+ *
+ * @see interfaceSetCreate
+ */
+typedef struct interfaceSet InterfaceSet;
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+InterfaceSet *interfaceSetCreate(void);
+
+/**
+ * <#One Line Description#>
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [<#in out in,out#>] <#name#> <#description#>
+ *
+ * @return <#value#> <#explanation#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see <#references#>
+ */
+void interfaceSetDestroy(InterfaceSet **setPtr);
+
+/**
+ * Adds interface to set, does not allow duplicates
+ *
+ *   Takes ownership of the iface memory if added
+ *
+ *   Duplicates are two entries with the same interface index
+ *
+ * @param <#param1#>
+ * @return true if added, false if not (likely a duplicate)
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+bool interfaceSetAdd(InterfaceSet *set, Interface *iface);
+
+/**
+ * The number of interfaces in the set
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return <#return#>
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+size_t interfaceSetLength(const InterfaceSet *set);
+
+/**
+ * Uses the ordinal index of the interface in the Set
+ *
+ *   Ranges from 0 .. <code>interfaceSetLength()-1</code>.
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByOrdinalIndex(InterfaceSet *set,
+                                         size_t ordinalIndex);
+
+/**
+ * Retreives by the assigned interface index
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByInterfaceIndex(const InterfaceSet *set,
+                                           unsigned interfaceIndex);
+
+/**
+ * Uses the system name (e.g. "en0")
+ *
+ *   <#Discussion#>
+ *
+ * @param <#param1#>
+ * @return NULL if not found
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+Interface *interfaceSetGetByName(InterfaceSet *set, const char *name);
+
+/**
+ * Determine if two InterfaceSet instances are equal.
+ *
+ * Two InterfaceSet instances are equal if, and only if, the sets contain the
+ * same elements
+ * - order independent.
+ * Each element is compared via <code>interfaceEquals()</code>
+ *
+ * The following equivalence relations on non-null `InterfaceSet` instances are
+ * maintained:
+ *
+ *  * It is reflexive: for any non-null reference value x,
+ * `InterfaceSet_Equals(x, x)` must return true.
+ *
+ *  * It is symmetric: for any non-null reference values x and y,
+ *    `InterfaceSet_Equals(x, y)` must return true if and only if
+ *        `interfaceSetEquals(y, x)` returns true.
+ *
+ *  * It is transitive: for any non-null reference values x, y, and z, if
+ *        `interfaceSetEquals(x, y)` returns true and
+ *        `interfaceSetEquals(y, z)` returns true,
+ *        then  `interfaceSetEquals(x, z)` must return true.
+ *
+ *  * It is consistent: for any non-null reference values x and y, multiple
+ *      invocations of `interfaceSetEquals(x, y)` consistently return true or
+ *      consistently return false.
+ *
+ *  * For any non-null reference value x, `interfaceSetEquals(x, NULL)` must
+ *      return false.
+ *
+ * @param a A pointer to a `InterfaceSet` instance.
+ * @param b A pointer to a `InterfaceSet` instance.
+ * @return true if the two `InterfaceSet` instances are equal.
+ *
+ * Example:
+ * @code
+ * {
+ *    InterfaceSet *a = interfaceSetCreate();
+ *    InterfaceSet *b = interfaceSetCreate();
+ *
+ *    if (interfaceSetEquals(a, b)) {
+ *        // true
+ *    } else {
+ *        // false
+ *    }
+ * }
+ * @endcode
+ */
+bool interfaceSetEquals(const InterfaceSet *a, const InterfaceSet *b);
+#endif  // InterfaceSet_h
diff --git a/hicn-light/src/utils/punting.c b/hicn-light/src/utils/punting.c
new file mode 100755 (executable)
index 0000000..9352732
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017-2019 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 <src/config.h>
+#include <stdio.h>
+
+#include <parc/assert/parc_Assert.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <src/utils/punting.h>
+
+struct punting {
+  char *symbolic;
+  Address *prefix;
+  uint32_t len;
+};
+
+Punting *puntingCreate(const char *listenerName, Address *prefix,
+                       uint32_t len) {
+  parcAssertNotNull(listenerName, "Parameter listenerName must be non-null");
+  parcAssertNotNull(prefix, "Parameter prefix must be non-null");
+
+  Punting *punting = parcMemory_AllocateAndClear(sizeof(Punting));
+  if (punting) {
+    punting->symbolic =
+        parcMemory_StringDuplicate(listenerName, strlen(listenerName));
+    punting->prefix = addressCopy(prefix);
+    punting->len = len;
+  }
+
+  return punting;
+}
+
+void puntingRelease(Punting **puntingPtr) {
+  parcAssertNotNull(puntingPtr,
+                    "Parameter puntingPtr must be non-null double pointer");
+  parcAssertNotNull(*puntingPtr,
+                    "Parameter puntingPtr dereference to non-null pointer");
+
+  Punting *punting = *puntingPtr;
+
+  if (punting->symbolic) {
+    parcMemory_Deallocate((void **)&punting->symbolic);
+  }
+
+  if (punting->prefix) {
+    addressDestroy(&punting->prefix);
+  }
+
+  parcMemory_Deallocate((void **)&punting);
+  *puntingPtr = NULL;
+}
+
+bool puntingEquals(const Punting *a, const Punting *b) {
+  if ((a == NULL && b == NULL) || a == b) {
+    // both null or identically equal
+    return true;
+  }
+
+  if (a == NULL || b == NULL) {
+    // only one is null
+    return false;
+  }
+
+  if ((strcmp(a->symbolic, b->symbolic) == 0) &&
+      (addressEquals(a->prefix, b->prefix)) && (a->len == b->len)) {
+    return true;
+  }
+
+  return false;
+}
+
+const char *puntingGetSymbolicName(const Punting *punting) {
+  parcAssertNotNull(punting, "Parameter listener must be non-null");
+  return punting->symbolic;
+}
+
+Address *puntingGetAddress(const Punting *punting) {
+  parcAssertNotNull(punting, "Parameter listener must be non-null");
+  return punting->prefix;
+}
+
+uint32_t puntingPrefixLen(const Punting *punting) {
+  parcAssertNotNull(punting, "Parameter listener must be non-null");
+  return punting->len;
+}
diff --git a/hicn-light/src/utils/punting.h b/hicn-light/src/utils/punting.h
new file mode 100755 (executable)
index 0000000..03841c5
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019 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 punting_h
+#define punting_h
+
+struct punting;
+typedef struct punting Punting;
+
+#include <src/utils/address.h>
+
+/**
+ * Creates a Punting object
+ *
+ * The symbolic name represents this listener and may be used by other commands.
+ * It must be unique, otherwise the command will fail when sent to the
+ * forwarder.
+ *
+ * @param [in] symbolic     name of the listener
+ * @param [in] prefix       address to add to the punting rule
+ * @param [in] len          prefix length
+ *
+ * @return non-null An Allocated object
+ * @return null An error
+ *
+ */
+Punting *puntingCreate(const char *symbolic, Address *prefix, uint32_t len);
+
+/**
+ * Releases a reference count to the object
+ *
+ * <#Paragraphs Of Explanation#>
+ *
+ * @param [in,out] etherConnPtr A pointer to an etherConn object, will be
+ * null'd.
+ *
+ */
+void puntingRelease(Punting **puntingPtr);
+
+/**
+ * Determine if two light Punting are equal.
+ *
+ */
+
+bool puntingEquals(const Punting *a, const Punting *b);
+
+/**
+ * Returns the symbolic name
+ *
+ */
+const char *puntingGetSymbolicName(const Punting *punting);
+
+/**
+ * Returns the address (INET or INET6 ip address)
+ *
+ */
+Address *puntingGetAddress(const Punting *punting);
+
+uint32_t puntingPrefixLen(const Punting *punting);
+#endif  // punting_h
diff --git a/hicn-light/src/utils/utils.c b/hicn-light/src/utils/utils.c
new file mode 100755 (executable)
index 0000000..a41478a
--- /dev/null
@@ -0,0 +1,258 @@
+// Utility function for commands
+
+#include <ctype.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Network.h>
+#include <parc/assert/parc_Assert.h>
+#include <src/utils/utils.h>
+
+// This is the unique sequence number used by all messages and its thread locks
+static pthread_mutex_t nextSequenceNumberMutex = PTHREAD_MUTEX_INITIALIZER;
+static uint32_t nextSequenceNumber = 1;
+
+uint32_t utils_GetNextSequenceNumber(void) {
+  uint32_t seqnum;
+
+  int result = pthread_mutex_lock(&nextSequenceNumberMutex);
+  parcAssertTrue(result == 0, "Got error from pthread_mutex_lock: %d", result);
+
+  seqnum = nextSequenceNumber++;
+
+  result = pthread_mutex_unlock(&nextSequenceNumberMutex);
+  parcAssertTrue(result == 0, "Got error from pthread_mutex_unlock: %d",
+                 result);
+
+  return seqnum;
+}
+
+/**
+ * Return true if string is purely an integer
+ */
+bool utils_IsNumber(const char *string) {
+  size_t len = strlen(string);
+  for (size_t i = 0; i < len; i++) {
+    if (!isdigit(string[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ * A symbolic name must be at least 1 character and must begin with an alpha.
+ * The remainder must be an alphanum.
+ */
+bool utils_ValidateSymbolicName(const char *symbolic) {
+  bool success = false;
+  size_t len = strlen(symbolic);
+  if (len > 0) {
+    if (isalpha(symbolic[0])) {
+      success = true;
+      for (size_t i = 1; i < len; i++) {
+        if (!isalnum(symbolic[i])) {
+          success = false;
+          break;
+        }
+      }
+    }
+  }
+  return success;
+}
+
+Address *utils_AddressFromInet(in_addr_t *addr4, in_port_t *port) {
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = *port;
+  addr.sin_addr.s_addr = *addr4;
+
+  Address *result = addressCreateFromInet(&addr);
+  return result;
+}
+
+Address *utils_AddressFromInet6(struct in6_addr *addr6, in_port_t *port) {
+  struct sockaddr_in6 addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port = *port;
+  addr.sin6_addr = *addr6;
+  addr.sin6_scope_id = 0;
+  // Other 2 fields: scope_id and flowinfo, do not know what to put inside.
+
+  Address *result = addressCreateFromInet6(&addr);
+  return result;
+}
+
+struct iovec *utils_CreateAck(header_control_message *header, void *payload,
+                              size_t payloadLen) {
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  header->messageType = ACK_LIGHT;
+
+  response[0].iov_base = header;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payload;
+  response[1].iov_len = payloadLen;
+
+  return response;
+}
+
+struct iovec *utils_CreateNack(header_control_message *header, void *payload,
+                               size_t payloadLen) {
+  struct iovec *response =
+      parcMemory_AllocateAndClear(sizeof(struct iovec) * 2);
+
+  header->messageType = NACK_LIGHT;
+
+  response[0].iov_base = header;
+  response[0].iov_len = sizeof(header_control_message);
+  response[1].iov_base = payload;
+  response[1].iov_len = payloadLen;
+
+  return response;
+}
+
+char *utils_BuildStringFromInet(in_addr_t *addr4, in_port_t *port) {
+  struct sockaddr_in addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  addr.sin_port = *port;
+  addr.sin_addr.s_addr = *addr4;
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+      parcNetwork_SockInet4Address_BuildString(&addr, composer));
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  parcBufferComposer_Release(&composer);
+  return result;
+}
+
+char *utils_BuildStringFromInet6(struct in6_addr *addr6, in_port_t *port) {
+  struct sockaddr_in6 addr;
+  memset(&addr, 0, sizeof(addr));
+  addr.sin6_family = AF_INET6;
+  addr.sin6_port = *port;
+  addr.sin6_addr = *addr6;
+
+  PARCBufferComposer *composer = parcBufferComposer_Create();
+  PARCBuffer *tempBuffer = parcBufferComposer_ProduceBuffer(
+      parcNetwork_SockInet6Address_BuildString(&addr, composer));
+  char *result = parcBuffer_ToString(tempBuffer);
+  parcBuffer_Release(&tempBuffer);
+  parcBufferComposer_Release(&composer);
+  return result;
+}
+
+char *utils_CommandAddressToString(address_type addressType,
+                                   union commandAddr *address,
+                                   in_port_t *port) {
+  char *result;
+
+  switch (addressType) {
+    case ADDR_INET: {
+      result = utils_BuildStringFromInet(&address->ipv4, port);
+      break;
+    }
+
+    case ADDR_INET6: {
+      result = utils_BuildStringFromInet6(&address->ipv6, port);
+      break;
+    }
+
+    default: {
+      char *addrStr = (char *)parcMemory_Allocate(sizeof(char) * 32);
+      sprintf(addrStr, "Error: UNKNOWN address type = %d", addressType);
+      result = addrStr;
+      break;
+    }
+  }
+  return result;
+}
+
+struct iovec *utils_SendRequest(ControlState *state, command_id command,
+                                void *payload, size_t payloadLen) {
+  bool success = false;
+
+  // get sequence number for the header
+  uint32_t currentSeqNum = utils_GetNextSequenceNumber();
+
+  // Allocate and fill the header
+  header_control_message *headerControlMessage =
+      parcMemory_AllocateAndClear(sizeof(header_control_message));
+  headerControlMessage->messageType = REQUEST_LIGHT;
+  headerControlMessage->commandID = command;
+  headerControlMessage->seqNum = currentSeqNum;
+  if (payloadLen > 0) {
+    headerControlMessage->length = 1;
+  }
+
+  struct iovec msg[2];
+  msg[0].iov_base = headerControlMessage;
+  msg[0].iov_len = sizeof(header_control_message);
+  msg[1].iov_base = payload;
+  msg[1].iov_len = payloadLen;
+
+  struct iovec *response = controlState_WriteRead(state, msg);
+
+  header_control_message *receivedHeader =
+      (header_control_message *)response[0].iov_base;
+  if (receivedHeader->seqNum != currentSeqNum) {
+    printf("Seq number is NOT correct: expected %d got %d  \n", currentSeqNum,
+           receivedHeader->seqNum);
+    // failure
+  } else {
+    if (receivedHeader->messageType == RESPONSE_LIGHT) {
+      return response;  // command needs both payload and header
+    } else {
+      if (receivedHeader->messageType == ACK_LIGHT) {
+        success = true;
+      } else if (receivedHeader->messageType == NACK_LIGHT) {
+        success = true;
+      } else {
+        printf("Error: unrecognized message type");  // failure
+      }
+    }
+  }
+
+  // deallocate when payload & header of the response are not needed
+  if (receivedHeader->length > 0) {
+    parcMemory_Deallocate(&response[1].iov_base);  // free received payload
+  }
+  parcMemory_Deallocate(&response[0].iov_base);  // free receivedHeader
+
+  // return response
+  if (success) {
+    return response;
+  } else {
+    parcMemory_Deallocate(&response);  // free iovec pointer
+    return NULL;                       // will generate a failure
+  }
+}
+
+const char *utils_PrefixLenToString(address_type addressType,
+                                    union commandAddr *address,
+                                    uint8_t *prefixLen) {
+  char len[4];  // max size + 1
+  sprintf(len, "%u", (unsigned)*prefixLen);
+  in_port_t port = htons(1234);  // this is a random port number that is ignored
+
+  char *prefix = utils_CommandAddressToString(addressType, address, &port);
+  char *prefixStr = malloc(strlen(prefix) + strlen(len) + 2);
+  strcpy(prefixStr, prefix);
+  strcat(prefixStr, "/");
+  strcat(prefixStr, len);
+
+  free(prefix);
+
+  return prefixStr;
+}
diff --git a/hicn-light/src/utils/utils.h b/hicn-light/src/utils/utils.h
new file mode 100755 (executable)
index 0000000..1d26169
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017-2019 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 utils_h
+#define utils_h
+
+#include <src/config/controlState.h>
+#include <src/utils/address.h>
+#include <src/utils/commands.h>
+
+/**
+ * Return true if string is purely an integer
+ */
+bool utils_IsNumber(const char *string);
+
+/**
+ * A symbolic name must be at least 1 character and must begin with an alpha.
+ * The remainder must be an alphanum.
+ */
+bool utils_ValidateSymbolicName(const char *symbolic);
+
+/**
+ * Convert an internet address family (IPv4) to the address format used by the
+ * Fwd
+ */
+Address *utils_AddressFromInet(in_addr_t *addr4, in_port_t *port);
+
+/**
+ * Convert an internet address family (IPv6) to the address format used by the
+ * Fwd
+ */
+Address *utils_AddressFromInet6(struct in6_addr *addr6, in_port_t *port);
+
+/**
+ *Create an Ack message instance as a response of a control successfully
+ *completed.
+ */
+struct iovec *utils_CreateAck(header_control_message *header, void *payload,
+                              size_t payloadLen);
+
+/**
+ *Create a Nack message instance as a response of a control unsuccessfully
+ *completed.
+ */
+struct iovec *utils_CreateNack(header_control_message *header, void *payload,
+                               size_t payloadLen);
+
+/**
+ *Convert IPv4/IPv6 address from binary to text string. `uint8_t *ipAddress` has
+ *to be a `in_addr_t * or `a struct in6_addr *.
+ */
+char *utils_CommandAddressToString(address_type addressType,
+                                   union commandAddr *address, in_port_t *port);
+
+/**
+ *Given a command payload, it generates the header and send the request to the
+ *deamon.
+ */
+struct iovec *utils_SendRequest(ControlState *state, command_id command,
+                                void *payload, size_t payloadLen);
+
+/**
+ *Convert a IPv4/IPv6 address plus Netmask len from binary to text string in the
+ *form [add]:[port]/[len].
+ */
+const char *utils_PrefixLenToString(address_type addressType,
+                                    union commandAddr *address,
+                                    uint8_t *prefixLen);
+
+#endif
\ No newline at end of file
diff --git a/hicn-plugin/AUTHORS b/hicn-plugin/AUTHORS
new file mode 100755 (executable)
index 0000000..9a3da8e
--- /dev/null
@@ -0,0 +1,4 @@
+hicn-plugin authors are listed below:
+
+    Alberto Compagno <acompagn@cisco.com>
+    Luca Muscariello <lumuscar@cisco.com>
\ No newline at end of file
diff --git a/hicn-plugin/CMakeLists.txt b/hicn-plugin/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f58ecb0
--- /dev/null
@@ -0,0 +1,235 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+project(hicn-plugin)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../cmake/Modules/")
+set (CMAKE_CXX_STANDARD 11)
+set (CMAKE_C_STANDARD 11)
+
+# Check for memfd_create syscall
+include(CheckSymbolExists)
+CHECK_SYMBOL_EXISTS ( "__NR_memfd_create" "sys/syscall.h" HAVE_MEMFD_CREATE )
+if ( HAVE_MEMFD_CREATE )
+    add_definitions ( -DHAVE_MEMFD_CREATE )
+endif()
+
+# Dependencies
+
+find_package(Vpp REQUIRED)
+
+include_directories(${VPP_INCLUDE_DIR})
+
+set(LIBHICN_FILES
+    ../lib/src/mapme.c
+    ../lib/src/name.c
+    ../lib/src/ops.c
+    ../lib/src/protocol/ah.c
+    ../lib/src/protocol/icmp.c
+    ../lib/src/protocol/ipv4.c
+    ../lib/src/protocol/ipv6.c
+    ../lib/src/protocol/tcp.c
+)
+
+set(LIBHICN_HEADER_FILES_SRC
+    ../lib/src/hicn.h
+    ../lib/src/base.h
+    ../lib/src/common.h
+    ../lib/src/error.h
+    ../lib/src/header.h
+    ../lib/src/name.h
+    ../lib/src/protocol.h
+    ../lib/src/ops.h
+    ../lib/src/mapme.h
+)
+
+set(LIBHICN_HEADER_FILES_PROTOCOL
+    ../lib/src/protocol/ah.h
+    ../lib/src/protocol/icmp.h
+    ../lib/src/protocol/icmprd.h
+    ../lib/src/protocol/ipv4.h
+    ../lib/src/protocol/ipv6.h
+    ../lib/src/protocol/tcp.h
+    ../lib/src/protocol/udp.h
+)
+
+set(HICN_PLUGIN_SOURCE_FILES
+    src/hicn.c
+    src/hicn_api.c
+    src/cli.c
+    src/hashtb.c
+    src/mgmt.c
+    src/pcs.c
+    src/route.c
+    src/strategy_dpo_manager.c
+    src/strategy.c
+    src/interest_pcslookup_node.c
+    src/interest_hitpit_node.c
+    src/interest_hitcs_node.c
+    src/data_pcslookup_node.c
+    src/data_fwd_node.c
+    src/data_push_node.c
+    src/error.c
+    src/faces/face_cli.c
+    src/faces/face.c
+    src/faces/ip/face_ip.c
+    src/faces/ip/face_ip_cli.c
+    src/faces/ip/face_ip_node.c
+    src/faces/ip/iface_ip_node.c
+    src/faces/ip/dpo_ip.c
+    src/faces/udp/face_udp.c
+    src/faces/udp/face_udp_cli.c
+    src/faces/udp/face_udp_node.c
+    src/faces/udp/iface_udp_node.c
+    src/faces/udp/dpo_udp.c
+    src/faces/app/address_mgr.c
+    src/faces/app/face_cons.c
+    src/faces/app/face_prod.c
+    src/faces/app/face_prod_node.c
+    src/faces/app/face_app_cli.c
+    src/punt.c
+    src/pg.c
+    src/strategies/dpo_mw.c
+    src/strategies/strategy_mw.c
+    src/strategies/strategy_mw_cli.c
+    src/cache_policies/cs_lru.c
+    src/mapme_ack_node.c
+    src/mapme_ctrl_node.c
+    src/mapme_eventmgr.c
+)
+
+set(HICN_PLUGIN_HEADER_FILES
+    src/hicn_all_api_h.h
+    src/hashtb.h
+    src/mgmt.h
+    src/params.h
+    src/pcs.h
+    src/hicn_api.h
+    src/hicn.h
+    src/state.h
+    src/infra.h
+    src/hicn_msg_enum.h
+    src/parser.h
+    src/route.h
+    src/strategy_dpo_ctx.h
+    src/strategy_dpo_manager.h
+    src/strategy.h
+    src/interest_pcslookup.h
+    src/interest_hitpit.h
+    src/interest_hitcs.h
+    src/data_pcslookup.h
+    src/data_fwd.h
+    src/error.h
+    src/face_db.h
+    src/faces/face.h
+    src/faces/ip/face_ip.h
+    src/faces/ip/face_ip_node.h
+    src/faces/ip/iface_ip_node.h
+    src/faces/ip/dpo_ip.h
+    src/faces/udp/face_udp.h
+    src/faces/udp/face_udp_node.h
+    src/faces/udp/iface_udp_node.h
+    src/faces/udp/dpo_udp.h
+    src/faces/app/address_mgr.h
+    src/faces/app/face_cons.h
+    src/faces/app/face_prod.h
+    src/punt.h
+    src/pg.h
+    src/strategies/dpo_mw.h
+    src/strategies/strategy_mw.h
+    src/cache_policies/cs_policy.h
+    src/cache_policies/cs_lru.h
+    src/mapme.h
+    src/mapme_ack.h
+    src/mapme_ctrl.h
+    src/mapme_eventmgr.h
+)
+
+set(HICN_API_TEST_SOURCE_FILES
+    src/hicn_api_test.c
+    src/error.c)
+
+set(HICN_API_TEST_HEADER_FILES
+    src/hicn_msg_enum.h
+    src/hicn_all_api_h.h
+    src/hicn_api.h
+    src/error.h)
+
+set(HICN_API_GENERATED_FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins/hicn/hicn.api.h)
+
+if (NOT VPP_HOME)
+    set(VPP_HOME /usr)
+endif()
+
+if (NOT CMAKE_BUILD_TYPE)
+    set (CMAKE_BUILD_TYPE "Release")
+endif (NOT CMAKE_BUILD_TYPE)
+
+SET(HICN_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/lib CACHE STRING "hicn_install_prefix")
+
+if (CMAKE_BUILD_TYPE STREQUAL "Release")
+   set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wall  -march=native -O3 -g")
+elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
+   set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -march=native -O0 -g")
+   add_definitions(-DCLIB_DEBUG -fPIC -fstack-protector-all)
+endif()
+
+execute_process(COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/hicn)
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins/hicn/hicn.api.h
+        COMMAND ${VPP_HOME}/bin/vppapigen --input ${CMAKE_CURRENT_SOURCE_DIR}/src/hicn.api --output ${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins/hicn/hicn.api.h
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/hicn.api)
+
+include_directories(SYSTEM)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHICN_VPP_PLUGIN=1")
+add_library(hicn_plugin SHARED
+    ${LIBHICN_FILES}
+    ${HICN_PLUGIN_SOURCE_FILES}
+    ${HICN_API_GENERATED_FILES})
+
+file(COPY ${HICN_API_TEST_HEADER_FILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins/hicn)
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/vpp_plugins)
+
+file(COPY ${LIBHICN_HEADER_FILES_SRC} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/hicn)
+file(COPY ${LIBHICN_HEADER_FILES_PROTOCOL} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/hicn/protocol)
+
+add_library(hicn_api_test_plugin SHARED
+       ${HICN_API_TEST_SOURCE_FILES}
+        ${HICN_API_GENERATED_FILES})
+
+set(VPP_INSTALL_PLUGIN ${HICN_INSTALL_PREFIX}/vpp_plugins)
+set(VPP_INSTALL_API_TEST_PLUGIN ${HICN_INSTALL_PREFIX}/vpp_api_test_plugins CACHE STRING "vpp_install_api_test_plugin")
+
+set_target_properties(hicn_plugin
+        PROPERTIES
+        LINKER_LANGUAGE C
+        INSTALL_RPATH ${VPP_INSTALL_PLUGIN}
+        PREFIX "")
+set_target_properties(hicn_api_test_plugin
+        PROPERTIES
+        LINKER_LANGUAGE C
+        PREFIX "")
+
+install(DIRECTORY DESTINATION ${VPP_INSTALL_PLUGIN})
+install(TARGETS hicn_plugin
+        DESTINATION
+        ${VPP_INSTALL_PLUGIN})
+
+install(DIRECTORY DESTINATION ${VPP_INSTALL_API_TEST_PLUGIN})
+install(TARGETS hicn_api_test_plugin
+        DESTINATION
+        ${VPP_INSTALL_API_TEST_PLUGIN})
+
+install(FILES ${HICN_API_TEST_HEADER_FILES} ${HICN_API_GENERATED_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/vpp_plugins/hicn)
diff --git a/hicn-plugin/README.md b/hicn-plugin/README.md
new file mode 100755 (executable)
index 0000000..448130b
--- /dev/null
@@ -0,0 +1,168 @@
+Hybrid ICN project: VPP plugin
+==============================
+
+The hICN-plugin forwarder
+
+## Introduction ##
+
+A high-performance Hybrid ICN forwarder as a plugin to VPP.
+
+The plugin provides the following functionalities:
+
+ - Fast packet processing
+ - Interest aggregation
+ - Content caching
+ - Forwarding strategies
+
+## Quick Start ##
+```
+From the code tree root
+
+(VPP installed with DEB pkg)
+$ cd hicn-plugin
+$ mkdir -p build
+$ cd build
+$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr
+$ make
+$ sudo make install
+
+(VPP source code -- build type RELEASE)
+$ cd hicn-plugin
+$ mkdir -p build
+$ cd build
+$ cmake .. -DVPP_HOME=<vpp dir>/build-root/install-vpp-native/vpp/include/ -DHICN_INSTALL_PREFIX=<vpp src>/build-root/install-vpp-native/vpp/lib
+$ make
+$ sudo make install
+
+(VPP source code -- build type DEBUG)
+$ cd hicn-plugin
+$ mkdir -p build
+$ cd build
+$ cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DVPP_HOME=<vpp dir>/build-root/install-vpp_debug-native/vpp/include/ -DHICN_INSTALL_PREFIX=<vpp src>/build-root/install-vpp_debug-native/vpp/lib
+$ make
+$ sudo make install
+
+CMAKE variables:
+- HICN_INSTALL_PREFIX -- set the install directory for the hicn-plugin. This is the common path to the folders vpp_plugins and vpp_api_test_plugins. Default is <vpp install dir>/lib
+- VPP_INSTALL_PLUGIN -- set the install directory for the libhicn_plugin.so. Defatuls id $HICN_INSTALL_PREFIX/vpp_plugins
+- HICN_API_TEST_HEADER_FILES -- set the install directory for the header files. Default is <vpp install dir>/include/vpp_plugins/hicn
+```
+
+## Using hICN plugin ##
+
+### Platforms ###
+
+hICN-plugin has been tested in:
+
+- Ubuntu 16.04 LTS (x86_64)
+- Ubuntu 18.04 LTS (x86_64)
+- Debian Stable/Testing
+- Red Hat Enterprise Linux 7
+- CentOS 7
+
+
+### Dependencies ###
+
+Build dependencies:
+
+- VPP 19.01
+  - DEB packages:
+  - vpp
+  - vpp-lib
+  - vpp-dev
+  - vpp-plugins
+
+Hardware support:
+
+- [DPDK](http://DPDK.org/) compatible nic
+
+### Getting started ###
+In order to start, the hICN plugin requires a running instance of VPP
+The steps required to successfully start hICN are:
+
+- Setup the host to run VPP
+- Configure VPP to use DPDK compatible nics
+- Start VPP
+- Configure VPP interfaces
+- Configure and start hICN
+
+Detailed information for configuring VPP can be found at [https://wiki.fd.io/view/VPP](https://wiki.fd.io/view/VPP).
+
+##### Setup the host for VPP #####
+
+Hugepages must be enabled in the system
+
+```
+$ sudo sysctl -w vm.nr_hugepages=1024
+```
+
+In order to use a DPDK interface, the package vpp-dpdk-dkms must be installed in the system and the `uio` and `igb_uio` modules need to be loaded in the kernel
+
+```
+$ sudo apt install vpp-dpdk-dkms
+$ sudo modprobe uio
+$ sudo modprobe igb_uio
+```
+
+If the DPDK interface we want to assign to VPP is up, we must bring it down
+
+```
+$ sudo ifconfig <interface_name> down
+```
+
+##### Configure VPP #####
+The file /etc/VPP/startup.conf contains a set of parameters to setup VPP at startup.
+The following example sets up VPP to use a DPDK interfaces:
+
+``` shell
+unix {
+  nodaemon
+  log /tmp/vpp.log
+  full-coredump
+}
+
+api-trace {
+  on
+}
+
+api-segment {
+  gid vpp
+}
+
+dpdk {
+  dev 0000:08:00.0
+}
+```
+Where `0000:08:00.0` must be replaced with the actual PCI address of the DPDK interface
+
+##### Start VPP #####
+
+VPP can be started as a process or a service:
+
+``` shell
+Start VPP as a service in Ubuntu 16.04
+$ sudo systemctl start vpp
+
+Start VPP as a process in both 16.04
+$ sudo vpp -c /etc/vpp/startup.conf
+
+```
+
+## License ##
+
+This software is distributed under the following license:
+
+```
+Copyright (c) 2017-2019 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.
+```
\ No newline at end of file
diff --git a/hicn-plugin/src/cache_policies/cs_lru.c b/hicn-plugin/src/cache_policies/cs_lru.c
new file mode 100755 (executable)
index 0000000..f35bee3
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017-2019 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 "../hashtb.h"
+#include "../strategy_dpo_manager.h"
+#include "../error.h"
+#include "cs_lru.h"
+#include "cs_policy.h"
+
+hicn_cs_policy_vft_t hicn_cs_lru = {
+  .hicn_cs_insert = &hicn_cs_lru_insert,
+  .hicn_cs_update = &hicn_cs_lru_update_head,
+  .hicn_cs_dequeue = &hicn_cs_lru_dequeue,
+  .hicn_cs_delete_get = &hicn_cs_lru_delete_get,
+  .hicn_cs_trim = &hicn_cs_lru_trim,
+};
+
+/*
+ * Insert a new CS element at the head of the CS LRU
+ */
+void
+hicn_cs_lru_insert (hicn_pit_cs_t * p, hicn_hash_node_t * node,
+                   hicn_pcs_entry_t * pcs, hicn_cs_policy_t * policy_state)
+{
+  hicn_hash_node_t *lrunode;
+  hicn_pcs_entry_t *lrupcs;
+  u32 idx;
+
+  idx = hicn_hashtb_node_idx_from_node (p->pcs_table, node);
+
+  if (policy_state->head != 0)
+    {
+      lrunode = hicn_hashtb_node_from_idx (p->pcs_table, policy_state->head);
+      lrupcs = hicn_pit_get_data (lrunode);
+
+      ASSERT (lrupcs->u.cs.cs_lru_prev == 0);
+      lrupcs->u.cs.cs_lru_prev = idx;
+
+      pcs->u.cs.cs_lru_prev = 0;
+      pcs->u.cs.cs_lru_next = policy_state->head;
+
+      policy_state->head = idx;
+    }
+  else
+    {
+      ASSERT (policy_state->tail == 0);        /* We think the list is
+                                        * empty */
+
+      policy_state->head = policy_state->tail = idx;
+
+      pcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_prev = 0;
+    }
+
+  policy_state->count++;
+}
+
+void
+hicn_cs_lru_delete_get (hicn_pit_cs_t * p, hicn_cs_policy_t * policy_state,
+                       hicn_hash_node_t ** nodep,
+                       hicn_pcs_entry_t ** pcs_entry,
+                       hicn_hash_entry_t ** hash_entry)
+{
+  *nodep = hicn_hashtb_node_from_idx (p->pcs_table, policy_state->tail);
+  *pcs_entry = hicn_pit_get_data (*nodep);
+
+  *hash_entry = hicn_hashtb_get_entry (p->pcs_table, (*nodep)->entry_idx,
+                                      (*nodep)->bucket_id,
+                                      (*nodep)->hn_flags &
+                                      HICN_HASH_NODE_OVERFLOW_BUCKET);
+}
+
+/*
+ * Dequeue an LRU element, for example when it has expired.
+ */
+void
+hicn_cs_lru_dequeue (hicn_pit_cs_t * pit, hicn_hash_node_t * pnode,
+                    hicn_pcs_entry_t * pcs, hicn_cs_policy_t * lru)
+{
+  hicn_hash_node_t *lrunode;
+  hicn_pcs_entry_t *lrupcs;
+
+  if (pcs->u.cs.cs_lru_prev != 0)
+    {
+      /* Not already on the head of the LRU */
+      lrunode = hicn_hashtb_node_from_idx (pit->pcs_table,
+                                          pcs->u.cs.cs_lru_prev);
+      lrupcs = hicn_pit_get_data (lrunode);
+
+      lrupcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_next;
+    }
+  else
+    {
+      ASSERT (lru->head ==
+             hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode));
+      lru->head = pcs->u.cs.cs_lru_next;
+    }
+
+  if (pcs->u.cs.cs_lru_next != 0)
+    {
+      /* Not already the end of the LRU */
+      lrunode = hicn_hashtb_node_from_idx (pit->pcs_table,
+                                          pcs->u.cs.cs_lru_next);
+      lrupcs = hicn_pit_get_data (lrunode);
+
+      lrupcs->u.cs.cs_lru_prev = pcs->u.cs.cs_lru_prev;
+    }
+  else
+    {
+      /* This was the last LRU element */
+      ASSERT (lru->tail ==
+             hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode));
+      lru->tail = pcs->u.cs.cs_lru_prev;
+    }
+
+  pcs->u.cs.cs_lru_next = pcs->u.cs.cs_lru_prev = 0;
+  lru->count--;
+}
+
+/*
+ * Move a CS LRU element to the head, probably after it's been used.
+ */
+void
+hicn_cs_lru_update_head (hicn_pit_cs_t * pit, hicn_hash_node_t * pnode,
+                        hicn_pcs_entry_t * pcs, hicn_cs_policy_t * lru)
+{
+  if (pcs->u.cs.cs_lru_prev != 0)
+    {
+      /*
+       * Not already on the head of the LRU, detach it from its
+       * current position
+       */
+      hicn_cs_lru_dequeue (pit, pnode, pcs, lru);
+
+      /* Now detached from the list; attach at head */
+      hicn_cs_lru_insert (pit, pnode, pcs, lru);
+
+    }
+  else
+    {
+      ASSERT (lru->head ==
+             hicn_hashtb_node_idx_from_node (pit->pcs_table, pnode));
+    }
+}
+
+/*
+ * Remove a batch of nodes from the CS LRU, copying their node indexes into
+ * the caller's array. We expect this is done when the LRU size exceeds the
+ * CS's limit. Return the number of removed nodes.
+ */
+int
+hicn_cs_lru_trim (hicn_pit_cs_t * pit, u32 * node_list, int sz,
+                 hicn_cs_policy_t * lru)
+{
+  hicn_hash_node_t *lrunode;
+  hicn_pcs_entry_t *lrupcs;
+  u32 idx;
+  int i;
+
+  idx = lru->tail;
+
+  for (i = 0; i < sz; i++)
+    {
+
+      if (idx == 0)
+       {
+         break;
+       }
+      lrunode = hicn_hashtb_node_from_idx (pit->pcs_table, idx);
+      lrupcs = hicn_pit_get_data (lrunode);
+
+      node_list[i] = idx;
+
+      idx = lrupcs->u.cs.cs_lru_prev;
+      lrupcs->u.cs.cs_lru_prev = 0;
+      lrupcs->u.cs.cs_lru_next = 0;
+    }
+
+  lru->count -= i;
+
+  lru->tail = idx;
+  if (idx != 0)
+    {
+      lrunode = hicn_hashtb_node_from_idx (pit->pcs_table, idx);
+      lrupcs = hicn_pit_get_data (lrunode);
+
+      lrupcs->u.cs.cs_lru_next = 0;
+    }
+  else
+    {
+      /* If the tail is empty, the whole lru is empty */
+      lru->head = 0;
+    }
+
+  return (i);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/cache_policies/cs_lru.h b/hicn-plugin/src/cache_policies/cs_lru.h
new file mode 100755 (executable)
index 0000000..94320f7
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017-2019 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 __LRU_H__
+#define __LRU_H__
+
+#include "../pcs.h"
+#include "../hashtb.h"
+#include "cs_policy.h"
+
+extern hicn_cs_policy_vft_t hicn_cs_lru;
+
+/*
+ * Insert a new CS element at the head of the CS LRU
+ */
+void
+hicn_cs_lru_insert (hicn_pit_cs_t * pcs, hicn_hash_node_t * pnode,
+                   hicn_pcs_entry_t * entry, hicn_cs_policy_t * lru);
+
+
+/*
+ * Dequeue an LRU element, for example when it has expired.
+ */
+void
+hicn_cs_lru_dequeue (hicn_pit_cs_t * pcs, hicn_hash_node_t * pnode,
+                    hicn_pcs_entry_t * entry, hicn_cs_policy_t * lru);
+
+/*
+ * Move a CS LRU element to the head, probably after it's been used.
+ */
+void
+hicn_cs_lru_update_head (hicn_pit_cs_t * pcs, hicn_hash_node_t * pnode,
+                        hicn_pcs_entry_t * entry, hicn_cs_policy_t * lru);
+
+void
+hicn_cs_lru_delete_get (hicn_pit_cs_t * p, hicn_cs_policy_t * policy,
+                       hicn_hash_node_t ** node, hicn_pcs_entry_t ** pcs,
+                       hicn_hash_entry_t ** hash_entry);
+
+/*
+ * Remove a batch of nodes from the CS LRU, copying their node indexes into
+ * the caller's array. We expect this is done when the LRU size exceeds the
+ * CS's limit. Return the number of removed nodes.
+ */
+int hicn_cs_lru_trim (hicn_pit_cs_t * pcs, u32 * node_list, int sz,
+                     hicn_cs_policy_t * lru);
+
+
+#endif /* // __LRU_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/cache_policies/cs_policy.h b/hicn-plugin/src/cache_policies/cs_policy.h
new file mode 100755 (executable)
index 0000000..08817de
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_CS_POLICY_H__
+#define __HICN_CS_POLICY_H__
+
+#include "../hashtb.h"
+
+/*
+ * Structure
+ */
+typedef struct hicn_cs_policy_s
+{
+  u32 max;
+  u32 count;
+
+  /* Indexes to hashtable nodes forming CS LRU */
+  u32 head;
+  u32 tail;
+
+} hicn_cs_policy_t;
+
+/* Forward declaration */
+struct hicn_pit_cs_s;
+struct hicn_hash_node_s;
+struct hicn_pcs_entry_s;
+struct hicn_cs_policy_s;
+
+/**
+ * @brief Definition of the virtual functin table for a cache policy.
+ *
+ * A cache policy must implement three functions: insert, update, delete, trim.
+ */
+typedef struct hicn_cs_policy_vft_s
+{
+  void (*hicn_cs_insert) (struct hicn_pit_cs_s * p,
+                         struct hicn_hash_node_s * node,
+                         struct hicn_pcs_entry_s * pcs,
+                         hicn_cs_policy_t * policy);
+
+  void (*hicn_cs_update) (struct hicn_pit_cs_s * p,
+                         struct hicn_hash_node_s * node,
+                         struct hicn_pcs_entry_s * pcs,
+                         hicn_cs_policy_t * policy);
+
+  void (*hicn_cs_dequeue) (struct hicn_pit_cs_s * p,
+                          struct hicn_hash_node_s * node,
+                          struct hicn_pcs_entry_s * pcs,
+                          hicn_cs_policy_t * policy);
+
+  void (*hicn_cs_delete_get) (struct hicn_pit_cs_s * p,
+                             hicn_cs_policy_t * policy,
+                             struct hicn_hash_node_s ** node,
+                             struct hicn_pcs_entry_s ** pcs,
+                             struct hicn_hash_entry_s ** hash_entry);
+
+  int (*hicn_cs_trim) (struct hicn_pit_cs_s * p, u32 * node_list, int sz,
+                      hicn_cs_policy_t * policy);
+} hicn_cs_policy_vft_t;
+
+
+
+#endif /* // __HICN_POLICY_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/cli.c b/hicn-plugin/src/cli.c
new file mode 100755 (executable)
index 0000000..c8c0be4
--- /dev/null
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vppinfra/error.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/udp/udp.h>      // port registration
+#include <vnet/ip/ip6_packet.h>        // ip46_address_t
+#include <vnet/ip/format.h>
+
+#include "hicn.h"
+#include "infra.h"
+#include "parser.h"
+#include "mgmt.h"
+#include "strategy_dpo_manager.h"
+#include "strategy.h"
+#include "pg.h"
+#include "error.h"
+#include "faces/face.h"
+#include "route.h"
+#include "punt.h"
+#include "hicn_api.h"
+#include "mapme.h"
+
+extern ip_version_t ipv4;
+extern ip_version_t ipv6;
+
+static vl_api_hicn_api_node_params_set_t node_ctl_params = {
+  .pit_max_size = -1,
+  .pit_dflt_lifetime_sec = -1.0f,
+  .pit_min_lifetime_sec = -1.0f,
+  .pit_max_lifetime_sec = -1.0f,
+  .cs_max_size = -1,
+  .cs_reserved_app = -1,
+};
+
+typedef enum
+{
+  IP,
+  ETHERNET,
+} interface_type_t;
+
+/*
+ * Supporting function that return if the interface is IP or ethernet
+ */
+static interface_type_t
+hicn_cli_is_ip_interface (vlib_main_t * vm,
+                         vnet_main_t * vnm, u32 sw_if_index)
+{
+
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, sw_if_index);
+
+  vnet_device_class_t *dev_class =
+    vnet_get_device_class (vnm, hi->dev_class_index);
+  if (!strcmp (dev_class->name, "Loopback"))
+    {
+      return IP;
+    }
+  return ETHERNET;
+
+}
+
+/*
+ * cli handler for 'control start'
+ */
+static clib_error_t *
+hicn_cli_node_ctl_start_set_command_fn (vlib_main_t * vm,
+                                       unformat_input_t * main_input,
+                                       vlib_cli_command_t * cmd)
+{
+  int ret;
+
+  ret = hicn_infra_plugin_enable_disable (1 /* enable */ ,
+                                         node_ctl_params.pit_max_size,
+                                         node_ctl_params.pit_dflt_lifetime_sec,
+                                         node_ctl_params.pit_min_lifetime_sec,
+                                         node_ctl_params.pit_max_lifetime_sec,
+                                         node_ctl_params.cs_max_size,
+                                         node_ctl_params.cs_reserved_app);
+
+  vlib_cli_output (vm, "hicn: fwdr initialize => %s\n",
+                  get_error_string (ret));
+
+  return (ret == HICN_ERROR_NONE) ? 0 : clib_error_return (0,
+                                                          get_error_string
+                                                          (ret));
+}
+
+/*
+ * cli handler for 'control stop'
+ */
+static clib_error_t *
+hicn_cli_node_ctl_stop_set_command_fn (vlib_main_t * vm,
+                                      unformat_input_t * main_input,
+                                      vlib_cli_command_t * cmd)
+{
+  int ret;
+
+  /*
+   * Catch unexpected extra arguments on this line. See comment on
+   * hicn_cli_node_ctrl_start_set_command_fn
+   */
+  if (main_input->index > 0 &&
+      main_input->buffer[main_input->index - 1] != '\n')
+    {
+      unformat_input_t _line_input, *line_input = &_line_input;
+      if (!unformat_user (main_input, unformat_line_input, line_input))
+       {
+         return (0);
+       }
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         return clib_error_return (0, "%s '%U'",
+                                   get_error_string (HICN_ERROR_CLI_INVAL),
+                                   format_unformat_error, line_input);
+       }
+    }
+  ret = hicn_infra_plugin_enable_disable (0 /* !enable */ ,
+                                         node_ctl_params.pit_max_size,
+                                         node_ctl_params.pit_dflt_lifetime_sec,
+                                         node_ctl_params.pit_min_lifetime_sec,
+                                         node_ctl_params.pit_max_lifetime_sec,
+                                         node_ctl_params.cs_max_size,
+                                         node_ctl_params.cs_reserved_app);
+
+  return (ret == HICN_ERROR_NONE) ? 0 : clib_error_return (0,
+                                                          get_error_string
+                                                          (ret));
+}
+
+#define DFLTD_RANGE_OK(val, min, max)        \
+({                        \
+    __typeof__ (val) _val = (val);        \
+    __typeof__ (min) _min = (min);        \
+    __typeof__ (max) _max = (max);        \
+    (_val == -1) ||                \
+    (_val >= _min && _val <= _max);        \
+})
+
+/*
+ * cli handler for 'control param'
+ */
+static clib_error_t *
+hicn_cli_node_ctl_param_set_command_fn (vlib_main_t * vm,
+                                       unformat_input_t * main_input,
+                                       vlib_cli_command_t * cmd)
+{
+  int rv = 0;
+
+  int table_size;
+  f64 lifetime;
+  int cs_reserved_app;
+
+  if (hicn_main.is_enabled)
+    {
+      return (clib_error_return
+             (0, "params cannot be altered once hicn started"));
+    }
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return clib_error_return (0,
+                               get_error_string
+                               (HICN_ERROR_FWD_ALREADY_ENABLED));
+    }
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "pit"))
+       {
+         if (unformat (line_input, "size %d", &table_size))
+           {
+             if (!DFLTD_RANGE_OK (table_size, HICN_PARAM_PIT_ENTRIES_MIN,
+                                  HICN_PARAM_PIT_ENTRIES_MAX))
+               {
+                 rv = HICN_ERROR_PIT_CONFIG_SIZE_OOB;
+                 break;
+               }
+             node_ctl_params.pit_max_size = table_size;
+           }
+         else if (unformat (line_input, "dfltlife %f", &lifetime))
+           {
+             if (!DFLTD_RANGE_OK
+                 (lifetime, HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC,
+                  HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC))
+               {
+                 rv = HICN_ERROR_PIT_CONFIG_DFTLT_OOB;
+                 break;
+               }
+             node_ctl_params.pit_dflt_lifetime_sec = lifetime;
+           }
+         else if (unformat (line_input, "minlife %f", &lifetime))
+           {
+             if (!DFLTD_RANGE_OK
+                 (lifetime, HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC,
+                  HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC))
+               {
+                 rv = HICN_ERROR_PIT_CONFIG_MINLT_OOB;
+                 break;
+               }
+             node_ctl_params.pit_min_lifetime_sec = lifetime;
+           }
+         else if (unformat (line_input, "maxlife %f", &lifetime))
+           {
+             if (!DFLTD_RANGE_OK
+                 (lifetime, HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC,
+                  HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC))
+               {
+                 rv = HICN_ERROR_PIT_CONFIG_MAXLT_OOB;
+                 break;
+               }
+             node_ctl_params.pit_max_lifetime_sec = lifetime;
+           }
+         else
+           {
+             rv = HICN_ERROR_CLI_INVAL;
+             break;
+           }
+       }
+      else if (unformat (line_input, "cs"))
+       {
+         if (unformat (line_input, "size %d", &table_size))
+           {
+             if (!DFLTD_RANGE_OK (table_size, HICN_PARAM_CS_ENTRIES_MIN,
+                                  HICN_PARAM_CS_ENTRIES_MAX))
+               {
+                 rv = HICN_ERROR_CS_CONFIG_SIZE_OOB;
+                 break;
+               }
+             node_ctl_params.cs_max_size = table_size;
+           }
+         else if (unformat (line_input, "app %d", &cs_reserved_app))
+           {
+             if (!DFLTD_RANGE_OK (cs_reserved_app, 0, 100))
+               {
+                 rv = HICN_ERROR_CS_CONFIG_SIZE_OOB;
+                 break;
+               }
+             node_ctl_params.cs_reserved_app = cs_reserved_app;
+           }
+         else
+           {
+             rv = HICN_ERROR_CLI_INVAL;
+             break;
+           }
+       }
+      else
+       {
+         rv = HICN_ERROR_CLI_INVAL;
+         break;
+       }
+    }
+
+  if (node_ctl_params.cs_max_size == 0)
+    vlib_cli_output (vm,
+                    "CS size set to 0. Consider disable CS at compilation time for better performances\n");
+
+  return (rv == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s '%U'",
+                                                         get_error_string
+                                                         (rv),
+                                                         format_unformat_error,
+                                                         line_input);
+}
+
+/*
+ * cli handler for 'hicn show'
+ */
+static clib_error_t *
+hicn_cli_show_command_fn (vlib_main_t * vm, unformat_input_t * main_input,
+                         vlib_cli_command_t * cmd)
+{
+  int face_p = 0, fib_p = 0, all_p, internal_p = 0, strategies_p = 0, ret =
+    HICN_ERROR_NONE;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "face all"))
+           {
+             face_p = 1;
+           }
+         else if (unformat (line_input, "internal"))
+           {
+             /*
+              * We consider 'internal' a superset, so
+              * include 'detail' too
+              */
+             internal_p = 1;
+           }
+         else if (unformat (line_input, "strategies"))
+           {
+             /*
+              * We consider 'internal' a superset, so
+              * include 'detail' too
+              */
+             strategies_p = 1;
+           }
+         else
+           {
+             ret = HICN_ERROR_CLI_INVAL;
+             goto done;
+           }
+       }
+    }
+  /* If nothing specified, show everything */
+  if ((face_p == 0) && (fib_p == 0) && (strategies_p == 0))
+    {
+      all_p = 1;
+    }
+  if (!hicn_main.is_enabled)
+    {
+      if (node_ctl_params.pit_max_size == -1 &&
+         node_ctl_params.pit_dflt_lifetime_sec == -1 &&
+         node_ctl_params.pit_min_lifetime_sec == -1 &&
+         node_ctl_params.pit_max_lifetime_sec == -1 &&
+         node_ctl_params.cs_max_size == -1 &&
+         node_ctl_params.cs_reserved_app == -1)
+       {
+         ret = HICN_ERROR_FWD_NOT_ENABLED;
+         goto done;
+       }
+      vlib_cli_output (vm, "Forwarder: %sabled\nPreconfiguration:\n",
+                      hicn_main.is_enabled ? "en" : "dis");
+
+      if (node_ctl_params.pit_max_size != -1)
+       {
+         vlib_cli_output (vm, "  PIT:: max entries:%d\n",
+                          node_ctl_params.pit_max_size);
+       }
+      if (node_ctl_params.pit_dflt_lifetime_sec != -1)
+       {
+         vlib_cli_output (vm, "  PIT:: dflt lifetime: %05.3f seconds\n",
+                          node_ctl_params.pit_dflt_lifetime_sec);
+       }
+      if (node_ctl_params.pit_min_lifetime_sec != -1)
+       {
+         vlib_cli_output (vm, "  PIT:: min lifetime: %05.3f seconds\n",
+                          node_ctl_params.pit_min_lifetime_sec);
+       }
+      if (node_ctl_params.pit_max_lifetime_sec != -1)
+       {
+         vlib_cli_output (vm, "  PIT:: max lifetime: %05.3f seconds\n",
+                          node_ctl_params.pit_max_lifetime_sec);
+       }
+      if (node_ctl_params.cs_max_size != -1)
+       {
+         vlib_cli_output (vm, "  CS:: max entries:%d\n",
+                          node_ctl_params.cs_max_size);
+       }
+      if (node_ctl_params.cs_reserved_app != -1)
+       {
+         vlib_cli_output (vm, "  CS:: reserved to app:%d\n",
+                          node_ctl_params.cs_reserved_app);
+       }
+      goto done;
+    }
+  /* Globals */
+  vlib_cli_output (vm,
+                  "Forwarder: %sabled\n"
+                  "  PIT:: max entries:%d,"
+                  " lifetime default: %05.3f sec (min:%05.3f, max:%05.3f)\n"
+                  "  CS::  max entries:%d, network entries:%d, app entries:%d (allocated %d, free %d)\n",
+                  hicn_main.is_enabled ? "en" : "dis",
+                  hicn_infra_pit_size,
+                  ((f64) hicn_main.pit_lifetime_dflt_ms) / SEC_MS,
+                  ((f64) hicn_main.pit_lifetime_min_ms) / SEC_MS,
+                  ((f64) hicn_main.pit_lifetime_max_ms) / SEC_MS,
+                  hicn_infra_cs_size,
+                  hicn_infra_cs_size - hicn_main.pitcs.pcs_app_max,
+                  hicn_main.pitcs.pcs_app_max,
+                  hicn_main.pitcs.pcs_app_count,
+                  hicn_main.pitcs.pcs_app_max -
+                  hicn_main.pitcs.pcs_app_count);
+
+  vl_api_hicn_api_node_stats_get_reply_t rm = { 0, }
+  , *rmp = &rm;
+  if (hicn_mgmt_node_stats_get (&rm) == HICN_ERROR_NONE)
+    {
+      vlib_cli_output (vm,     //compare vl_api_hicn_api_node_stats_get_reply_t_handler block
+                      "  PIT entries (now): %d\n"
+                      "  CS total entries (now): %d, network entries (now): %d\n"
+                      "  Forwarding statistics:\n"
+                      "    pkts_processed: %d\n"
+                      "    pkts_interest_count: %d\n"
+                      "    pkts_data_count: %d\n"
+                      "    pkts_from_cache_count: %d\n"
+                      "    interests_aggregated: %d\n"
+                      "    interests_retransmitted: %d\n",
+                      clib_net_to_host_u64 (rmp->pit_entries_count),
+                      clib_net_to_host_u64 (rmp->cs_entries_count),
+                      clib_net_to_host_u64 (rmp->cs_entries_ntw_count),
+                      clib_net_to_host_u64 (rmp->pkts_processed),
+                      clib_net_to_host_u64 (rmp->pkts_interest_count),
+                      clib_net_to_host_u64 (rmp->pkts_data_count),
+                      clib_net_to_host_u64 (rmp->pkts_from_cache_count),
+                      clib_net_to_host_u64 (rmp->interests_aggregated),
+                      clib_net_to_host_u64 (rmp->interests_retx));
+    }
+  if (face_p || all_p)
+    {
+      u8 *strbuf = NULL;
+
+      strbuf = format_hicn_face_all (strbuf, 1, 0);
+      vlib_cli_output (vm, "%s", strbuf);
+
+    }
+  if (strategies_p || all_p)
+    {
+      u8 *strbuf = NULL;
+
+      strbuf = format_hicn_strategy_list (strbuf, 1, 0);
+      vlib_cli_output (vm, (char *) strbuf);
+    }
+done:
+  if (all_p && internal_p && ret == HICN_ERROR_NONE)
+    {
+      vlib_cli_output (vm, "Plugin features: cs:%d\n", HICN_FEATURE_CS);
+      vlib_cli_output (vm,
+                      "Removed CS entries (and freed vlib buffers) %d, Removed PIT entries %d",
+                      hicn_main.pitcs.pcs_cs_dealloc,
+                      hicn_main.pitcs.pcs_pit_dealloc);
+
+    }
+  return (ret == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n",
+                                                          get_error_string
+                                                          (ret));
+}
+
+/*
+ * cli handler for 'fib'
+ */
+static clib_error_t *
+hicn_cli_fib_set_command_fn (vlib_main_t * vm, unformat_input_t * main_input,
+                            vlib_cli_command_t * cmd)
+{
+  clib_error_t *cl_err = 0;
+
+  int rv = HICN_ERROR_NONE;
+  int addpfx = -1;
+  ip46_address_t prefix;
+  hicn_face_id_t faceid = HICN_FACE_NULL;
+  u32 strategy_id;
+  u8 plen = 0;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (addpfx == -1 && unformat (line_input, "add"))
+       {
+         addpfx = 1;
+       }
+      else if (addpfx == -1 && unformat (line_input, "delete"))
+       {
+         addpfx = 0;
+       }
+      else if (unformat (line_input, "set strategy %d", &strategy_id))
+       {
+         addpfx = 2;
+       }
+      else if (addpfx != -1
+              && unformat (line_input, "prefix %U/%d", unformat_ip46_address,
+                           &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else if (addpfx <= 1 && unformat (line_input, "face %u", &faceid))
+       {;
+       }
+      else
+       {
+         cl_err = clib_error_return (0, "%s '%U'",
+                                     get_error_string (HICN_ERROR_CLI_INVAL),
+                                     format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  /* Check parse */
+  if (addpfx <= 1
+      && ((ip46_address_is_zero (&prefix)) || faceid == HICN_FACE_NULL))
+    {
+      cl_err =
+       clib_error_return (0, "Please specify prefix and a valid faceid...");
+      goto done;
+    }
+  /* Check parse */
+  if ((ip46_address_is_zero (&prefix))
+      || (addpfx == 2 && hicn_dpo_strategy_id_is_valid (strategy_id)))
+    {
+      cl_err = clib_error_return (0,
+                                 "Please specify prefix and strategy_id...");
+      goto done;
+    }
+  if (addpfx == 0)
+    {
+      if (ip46_address_is_zero (&prefix))
+       {
+         cl_err = clib_error_return (0, "Please specify prefix");
+         goto done;
+       }
+      if (faceid == HICN_FACE_NULL)
+       {
+         rv = hicn_route_del (&prefix, plen);
+       }
+      else
+       {
+         rv = hicn_route_del_nhop (&prefix, plen, faceid);
+       }
+      cl_err =
+       (rv == HICN_ERROR_NONE) ? NULL : clib_error_return (0,
+                                                           get_error_string
+                                                           (rv));
+
+    }
+  else if (addpfx == 1)
+    {
+      rv = hicn_route_add (&faceid, 1, &prefix, plen);
+      if (rv == HICN_ERROR_ROUTE_ALREADY_EXISTS)
+       {
+         rv = hicn_route_add_nhops (&faceid, 1, &prefix, plen);
+       }
+      cl_err =
+       (rv == HICN_ERROR_NONE) ? NULL : clib_error_return (0,
+                                                           get_error_string
+                                                           (rv));
+    }
+  else if (addpfx == 2)
+    {
+      rv = hicn_route_set_strategy (&prefix, plen, strategy_id);
+      cl_err =
+       (rv == HICN_ERROR_NONE) ? NULL : clib_error_return (0,
+                                                           get_error_string
+                                                           (rv));
+    }
+done:
+
+  return (cl_err);
+}
+
+static clib_error_t *
+hicn_cli_punting_command_fn (vlib_main_t * vm, unformat_input_t * main_input,
+                            vlib_cli_command_t * cmd)
+{
+  hicn_mgmt_punting_op_e punting_op = HICN_MGMT_PUNTING_OP_NONE;
+  unsigned int subnet_mask = 0;
+  ip46_address_t prefix;
+  u32 sw_if_index = ~0;
+  int ret = 0;
+  vnet_main_t *vnm = NULL;
+  u8 type = HICN_PUNT_IP_TYPE;
+  u32 src_port = 0, dst_port = 0;
+  vnm = vnet_get_main ();
+
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "add"))
+       {
+         punting_op = HICN_MGMT_PUNTING_OP_CREATE;
+       }
+      else if (unformat (line_input, "delete"))
+       {
+         punting_op = HICN_MGMT_PUNTING_OP_DELETE;
+       }
+      else if (unformat (line_input, "intfc %U",
+                        unformat_vnet_sw_interface, vnm, &sw_if_index))
+       {;
+       }
+      else if (unformat
+              (line_input, "prefix %U/%d", unformat_ip46_address,
+               &prefix, IP46_TYPE_ANY, &subnet_mask))
+       {;
+       }
+      else if (unformat (line_input, "type ip"))
+       {
+         type = HICN_PUNT_IP_TYPE;
+       }
+      else if (unformat (line_input, "type"))
+       {
+         if (unformat (line_input, "udp4"))
+           {
+             type = HICN_PUNT_UDP4_TYPE;
+           }
+         else if (unformat (line_input, "udp6"))
+           {
+             type = HICN_PUNT_UDP6_TYPE;
+           }
+
+         if (unformat (line_input, "src_port %u", &src_port))
+           ;
+         if (unformat (line_input, "dst_port %u", &dst_port))
+           ;
+       }
+      else
+       {
+         return (clib_error_return (0, "invalid option"));
+       }
+    }
+
+  if (punting_op == HICN_MGMT_PUNTING_OP_CREATE
+      && (ip46_address_is_zero (&prefix) || sw_if_index == ~0))
+    {
+      return (clib_error_return
+             (0, "Please specify valid prefix and interface"));
+    }
+  else if ((punting_op == HICN_MGMT_PUNTING_OP_DELETE) &&
+          ip46_address_is_zero (&prefix))
+    {
+      return (clib_error_return
+             (0, "Please specify valid prefix and optionally an interface"));
+    }
+  else if (punting_op == HICN_MGMT_PUNTING_OP_NONE)
+    {
+      return (clib_error_return
+             (0, "Please specify valid operation, add or delete"));
+    }
+  switch (punting_op)
+    {
+    case HICN_MGMT_PUNTING_OP_CREATE:
+      {
+       if (type == HICN_PUNT_UDP4_TYPE || type == HICN_PUNT_UDP6_TYPE)
+         {
+           if (src_port != 0 && dst_port != 0)
+             ret =
+               hicn_punt_interest_data_for_udp (vm, &prefix, subnet_mask,
+                                                sw_if_index, type,
+                                                clib_host_to_net_u16
+                                                (src_port),
+                                                clib_host_to_net_u16
+                                                (dst_port));
+           else
+             return (clib_error_return
+                     (0,
+                      "Please specify valid source and destination udp port"));
+         }
+       else
+         {
+           ret =
+             hicn_punt_interest_data_for_ethernet (vm, &prefix, subnet_mask,
+                                                   sw_if_index, type);
+         }
+      }
+      break;
+    case HICN_MGMT_PUNTING_OP_DELETE:
+      {
+       if (sw_if_index != ~0)
+         {
+           ip46_address_is_ip4 (&prefix) ?
+             hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm,
+                                                              sw_if_index,
+                                                              0) :
+             hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm,
+                                                              sw_if_index,
+                                                              0);
+         }
+       else if (!(ip46_address_is_zero (&prefix)))
+         {
+           ret = ip46_address_is_ip4 (&prefix) ?
+             hicn_punt_remove_ip4_address (vm, &(prefix.ip4), subnet_mask, 1,
+                                           sw_if_index,
+                                           0) :
+             hicn_punt_remove_ip6_address (vm, (ip6_address_t *) & prefix,
+                                           subnet_mask, 1, sw_if_index, 0);
+         }
+      }
+      break;
+    default:
+      break;
+    }
+
+  return (ret == HICN_ERROR_NONE) ? 0 : clib_error_return (0,
+                                                          get_error_string
+                                                          (ret));
+}
+
+static clib_error_t *
+hicn_cli_mapme_command_fn (vlib_main_t * vm, unformat_input_t * main_input,
+                          vlib_cli_command_t * cmd)
+{
+  hicn_mgmt_mapme_op_e mapme_op = HICN_MGMT_MAPME_OP_NONE;
+  unsigned int subnet_mask = 0;
+  ip46_address_t prefix;
+  u32 sw_if_index = ~0;
+  int ret = 0;
+  vnet_main_t *vnm = NULL;
+
+  vnm = vnet_get_main ();
+
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "add"))
+       {
+         mapme_op = HICN_MGMT_MAPME_OP_CREATE;
+       }
+      else if (unformat (line_input, "delete"))
+       {
+         mapme_op = HICN_MGMT_MAPME_OP_DELETE;
+       }
+      else if (unformat (line_input, "intfc %U",
+                        unformat_vnet_sw_interface, vnm, &sw_if_index))
+       {;
+       }
+      else if (unformat
+              (line_input, "prefix %U/%d", unformat_ip46_address,
+               &prefix, IP46_TYPE_ANY, &subnet_mask))
+       {;
+       }
+      else
+       {
+         return (clib_error_return (0, "invalid option"));
+       }
+    }
+
+  if (mapme_op == HICN_MGMT_MAPME_OP_CREATE
+      && (ip46_address_is_zero (&prefix) || sw_if_index == ~0))
+    {
+      return (clib_error_return
+             (0, "Please specify valid prefix and interface"));
+    }
+  else if ((mapme_op == HICN_MGMT_MAPME_OP_DELETE) &&
+          ip46_address_is_zero (&prefix))
+    {
+      return (clib_error_return
+             (0, "Please specify valid prefix and optionally an interface"));
+    }
+  else if (mapme_op == HICN_MGMT_MAPME_OP_NONE)
+    {
+      return (clib_error_return
+             (0, "Please specify valid operation, add or delete"));
+    }
+  return (ret == HICN_ERROR_NONE) ? clib_error_return (0, "Punting %s",
+                                                      get_error_string (ret))
+    : clib_error_return (0, get_error_string (ret));
+}
+
+/*
+ * cli handler for 'pgen'
+ */
+static clib_error_t *
+hicn_cli_pgen_client_set_command_fn (vlib_main_t * vm,
+                                    unformat_input_t * main_input,
+                                    vlib_cli_command_t * cmd)
+{
+  hicn_main_t *sm = &hicn_main;
+  hicnpg_main_t *hpgm = &hicnpg_main;
+  ip46_address_t src_addr, hicn_name;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 sw_if_index = ~0;
+  u16 lifetime = 4000;
+  int rv = VNET_API_ERROR_UNIMPLEMENTED;
+  u32 max_seq = ~0;
+  u32 n_flows = ~0;
+  u32 mask = 0;
+  u32 n_ifaces = 1;
+  u32 hicn_underneath = ~0;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "fwd"))
+           {
+             if (unformat (line_input, "ip"))
+               hicn_underneath = 0;
+             else if (unformat (line_input, "hicn"))
+               hicn_underneath = 1;
+           }
+         if (unformat
+             (line_input, "intfc %U", unformat_vnet_sw_interface, vnm,
+              &sw_if_index))
+           {
+             ;
+           }
+         else if (unformat (line_input, "src %U",
+                            unformat_ip46_address, &src_addr))
+           {
+             ;
+           }
+         else if (unformat (line_input, "n_ifaces %d", &n_ifaces))
+           {
+             ;
+           }
+         else if (unformat (line_input, "name %U/%d",
+                            unformat_ip46_address, &hicn_name, IP46_TYPE_ANY,
+                            &mask))
+           {
+             ;
+           }
+         else if (unformat (line_input, "lifetime %d", &lifetime))
+           {
+             ;
+           }
+         else if (unformat (line_input, "max_seq %d", &max_seq))
+           {
+             ;
+           }
+         else if (unformat (line_input, "n_flows %d", &n_flows))
+           {
+             ;
+           }
+         else
+           {
+             return (clib_error_return
+                     (0, "Unknown input '%U'", format_unformat_error,
+                      line_input));
+             break;
+           }
+       }
+    }
+  hpgm->interest_lifetime = lifetime;
+
+  if (sw_if_index == ~0)
+    {
+      return (clib_error_return (0, "Packet generator interface missing"));
+    }
+  if (hicn_underneath == ~0)
+    {
+      return (clib_error_return
+             (0, "Choose the underlying forwarder type ip|hicn"));
+    }
+  else if (hicn_underneath && !sm->is_enabled)
+    {
+      return (clib_error_return (0, "hICN not enabled in VPP"));
+    }
+  else if (!hicn_underneath && sm->is_enabled)
+    {
+      return (clib_error_return (0, "hICN enabled in VPP"));
+    }
+
+  int skip = 1;
+  int base_offset = ETH_L2;
+  u8 use_current_data = HICN_CLASSIFY_NO_CURRENT_DATA_FLAG;
+
+  if (hicn_cli_is_ip_interface (vm, vnm, sw_if_index) == IP)
+    {
+      skip = 0;
+      base_offset = NO_L2;
+      use_current_data = HICN_CLASSIFY_CURRENT_DATA_FLAG;
+    }
+  /*
+   * Register punting on src address generated by pg and data punting
+   * on the name
+   */
+  if (ip46_address_is_ip4 (&src_addr) && ip46_address_is_ip4 (&hicn_name))
+    {
+      /* Add data node to the vpp graph */
+      u32 next_hit_node = vlib_node_add_next (vm,
+                                             hicn_punt_glb.
+                                             hicn_node_info.ip4_inacl_node_index,
+                                             hicn_pg_data_node.index);
+
+      /* Add pgen_client node to the vpp graph */
+      vlib_node_add_next (vm,
+                         pg_input_node.index, hicn_pg_interest_node.index);
+
+      /* Create the punting table if it does not exist */
+      hicn_punt_add_vnettbl (&ipv4, &ipv4_src, mask, ~0, sw_if_index,
+                            base_offset, use_current_data);
+      hicn_punt_add_vnettbl (&ipv4, &ipv4_dst, mask,
+                            hicn_punt_glb.ip4_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][mask], sw_if_index, base_offset,
+                            use_current_data);
+
+      /* Add a session to the table */
+      hicn_punt_add_vnetssn (&ipv4, &ipv4_src,
+                            &hicn_name, mask,
+                            next_hit_node, sw_if_index, base_offset);
+
+      hicn_punt_add_vnetssn (&ipv4, &ipv4_src,
+                            &hicn_name, mask,
+                            next_hit_node, sw_if_index, base_offset);
+
+      hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm, sw_if_index,
+                                                      OP_ENABLE);
+
+      pg_node_t *pn;
+      pn = pg_get_node (hicn_pg_interest_node.index);
+      pn->unformat_edit = unformat_pg_ip4_header;
+
+    }
+  else if (!ip46_address_is_ip4 (&src_addr)
+          && !ip46_address_is_ip4 (&hicn_name))
+    {
+      /* Add node to the vpp graph */
+      u32 next_hit_node = vlib_node_add_next (vm,
+                                             hicn_punt_glb.hicn_node_info.
+                                             ip6_inacl_node_index,
+                                             hicn_pg_data_node.index);
+
+      /* Add pgen_client node to the vpp graph */
+      vlib_node_add_next (vm, pg_input_node.index,
+                         hicn_pg_interest_node.index);
+
+      /* Create the punting table if it does not exist */
+      hicn_punt_add_vnettbl (&ipv6, &ipv6_src, mask, ~0, sw_if_index,
+                            base_offset, use_current_data);
+      hicn_punt_add_vnettbl (&ipv6, &ipv6_dst, mask,
+                            hicn_punt_glb.ip6_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][mask], sw_if_index, base_offset,
+                            use_current_data);
+
+      /* Add a session to the table */
+      hicn_punt_add_vnetssn (&ipv6, &ipv6_src,
+                            &hicn_name, mask,
+                            next_hit_node, sw_if_index, base_offset);
+
+      hicn_punt_add_vnetssn (&ipv6, &ipv6_src,
+                            &hicn_name, mask,
+                            next_hit_node, sw_if_index, base_offset);
+
+      hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm, sw_if_index,
+                                                      OP_ENABLE);
+
+      pg_node_t *pn;
+      pn = pg_get_node (hicn_pg_interest_node.index);
+      pn->unformat_edit = unformat_pg_ip6_header;
+    }
+  else
+    {
+      return (clib_error_return
+             (0,
+              "pg interface source address, source address and hicn name must be of the same type IPv4 or IPv6"));
+    }
+
+
+  hpgm->pgen_clt_src_addr = src_addr;
+  hpgm->pgen_clt_hicn_name = hicn_name;
+  hpgm->max_seq_number = max_seq;
+  hpgm->n_flows = n_flows;
+  hpgm->n_ifaces = n_ifaces;
+  hpgm->hicn_underneath = hicn_underneath;
+  vlib_cli_output (vm, "ifaces %d", hpgm->n_ifaces);
+  rv = 0;
+
+  switch (rv)
+    {
+    case 0:
+      break;
+
+    case VNET_API_ERROR_UNIMPLEMENTED:
+      return clib_error_return (0, "Unimplemented, NYI");
+      break;
+
+    default:
+      return clib_error_return (0, "hicn enable_disable returned %d", rv);
+    }
+
+  return 0;
+}
+
+/*
+ * cli handler for 'pgen'
+ */
+static clib_error_t *
+hicn_cli_pgen_server_set_command_fn (vlib_main_t * vm,
+                                    unformat_input_t * main_input,
+                                    vlib_cli_command_t * cmd)
+{
+  clib_error_t *cl_err;
+  int rv = HICN_ERROR_NONE;
+  hicnpg_server_main_t *pg_main = &hicnpg_server_main;
+  hicn_main_t *sm = &hicn_main;
+  ip46_address_t hicn_name;
+  u32 subnet_mask;
+  int payload_size = 0;
+  u32 sw_if_index = ~0;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 hicn_underneath = ~0;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      /* Parse the arguments */
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "fwd"))
+           {
+             if (unformat (line_input, "ip"))
+               hicn_underneath = 0;
+             else if (unformat (line_input, "hicn"))
+               hicn_underneath = 1;
+           }
+         if (unformat (line_input, "name %U/%d",
+                       unformat_ip46_address, &hicn_name, IP46_TYPE_ANY,
+                       &subnet_mask))
+           {;
+           }
+         else if (unformat (line_input, "size %d", &payload_size))
+           {
+             if (payload_size > 1440)
+               {
+                 return (clib_error_return (0,
+                                            "Payload size must be <= 1440 bytes..."));
+               }
+           }
+         else
+           if (unformat
+               (line_input, "intfc %U", unformat_vnet_sw_interface, vnm,
+                &sw_if_index))
+           {
+             ;
+           }
+         else
+           {
+             return (clib_error_return
+                     (0, "Unknown input '%U'", format_unformat_error,
+                      line_input));
+             break;
+           }
+       }
+    }
+  /* Attach our packet-gen node for ip4 udp local traffic */
+  if (payload_size == 0 || sw_if_index == ~0)
+    {
+      return clib_error_return (0,
+                               "Error: must supply local port, payload size and incoming interface");
+    }
+  if (hicn_underneath == ~0)
+    {
+      return (clib_error_return
+             (0, "Choose the underlying forwarder type ip|hicn"));
+    }
+  else if (hicn_underneath && !sm->is_enabled)
+    {
+      return (clib_error_return (0, "hICN not enabled in VPP"));
+    }
+  else if (!hicn_underneath && sm->is_enabled)
+    {
+      return (clib_error_return (0, "hICN enabled in VPP"));
+    }
+  pg_main->hicn_underneath = hicn_underneath;
+
+  /* Allocate the buffer with the actual content payload TLV */
+  vlib_buffer_alloc (vm, &pg_main->pgen_svr_buffer_idx, 1);
+  vlib_buffer_t *rb = NULL;
+  rb = vlib_get_buffer (vm, pg_main->pgen_svr_buffer_idx);
+
+  /* Initialize the buffer data with zeros */
+  memset (rb->data, 0, payload_size);
+  rb->current_length = payload_size;
+
+  int skip = 2;
+  int base_offset = ETH_L2;
+  u8 use_current_data = HICN_CLASSIFY_NO_CURRENT_DATA_FLAG;
+
+  if (hicn_cli_is_ip_interface (vm, vnm, sw_if_index) == IP)
+    {
+      skip = 1;
+      base_offset = NO_L2;
+      use_current_data = HICN_CLASSIFY_CURRENT_DATA_FLAG;
+    }
+  if (ip46_address_is_ip4 (&hicn_name))
+    {
+      /* Add node to the vpp graph */
+      u32 next_hit_node = vlib_node_add_next (vm,
+                                             hicn_punt_glb.
+                                             hicn_node_info.ip4_inacl_node_index,
+                                             hicn_pg_server_node.index);
+
+      /* Create the punting table if it does not exist */
+      hicn_punt_add_vnettbl (&ipv4, &ipv4_src, subnet_mask, ~0, sw_if_index,
+                            base_offset, use_current_data);
+      hicn_punt_add_vnettbl (&ipv4, &ipv4_dst, subnet_mask,
+                            hicn_punt_glb.ip4_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][subnet_mask - 1], sw_if_index,
+                            base_offset, use_current_data);
+
+
+      /* Add a session to the table */
+      hicn_punt_add_vnetssn (&ipv4, &ipv4_dst,
+                            (ip46_address_t *) & (hicn_name.ip4),
+                            subnet_mask, next_hit_node, sw_if_index,
+                            base_offset);
+
+      hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm, sw_if_index,
+                                                      OP_ENABLE);
+
+    }
+  else
+    {
+      /* Add node to the vpp graph */
+      u32 next_hit_node = vlib_node_add_next (vm,
+                                             hicn_punt_glb.hicn_node_info.
+                                             ip6_inacl_node_index,
+                                             hicn_pg_server_node.index);
+
+      /* Create the punting table if it does not exist */
+      hicn_punt_add_vnettbl (&ipv6, &ipv6_src, subnet_mask, ~0, sw_if_index,
+                            base_offset, use_current_data);
+      hicn_punt_add_vnettbl (&ipv6, &ipv6_dst, subnet_mask,
+                            hicn_punt_glb.ip6_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][subnet_mask - 1], sw_if_index,
+                            base_offset, use_current_data);
+
+
+      /* Add a session to the table */
+      hicn_punt_add_vnetssn (&ipv6, &ipv6_dst,
+                            (ip46_address_t *) & (hicn_name.ip6),
+                            subnet_mask, next_hit_node, sw_if_index,
+                            base_offset);
+
+      hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm, sw_if_index,
+                                                      OP_ENABLE);
+    }
+
+  switch (rv)
+    {
+    case 0:
+      cl_err = 0;
+      break;
+
+    case VNET_API_ERROR_UNIMPLEMENTED:
+      cl_err = clib_error_return (0, "Unimplemented, NYI");
+      break;
+
+    default:
+      cl_err = clib_error_return (0, "hicn pgen server returned %d", rv);
+    }
+
+  return cl_err;
+}
+
+/* cli declaration for 'control start' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND(hicn_cli_node_ctl_start_set_command, static)=
+{
+       .path = "hicn control start",
+        .short_help = "hicn control start",
+        .function = hicn_cli_node_ctl_start_set_command_fn,
+};
+
+
+/* cli declaration for 'control stop' */
+VLIB_CLI_COMMAND(hicn_cli_node_ctl_stop_set_command, static)=
+{
+       .path = "hicn control stop",
+        .short_help = "hicn control stop",
+        .function = hicn_cli_node_ctl_stop_set_command_fn,
+};
+
+
+/* cli declaration for 'control param' */
+VLIB_CLI_COMMAND(hicn_cli_node_ctl_param_set_command, static)=
+{
+       .path = "hicn control param",
+        .short_help = "hicn control param { pit { size <entries> | { dfltlife | minlife | maxlife } <seconds> } | fib size <entries> | cs {size <entries> | app <portion to reserved to app>} }\n",
+        .function = hicn_cli_node_ctl_param_set_command_fn,
+};
+
+/* cli declaration for 'control' (root path of multiple commands, for help) */
+VLIB_CLI_COMMAND(hicn_cli_node_ctl_command, static)=
+{
+       .path = "hicn control",
+        .short_help = "hicn control"
+};
+
+/* cli declaration for 'fib' */
+VLIB_CLI_COMMAND(hicn_cli_fib_set_command, static)=
+{
+       .path = "hicn fib",
+        .short_help = "hicn fib {{add | delete } prefix <prefix> face <faceid> }"
+        " | set strategy <strategy_id> prefix <prefix>",
+        .function = hicn_cli_fib_set_command_fn,
+};
+
+/* cli declaration for 'show' */
+VLIB_CLI_COMMAND(hicn_cli_show_command, static)=
+{
+       .path = "hicn show",
+        .short_help = "hicn show "
+        "[detail] [internal]"
+        "[strategies]",
+        .function = hicn_cli_show_command_fn,
+};
+
+/* cli declaration for 'punting' */
+VLIB_CLI_COMMAND(hicn_cli_punting_command, static)=
+{
+       .path = "hicn punting",
+        .short_help = "hicn punting {add|delete} prefix <ip_address/mask> intfc <interface> type <ip/udp>",
+        .function = hicn_cli_punting_command_fn,
+};
+
+VLIB_CLI_COMMAND(hicn_cli_mapme_command, static)=
+{
+       .path = "hicn mapme",
+        .short_help = "hicn mapme {enable|disable|set <param> <value>}",
+        .function = hicn_cli_mapme_command_fn,
+};
+
+/* cli declaration for 'hicn pgen client' */
+VLIB_CLI_COMMAND(hicn_cli_pgen_client_set_command, static)=
+{
+       .path = "hicn pgen client",
+        .short_help = "hicn pgen client fwd <ip|hicn> src <addr> n_ifaces <n_ifaces> name <addr/subnet> lifetime <interest-lifetime> intfc <data in-interface> max_seq <max sequence number> n_flows <number of flows>",
+        .long_help = "Run hicn in packet-gen client mode\n",
+        .function = hicn_cli_pgen_client_set_command_fn,
+};
+
+/* cli declaration for 'hicn pgen client' */
+VLIB_CLI_COMMAND(hicn_cli_pgen_server_set_command, static)=
+{
+       .path = "hicn pgen server",
+        .short_help = "hicn pgen server fwd <ip|hicn> name <addr/subnet> intfc <interest in-interface> size <payload_size>",
+        .long_help = "Run hicn in packet-gen server mode\n",
+        .function = hicn_cli_pgen_server_set_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/data_fwd.h b/hicn-plugin/src/data_fwd.h
new file mode 100755 (executable)
index 0000000..7390382
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_DATA_FWD_H__
+#define __HICN_DATA_FWD_H__
+
+#include <vlib/buffer.h>
+
+#include "pcs.h"
+
+/*
+ * Node context data; we think this is per-thread/instance
+ */
+typedef struct hicn_data_fwd_runtime_s
+{
+  vlib_combined_counter_main_t repm_counters;
+
+  /* per-cpu vector of cloned packets */
+  u32 **clones;
+} hicn_data_fwd_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u8 packet_data[64];
+} hicn_data_fwd_trace_t;
+
+typedef enum
+{
+  HICN_DATA_FWD_NEXT_V4_LOOKUP,
+  HICN_DATA_FWD_NEXT_V6_LOOKUP,
+  HICN_DATA_FWD_NEXT_ERROR_DROP,
+  HICN_DATA_FWD_N_NEXT,
+} hicn_data_fwd_next_t;
+
+/**
+ *@brief Create a maximum of 256 clones of buffer and store them
+ *   in the supplied array. Unlike the original function in the vlib
+ *   library, we don't prevent cloning if n_buffer==1 and if
+ *   s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2.
+ *
+ * @param vm - (vlib_main_t *) vlib main data structure pointer
+ * @param src_buffer - (u32) source buffer index
+ * @param buffers - (u32 * ) buffer index array
+ * @param n_buffers - (u16) number of buffer clones requested (<=256)
+ * @param head_end_offset - (u16) offset relative to current position
+ *          where packet head ends
+ * @return - (u16) number of buffers actually cloned, may be
+ *   less than the number requested or zero
+ */
+always_inline u16
+vlib_buffer_clone_256_2 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
+                        u16 n_buffers, u16 head_end_offset)
+{
+  u16 i;
+  vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
+
+  ASSERT (n_buffers);
+  ASSERT (n_buffers <= 256);
+
+  if (s->current_length <= CLIB_CACHE_LINE_BYTES * 2)
+    {
+      for (i = 0; i < n_buffers; i++)
+       {
+         vlib_buffer_t *d;
+         d = vlib_buffer_copy (vm, s);
+         clib_memcpy (d->opaque2, s->opaque2, sizeof (s->opaque2));
+         if (d == 0)
+           return i;
+         buffers[i] = vlib_get_buffer_index (vm, d);
+       }
+      s->current_data += head_end_offset;
+      s->current_length -= head_end_offset;
+      return n_buffers;
+    }
+  n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
+                                               vlib_buffer_get_free_list_index
+                                               (s));
+
+  for (i = 0; i < n_buffers; i++)
+    {
+      vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
+      d->current_data = s->current_data;
+      d->current_length = head_end_offset;
+      d->trace_index = s->trace_index;
+      vlib_buffer_set_free_list_index (d,
+                                      vlib_buffer_get_free_list_index (s));
+
+      d->total_length_not_including_first_buffer = s->current_length -
+       head_end_offset;
+      if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
+       {
+         d->total_length_not_including_first_buffer +=
+           s->total_length_not_including_first_buffer;
+       }
+      d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
+      d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
+      clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
+      clib_memcpy (d->opaque2, s->opaque2, sizeof (s->opaque2));
+      clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
+                  head_end_offset);
+      d->next_buffer = src_buffer;
+    }
+  vlib_buffer_advance (s, head_end_offset);
+  s->n_add_refs = n_buffers - 1;
+  while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
+    {
+      s = vlib_get_buffer (vm, s->next_buffer);
+      s->n_add_refs = n_buffers - 1;
+    }
+
+  return n_buffers;
+}
+
+/**
+ * @brief Create multiple clones of buffer and store them
+ *  in the supplied array. Unlike the function in the vlib library,
+ *   we allow src_buffer to have n_add_refs != 0.
+ *
+ * @param vm - (vlib_main_t *) vlib main data structure pointer
+ * @param src_buffer - (u32) source buffer index
+ * @param buffers - (u32 * ) buffer index array
+ * @param n_buffers - (u16) number of buffer clones requested (<=256)
+ * @param head_end_offset - (u16) offset relative to current position
+ *   where packet head ends
+ * @return - (u16) number of buffers actually cloned, may be
+ *   less than the number requested or zero
+ */
+always_inline u16
+vlib_buffer_clone2 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
+                   u16 n_buffers, u16 head_end_offset)
+{
+  ASSERT (head_end_offset >= VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+
+  vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
+
+  /*
+   * total_length_not_including_first_buffer is not initialized to 0
+   * when a buffer is used.
+   */
+  if (PREDICT_TRUE (s->next_buffer == 0))
+    s->total_length_not_including_first_buffer = 0;
+
+  u16 n_cloned = 0;
+  u8 n_clone_src = 255 - s->n_add_refs;
+
+  /*
+   * We need to copy src for all the clones that cannot be chained in
+   * the src_buffer
+   */
+  /* MAX(n_add_refs) = 256 */
+  if (n_buffers > n_clone_src)
+    {
+      vlib_buffer_t *copy;
+      /* Ok to call the original vlib_buffer_copy. */
+      copy = vlib_buffer_copy (vm, s);
+      n_cloned += vlib_buffer_clone (vm,
+                                    vlib_get_buffer_index (vm, copy),
+                                    buffers,
+                                    n_buffers - n_clone_src,
+                                    head_end_offset);
+      n_buffers -= n_cloned;
+    }
+  /*
+   * vlib_buffer_clone_256 check if n_add_refs is 0. We force it to be
+   * 0 before calling the function and we retore it to the right value
+   * after the function has been called
+   */
+  u8 tmp_n_add_refs = s->n_add_refs;
+
+  s->n_add_refs = 0;
+  /*
+   * The regular vlib_buffer_clone_256 does copy if we need to clone
+   * only one packet. While this is not a problem per se, it adds
+   * complexity to the code, especially because we need to add 1 to
+   * n_add_refs when the packet is cloned.
+   */
+  n_cloned += vlib_buffer_clone_256_2 (vm,
+                                      src_buffer,
+                                      (buffers + n_cloned),
+                                      n_buffers, head_end_offset);
+
+  s->n_add_refs += tmp_n_add_refs;
+
+  return n_cloned;
+}
+
+#endif /* //__HICN_DATA_FWD_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/data_fwd_node.c b/hicn-plugin/src/data_fwd_node.c
new file mode 100755 (executable)
index 0000000..088683f
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/dpo/dpo.h>
+
+#include "data_fwd.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "infra.h"
+#include "strategy.h"
+#include "strategy_dpo_manager.h"
+#include "state.h"
+#include "error.h"
+
+/* Stats string values */
+static char *hicn_data_fwd_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* Declarations */
+always_inline void
+drop_packet (vlib_main_t * vm, u32 bi0,
+            u32 * n_left_to_next, u32 * next0, u32 ** to_next,
+            u32 * next_index, vlib_node_runtime_t * node);
+
+always_inline int
+hicn_satisfy_faces (vlib_main_t * vm, u32 b0,
+                   hicn_pcs_entry_t * pitp, u32 * n_left_to_next,
+                   u32 ** to_next, u32 * next_index,
+                   vlib_node_runtime_t * node, u8 isv6,
+                   vl_api_hicn_api_node_stats_get_reply_t * stats);
+
+always_inline void
+clone_data_to_cs (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                 hicn_pcs_entry_t * pitp, hicn_header_t * hicn0, f64 tnow,
+                 hicn_hash_node_t * nodep, vlib_buffer_t * b0,
+                 hicn_hash_entry_t * hash_entry, u64 name_hash,
+                 hicn_buffer_t * hicnb, const hicn_dpo_vft_t * dpo_vft,
+                 dpo_id_t * hicn_dpo_id);
+
+
+/* packet trace format function */
+always_inline u8 *hicn_data_fwd_format_trace (u8 * s, va_list * args);
+
+vlib_node_registration_t hicn_data_fwd_node;
+
+/*
+ * ICN forwarder node for interests: handling of Data delivered based on ACL.
+ * - 1 packet at a time - ipv4/tcp ipv6/tcp
+ */
+static uword
+hicn_data_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                  vlib_frame_t * frame)
+{
+
+  u32 n_left_from, *from, *to_next;
+  hicn_data_fwd_next_t next_index;
+  hicn_pit_cs_t *pitcs = &hicn_main.pitcs;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  f64 tnow;
+  u32 data_received = 1;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  /* Capture time in vpp terms */
+  tnow = vlib_time_now (vm);
+
+  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 > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         u32 bi0;
+         u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         hicn_buffer_t *hicnb0;
+         hicn_hash_node_t *node0;
+         const hicn_strategy_vft_t *strategy_vft0;
+         const hicn_dpo_vft_t *dpo_vft0;
+         u8 dpo_ctx_id0;
+         hicn_pcs_entry_t *pitp;
+         hicn_hash_entry_t *hash_entry0;
+         int ret = HICN_ERROR_NONE;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE);
+
+             /* HICN PREFETCH */
+             hicn_buffer_t *hicnb1 = hicn_get_buffer (b1);
+             hicn_prefetch_pcs_entry (hicnb1, pitcs);
+           }
+         /* Dequeue a packet buffer */
+         /*
+          * Do not copy the index in the next buffer, we'll do
+          * it later. The packet might be cloned, so the buffer to move
+          * to next must be the cloned one
+          */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         /* Get hicn buffer and state */
+         hicnb0 = hicn_get_buffer (b0);
+         hicn_get_internal_state (hicnb0, pitcs, &node0, &strategy_vft0,
+                                  &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
+
+         ret = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         pitp = hicn_pit_get_data (node0);
+         nameptr = (u8 *) (&name);
+
+         if (PREDICT_FALSE
+             (ret != HICN_ERROR_NONE
+              || !hicn_node_compare (nameptr, namelen, node0)
+              || (hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)))
+           {
+             /*
+              * Remove the lock acquired from
+              * data_pcslookup node
+              */
+             dpo_id_t hicn_dpo_id0 = { dpo_vft0->hicn_dpo_get_type (), 0, 0,
+               dpo_ctx_id0
+             };
+             hicn_pcs_remove_lock (pitcs, &pitp, &node0, vm,
+                                   hash_entry0, dpo_vft0, &hicn_dpo_id0);
+
+             drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next,
+                          &next_index, node);
+
+             goto end_processing;
+           }
+         /*
+          * Check if the hit is instead a collision in the
+          * hash table. Unlikely to happen.
+          */
+         /*
+          * there is no guarantee that the type of entry has
+          * not changed from the lookup.
+          */
+
+         if (tnow > pitp->shared.expire_time)
+           {
+             dpo_id_t hicn_dpo_id0 =
+               { dpo_vft0->hicn_dpo_get_type (), 0, 0, dpo_ctx_id0 };
+             hicn_pcs_delete (pitcs, &pitp, &node0, vm, hash_entry0,
+                              dpo_vft0, &hicn_dpo_id0);
+
+             drop_packet (vm, bi0, &n_left_to_next, &next0, &to_next,
+                          &next_index, node);
+             stats.pit_expired_count++;
+           }
+         else
+           {
+             ASSERT ((hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_DELETED)
+                     == 0);
+
+             data_received++;
+             /*
+              * We do not check if the data is coming from
+              * the outgoing interest face.
+              */
+
+             /* Prepare the buffer for the cloning */
+             ret = hicn_satisfy_faces (vm, bi0, pitp, &n_left_to_next,
+                                       &to_next, &next_index, node,
+                                       isv6, &stats);
+
+             dpo_id_t hicn_dpo_id0 = { dpo_vft0->hicn_dpo_get_type (), 0, 0,
+               dpo_ctx_id0
+             };
+
+             if (PREDICT_FALSE (ret != HICN_ERROR_NONE))
+               {
+                 hicn_pcs_pit_delete (pitcs, &pitp, &node0, vm,
+                                      hash_entry0, dpo_vft0, &hicn_dpo_id0);
+                 continue;
+               }
+             /*
+              * Call the strategy callback since the
+              * interest has been satisfied
+              */
+             strategy_vft0->hicn_receive_data (dpo_ctx_id0,
+                                               pitp->u.pit.pe_txnh);
+
+#if HICN_FEATURE_CS
+             /*
+              * Clone data packet in the content store and
+              * convert the PIT entry into a CS entry
+              */
+             clone_data_to_cs (vm, pitcs, pitp, hicn0, tnow, node0,
+                               b0, hash_entry0, hicnb0->name_hash, hicnb0,
+                               dpo_vft0, &hicn_dpo_id0);
+
+             hicn_pcs_remove_lock (pitcs, &pitp, &node0, vm,
+                                   hash_entry0, NULL, NULL);
+#else
+             ASSERT (pitp == hicn_pit_get_data (node0));
+             /*
+              * Remove one reference as the buffer is no
+              * longer in any frame
+              */
+             b0->n_add_refs--;
+             /* If not enabled, delete the PIT entry */
+             hicn_pcs_pit_delete (pitcs, &pitp, &node0, vm,
+                                  hash_entry0, dpo_vft0, &hicn_dpo_id0);
+#endif
+           }
+       end_processing:
+
+         /* Incr packet counter */
+         stats.pkts_processed += 1;
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+  u32 pit_int_count = hicn_pit_get_int_count (pitcs);
+  u32 pit_cs_count = hicn_pit_get_cs_count (pitcs);
+
+  vlib_node_increment_counter (vm, hicn_data_fwd_node.index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+
+  update_node_counter (vm, hicn_data_fwd_node.index,
+                      HICNFWD_ERROR_INT_COUNT, pit_int_count);
+  update_node_counter (vm, hicn_data_fwd_node.index,
+                      HICNFWD_ERROR_CS_COUNT, pit_cs_count);
+  update_node_counter (vm, hicn_data_fwd_node.index,
+                      HICNFWD_ERROR_INTEREST_AGG_ENTRY,
+                      stats.pkts_data_count / data_received);
+
+  return (frame->n_vectors);
+}
+
+always_inline void
+drop_packet (vlib_main_t * vm, u32 bi0,
+            u32 * n_left_to_next, u32 * next0, u32 ** to_next,
+            u32 * next_index, vlib_node_runtime_t * node)
+{
+  *next0 = HICN_DATA_FWD_NEXT_ERROR_DROP;
+
+  (*to_next)[0] = bi0;
+  *to_next += 1;
+  *n_left_to_next -= 1;
+
+  vlib_validate_buffer_enqueue_x1 (vm, node, *next_index,
+                                  *to_next, *n_left_to_next, bi0, *next0);
+}
+
+always_inline int
+hicn_satisfy_faces (vlib_main_t * vm, u32 bi0,
+                   hicn_pcs_entry_t * pitp, u32 * n_left_to_next,
+                   u32 ** to_next, u32 * next_index,
+                   vlib_node_runtime_t * node, u8 isv6,
+                   vl_api_hicn_api_node_stats_get_reply_t * stats)
+{
+  int found = 0;
+  int ret = HICN_ERROR_NONE;
+  u32 *clones = NULL, *header = NULL;
+  u32 n_left_from = 0;
+  u32 next0 = HICN_DATA_FWD_NEXT_ERROR_DROP, next1 =
+    HICN_DATA_FWD_NEXT_ERROR_DROP;
+
+  /*
+   * We have a hard limit on the number of vlib_buffer that we can
+   * chain (no more than 256)
+   */
+  /*
+   * The first group of vlib_buffer can be directly cloned from b0. We
+   * need to be careful to clone it only 254 times as the buffer
+   * already has n_add_reds=1.
+   */
+  vec_alloc (clones, pitp->u.pit.faces.n_faces);
+  header = clones;
+
+  /* Clone bi0 */
+  vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
+
+  /* Add one reference to maintain the buffer in the CS */
+  b0->n_add_refs++;
+  found = n_left_from =
+    vlib_buffer_clone2 (vm, bi0, clones, pitp->u.pit.faces.n_faces,
+                       VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+
+  ASSERT (n_left_from == pitp->u.pit.faces.n_faces);
+
+  /* Index to iterate over the faces */
+  int i = 0;
+
+  while (n_left_from > 0)
+    {
+
+      //Dual loop, X2
+      while (n_left_from >= 4 && *n_left_to_next >= 2)
+       {
+         vlib_buffer_t *h0, *h1;
+         u32 hi0, hi1;
+         dpo_id_t *face0, *face1;
+
+         /* Prefetch for next iteration. */
+         {
+           vlib_buffer_t *h2, *h3;
+           h2 = vlib_get_buffer (vm, clones[2]);
+           h3 = vlib_get_buffer (vm, clones[3]);
+           CLIB_PREFETCH (h2, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (h3, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+         }
+
+         face0 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces);
+         face1 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces);
+
+         h0 = vlib_get_buffer (vm, clones[0]);
+         h1 = vlib_get_buffer (vm, clones[1]);
+
+         (*to_next)[0] = hi0 = clones[0];
+         (*to_next)[1] = hi1 = clones[1];
+         *to_next += 2;
+         *n_left_to_next -= 2;
+         n_left_from -= 2;
+         clones += 2;
+
+         next0 = face0->dpoi_next_node;
+         next1 = face1->dpoi_next_node;
+         vnet_buffer (h0)->ip.adj_index[VLIB_TX] = face0->dpoi_index;
+         vnet_buffer (h1)->ip.adj_index[VLIB_TX] = face1->dpoi_index;
+
+         stats->pkts_data_count += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (h0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_fwd_trace_t *t =
+               vlib_add_trace (vm, node, h0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+             clib_memcpy (t->packet_data,
+                          vlib_buffer_get_current (h0),
+                          sizeof (t->packet_data));
+           }
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (h1->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_fwd_trace_t *t =
+               vlib_add_trace (vm, node, h1, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (h1)->sw_if_index[VLIB_RX];
+             t->next_index = next1;
+             clib_memcpy (t->packet_data,
+                          vlib_buffer_get_current (h1),
+                          sizeof (t->packet_data));
+           }
+         vlib_validate_buffer_enqueue_x2 (vm, node, *next_index,
+                                          *to_next, *n_left_to_next,
+                                          hi0, hi1, next0, next1);
+       }
+
+
+      while (n_left_from > 0 && *n_left_to_next > 0)
+       {
+         vlib_buffer_t *h0;
+         u32 hi0;
+         dpo_id_t *face0;
+
+         face0 = hicn_face_db_get_dpo_face (i++, &pitp->u.pit.faces);
+
+         h0 = vlib_get_buffer (vm, clones[0]);
+
+         (*to_next)[0] = hi0 = clones[0];
+         *to_next += 1;
+         *n_left_to_next -= 1;
+         n_left_from -= 1;
+         clones += 1;
+         next0 = face0->dpoi_next_node;
+         vnet_buffer (h0)->ip.adj_index[VLIB_TX] = face0->dpoi_index;
+
+         stats->pkts_data_count++;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (h0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_fwd_trace_t *t =
+               vlib_add_trace (vm, node, h0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (h0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+             clib_memcpy (t->packet_data,
+                          vlib_buffer_get_current (h0),
+                          sizeof (t->packet_data));
+           }
+         /*
+          * Verify speculative enqueue, maybe switch current
+          * next frame
+          */
+         /*
+          * Fix in case of a wrong speculation. Needed to
+          * clone the data in the right frame
+          */
+         vlib_validate_buffer_enqueue_x1 (vm, node, *next_index,
+                                          *to_next, *n_left_to_next,
+                                          hi0, next0);
+
+       }
+
+      /* Ensure that there is space for the next clone (if any) */
+      if (PREDICT_FALSE (*n_left_to_next == 0))
+       {
+         vlib_put_next_frame (vm, node, *next_index, *n_left_to_next);
+
+         vlib_get_next_frame (vm, node, *next_index, *to_next,
+                              *n_left_to_next);
+       }
+    }
+
+
+  vec_free (header);
+
+  if (PREDICT_FALSE (!found))
+    {
+      ASSERT (0);
+      drop_packet (vm, bi0, n_left_to_next, &next0, to_next, next_index,
+                  node);
+      ret = HICN_ERROR_FACE_NOT_FOUND;
+    }
+  return ret;
+}
+
+always_inline void
+clone_data_to_cs (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                 hicn_pcs_entry_t * pitp, hicn_header_t * hicn0, f64 tnow,
+                 hicn_hash_node_t * nodep, vlib_buffer_t * b0,
+                 hicn_hash_entry_t * hash_entry, u64 name_hash,
+                 hicn_buffer_t * hicnb, const hicn_dpo_vft_t * dpo_vft,
+                 dpo_id_t * hicn_dpo_id)
+{
+  hicn_lifetime_t dmsg_lifetime;
+  /*
+   * At this point we think we're safe to proceed. Store the CS buf in
+   * the PIT/CS hashtable entry
+   */
+
+  /*
+   * Start turning the PIT into a CS. Note that we may be stepping on
+   * the PIT part of the union as we update the CS part, so don't
+   * expect the PIT part to be valid after this point.
+   */
+  hicn_buffer_t *hicnb0 = hicn_get_buffer (b0);
+  hicn_pit_to_cs (vm, pitcs, pitp, hash_entry, nodep, dpo_vft, hicn_dpo_id,
+                 &hicnb->face_dpo_id, hicnb0->is_appface);
+
+  pitp->shared.create_time = tnow;
+
+  hicn_type_t type = hicnb0->type;
+  hicn_ops_vft[type.l1]->get_lifetime (type, &hicn0->protocol,
+                                      &dmsg_lifetime);
+
+  if (dmsg_lifetime < HICN_PARAM_CS_LIFETIME_MIN
+      || dmsg_lifetime > HICN_PARAM_CS_LIFETIME_MAX)
+    {
+      dmsg_lifetime = HICN_PARAM_CS_LIFETIME_DFLT;
+    }
+  pitp->shared.expire_time = hicn_pcs_get_exp_time (tnow, dmsg_lifetime);
+
+  /* Store the original packet buffer in the CS node */
+  pitp->u.cs.cs_pkt_buf = vlib_get_buffer_index (vm, b0);
+}
+
+/* packet trace format function */
+always_inline u8 *
+hicn_data_fwd_format_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 *);
+  hicn_data_fwd_trace_t *t = va_arg (*args, hicn_data_fwd_trace_t *);
+  u32 indent = format_get_indent (s);
+
+  s = format (s, "DATAFWD: pkt: %d, sw_if_index %d, next index %d\n",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+
+  s = format (s, "%U%U", format_white_space, indent,
+             format_ip6_header, t->packet_data, sizeof (t->packet_data));
+  return (s);
+}
+
+/*
+ * Node registration for the data forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_data_fwd_node) =
+{
+  .function = hicn_data_node_fn,
+  .name = "hicn-data-fwd",
+  .vector_size = sizeof(u32),
+  .runtime_data_bytes = sizeof(hicn_data_fwd_runtime_t),
+  .format_trace = hicn_data_fwd_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_data_fwd_error_strings),
+  .error_strings = hicn_data_fwd_error_strings,
+  .n_next_nodes = HICN_DATA_FWD_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes = {
+    [HICN_DATA_FWD_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICN_DATA_FWD_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICN_DATA_FWD_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/data_pcslookup.h b/hicn-plugin/src/data_pcslookup.h
new file mode 100755 (executable)
index 0000000..fa75c3a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_DATA_PCSLOOKUP_H__
+#define __HICN_DATA_PCSLOOKUP_H__
+
+#include "pcs.h"
+
+/*
+ * Node context data; we think this is per-thread/instance
+ */
+typedef struct hicn_data_pcslookup_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_data_pcslookup_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_data_pcslookup_trace_t;
+
+typedef enum
+{
+  HICN_DATA_PCSLOOKUP_NEXT_V4_LOOKUP,
+  HICN_DATA_PCSLOOKUP_NEXT_V6_LOOKUP,
+  HICN_DATA_PCSLOOKUP_NEXT_STORE_DATA,
+  HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD,   /* This must be one position
+                                        * before the error drop!! */
+  HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP,
+  HICN_DATA_PCSLOOKUP_N_NEXT,
+} hicn_data_pcslookup_next_t;
+
+#endif /* //__HICN_DATA_PCSLOOKUP_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/data_pcslookup_node.c b/hicn-plugin/src/data_pcslookup_node.c
new file mode 100755 (executable)
index 0000000..2225451
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2017-2019 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 "data_pcslookup.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "infra.h"
+#include "strategy.h"
+#include "strategy_dpo_manager.h"
+#include "state.h"
+
+/* Stats string values */
+static char *hicn_data_pcslookup_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* packet trace format function */
+always_inline u8 *hicn_data_pcslookup_format_trace (u8 * s, va_list * args);
+
+vlib_node_registration_t hicn_data_pcslookup_node;
+
+/*
+ * hICN node for handling data. It performs a lookup in the PIT.
+ */
+static uword
+hicn_data_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                            vlib_frame_t * frame)
+{
+
+  u32 n_left_from, *from, *to_next;
+  hicn_data_pcslookup_next_t next_index;
+  hicn_data_pcslookup_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  rt = vlib_node_get_runtime_data (vm, node->node_index);
+
+  if (PREDICT_FALSE (rt->pitcs == NULL))
+    {
+      rt->pitcs = &hicn_main.pitcs;
+    }
+  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 > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         hicn_buffer_t *hb0;
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         u32 bi0;
+         u32 next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP;
+         u64 name_hash = 0;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         u32 node_id0 = 0;
+         u8 dpo_ctx_id0 = 0;
+         int ret0;
+         u8 vft_id0;
+         u8 is_cs0;
+         u8 hash_entry_id = 0;
+         u8 bucket_is_overflown = 0;
+         u32 bucket_id = ~0;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             //Prefetch one cache line-- 64 byte-- so that we load the hicn_buffer_t as well
+             CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD);
+           }
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+
+         b0 = vlib_get_buffer (vm, bi0);
+         hb0 = hicn_get_buffer (b0);
+
+         /* Incr packet counter */
+         stats.pkts_processed += 1;
+
+         ret0 = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+
+         if (PREDICT_TRUE (ret0 == HICN_ERROR_NONE))
+           {
+             next0 =
+               isv6 ? HICN_DATA_PCSLOOKUP_NEXT_V6_LOOKUP :
+               HICN_DATA_PCSLOOKUP_NEXT_V4_LOOKUP;
+           }
+         nameptr = (u8 *) (&name);
+         if (PREDICT_FALSE
+             (ret0 != HICN_ERROR_NONE
+              || hicn_hashtb_fullhash (nameptr, namelen,
+                                       &name_hash) != HICN_ERROR_NONE))
+           {
+             next0 = HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP;
+           }
+         else
+           {
+             int res =
+               hicn_hashtb_lookup_node (rt->pitcs->pcs_table, nameptr,
+                                        namelen, name_hash,
+                                        !(hb0->is_appface) /* take lock */ ,
+                                        &node_id0, &dpo_ctx_id0, &vft_id0,
+                                        &is_cs0,
+                                        &hash_entry_id, &bucket_id,
+                                        &bucket_is_overflown);
+
+             stats.pkts_data_count += 1;
+
+             if ((res == HICN_ERROR_HASHTB_HASH_NOT_FOUND
+                  || (res == HICN_ERROR_NONE && is_cs0))
+                 && (hb0->is_appface))
+               {
+                 next0 = HICN_DATA_PCSLOOKUP_NEXT_STORE_DATA;
+               }
+             else if (res == HICN_ERROR_NONE)
+               {
+                 /*
+                  * In case the result of the lookup
+                  * is a CS entry, the packet is
+                  * dropped
+                  */
+                 next0 = HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD + is_cs0;
+               }
+           }
+
+         hicn_store_internal_state (b0, name_hash, node_id0, dpo_ctx_id0,
+                                    vft_id0, hash_entry_id, bucket_id,
+                                    bucket_is_overflown);
+
+         /*
+          * Verify speculative enqueue, maybe switch current
+          * next frame
+          */
+         /*
+          * Fix in case of a wrong speculation. Needed to
+          * clone the data in the right frame
+          */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, next0);
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_pcslookup_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+           }
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+  /* Check the CS LRU, and trim if necessary. */
+  u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs);
+  u32 pit_cs_count = hicn_pit_get_cs_count (rt->pitcs);
+
+  vlib_node_increment_counter (vm, hicn_data_pcslookup_node.index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+
+  vlib_node_increment_counter (vm, hicn_data_pcslookup_node.index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  update_node_counter (vm, hicn_data_pcslookup_node.index,
+                      HICNFWD_ERROR_INT_COUNT, pit_int_count);
+  update_node_counter (vm, hicn_data_pcslookup_node.index,
+                      HICNFWD_ERROR_CS_COUNT, pit_cs_count);
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_data_pcslookup_format_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 *);
+  hicn_data_pcslookup_trace_t *t =
+    va_arg (*args, hicn_data_pcslookup_trace_t *);
+
+  s = format (s, "DATA-PCSLOOKUP: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the data forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_data_pcslookup_node) =
+{
+  .function = hicn_data_pcslookup_node_fn,
+  .name = "hicn-data-pcslookup",
+  .vector_size = sizeof (u32),
+  .runtime_data_bytes = sizeof (hicn_data_pcslookup_runtime_t),
+  .format_trace = hicn_data_pcslookup_format_trace,
+  .type =  VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_data_pcslookup_error_strings),
+  .error_strings = hicn_data_pcslookup_error_strings,
+  .n_next_nodes = HICN_DATA_PCSLOOKUP_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_DATA_PCSLOOKUP_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICN_DATA_PCSLOOKUP_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICN_DATA_PCSLOOKUP_NEXT_STORE_DATA] = "hicn-data-push",
+    [HICN_DATA_PCSLOOKUP_NEXT_DATA_FWD] = "hicn-data-fwd",
+    [HICN_DATA_PCSLOOKUP_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/data_push_node.c b/hicn-plugin/src/data_push_node.c
new file mode 100755 (executable)
index 0000000..a4a25e2
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "hicn.h"
+#include "parser.h"
+#include "strategy_dpo_ctx.h"
+#include "infra.h"
+#include "mgmt.h"
+#include "pcs.h"
+
+/*
+ * Node context data (to be used in all the strategy nodes); we think this is
+ * per-thread/instance
+ */
+typedef struct hicn_data_push_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_data_push_runtime_t;
+
+/* Stats string values */
+static char *hicn_data_push_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+typedef enum
+{
+  HICN_DATA_PUSH_NEXT_ERROR_DROP,
+  HICN_DATA_PUSH_N_NEXT,
+} hicn_data_push_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u8 packet_data[40];
+} hicn_data_push_trace_t;
+
+vlib_node_registration_t hicn_data_push_node;
+
+always_inline void
+prep_buffer_for_cs (vlib_main_t * vm, vlib_buffer_t * b0, u8 isv6)
+{
+  if (isv6)
+    {
+      /* Advance the vlib buffer to the beginning of the TCP header */
+      vlib_buffer_advance (b0, sizeof (ip6_header_t) + sizeof (tcp_header_t));
+      b0->total_length_not_including_first_buffer = 0;
+    }
+  else
+    {
+      /* Advance the vlib buffer to the beginning of the TCP header */
+      vlib_buffer_advance (b0, sizeof (ip4_header_t) + sizeof (tcp_header_t));
+      b0->total_length_not_including_first_buffer = 0;
+    }
+}
+
+always_inline int
+hicn_new_data (vlib_main_t * vm, hicn_data_push_runtime_t * rt,
+              vlib_buffer_t * b0, u32 * next, f64 tnow, u8 * nameptr,
+              u16 namelen, u8 isv6)
+{
+  int ret;
+  hicn_hash_node_t *nodep;
+  hicn_pcs_entry_t *pitp;
+  hicn_header_t *hicn0;
+  hicn_buffer_t *hicnb0 = hicn_get_buffer (b0);
+  u32 node_id0 = 0;
+  u8 dpo_ctx_id0 = 0;
+  u8 vft_id0 = 0;
+  u8 is_cs0 = 0;
+  u8 hash_entry_id = 0;
+  u32 bucket_id = ~0;
+  u8 bucket_is_overflow = 0;
+  hicn_lifetime_t dmsg_lifetime;
+
+  /* Create PIT node and init PIT entry */
+  nodep = hicn_hashtb_alloc_node (rt->pitcs->pcs_table);
+  if (PREDICT_FALSE (nodep == NULL))
+    {
+      /* Nothing we can do - no mem */
+      *next = HICN_DATA_PUSH_NEXT_ERROR_DROP;
+      return HICN_ERROR_HASHTB_NOMEM;
+    }
+  pitp = hicn_pit_get_data (nodep);
+  hicn_pit_init_data (pitp);
+  pitp->shared.create_time = tnow;
+
+  hicn0 = vlib_buffer_get_current (b0);
+
+  hicn_type_t type = hicnb0->type;
+  hicn_ops_vft[type.l1]->get_lifetime (type, &hicn0->protocol,
+                                      &dmsg_lifetime);
+
+  if (dmsg_lifetime < HICN_PARAM_CS_LIFETIME_MIN
+      || dmsg_lifetime > HICN_PARAM_CS_LIFETIME_MAX)
+    {
+      dmsg_lifetime = HICN_PARAM_CS_LIFETIME_DFLT;
+    }
+  pitp->shared.expire_time = hicn_pcs_get_exp_time (tnow, dmsg_lifetime);
+  prep_buffer_for_cs (vm, b0, isv6);
+
+  /* Store the original packet buffer in the CS node */
+  pitp->u.cs.cs_pkt_buf = vlib_get_buffer_index (vm, b0);
+
+  pitp->u.cs.cs_rxface = hicnb0->face_dpo_id;
+
+  /* Set up the hash node and insert it */
+  hicn_hashtb_init_node (rt->pitcs->pcs_table, nodep, nameptr, namelen);
+
+
+  nodep->hn_flags |= HICN_HASH_NODE_CS_FLAGS;
+  pitp->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG;
+
+  hicn_hash_entry_t *hash_entry;
+  ret =
+    hicn_pcs_cs_insert_update (vm, rt->pitcs, pitp, nodep, &hash_entry,
+                              hicnb0->name_hash, &node_id0, &dpo_ctx_id0,
+                              &vft_id0, &is_cs0, &hash_entry_id, &bucket_id,
+                              &bucket_is_overflow);
+
+  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY;
+  if (ret != HICN_ERROR_NONE)
+    {
+      hicn_hashtb_free_node (rt->pitcs->pcs_table, nodep);
+    }
+  return (ret);
+
+}
+
+/*
+ * ICN strategy later node for interests: - 1 packet at a time - ipv4/tcp
+ * ipv6/tcp
+ */
+uword
+hicn_data_push_fn (vlib_main_t * vm,
+                  vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+
+  u32 n_left_from, *from, *to_next, n_left_to_next;
+  hicn_data_push_next_t next_index;
+  hicn_data_push_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  f64 tnow;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = (hicn_data_push_next_t) node->cached_next_index;
+  rt = vlib_node_get_runtime_data (vm, hicn_data_push_node.index);
+  rt->pitcs = &hicn_main.pitcs;
+  /* Capture time in vpp terms */
+  tnow = vlib_time_now (vm);
+
+  while (n_left_from > 0)
+    {
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         u8 isv6_0, isv6_1;
+         u8 *nameptr0, *nameptr1;
+         u16 namelen0, namelen1;
+         hicn_name_t name0, name1;
+         hicn_header_t *hicn0, *hicn1;
+         vlib_buffer_t *b0, *b1;
+         u32 bi0, bi1;
+         u32 next0 = next_index, next1 = next_index;
+         int ret0, ret1;
+
+         /* Prefetch for next iteration. */
+         {
+           vlib_buffer_t *b2, *b3;
+           b2 = vlib_get_buffer (vm, from[2]);
+           b3 = vlib_get_buffer (vm, from[3]);
+           CLIB_PREFETCH (b2, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+           CLIB_PREFETCH (b3, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+           CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES, STORE);
+         }
+
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         bi1 = from[1];
+         from += 2;
+         n_left_from -= 2;
+         /* to_next[0] = bi0; */
+         /* to_next[1] = bi1; */
+         /* to_next += 2; */
+         /* n_left_to_next -= 2; */
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+         next0 = next1 = HICN_DATA_PUSH_NEXT_ERROR_DROP;
+
+         ret0 = hicn_data_parse_pkt (b0, &name0, &namelen0, &hicn0, &isv6_0);
+         ret1 = hicn_data_parse_pkt (b1, &name1, &namelen1, &hicn1, &isv6_1);
+
+         nameptr0 = (u8 *) (&name0);
+         nameptr1 = (u8 *) (&name1);
+         if (PREDICT_TRUE (ret0 == HICN_ERROR_NONE))
+           hicn_new_data (vm, rt, b0, &next0, tnow, nameptr0, namelen0,
+                          isv6_0);
+
+         if (PREDICT_TRUE (ret1 == HICN_ERROR_NONE))
+           hicn_new_data (vm, rt, b1, &next1, tnow, nameptr1, namelen1,
+                          isv6_1);
+         stats.pkts_data_count += 2;
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_push_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];;
+             t->next_index = next0;
+           }
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b1->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_push_trace_t *t =
+               vlib_add_trace (vm, node, b1, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];;
+             t->next_index = next0;
+           }
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         vlib_buffer_t *b0;
+         u32 bi0;
+         u32 next0 = next_index;
+         int ret0;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             //hicn_buffer_t * hicnb1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE);
+           }
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         next0 = HICN_DATA_PUSH_NEXT_ERROR_DROP;
+
+         ret0 = hicn_data_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         nameptr = (u8 *) (&name);
+
+         if (PREDICT_TRUE (ret0 == HICN_ERROR_NONE))
+           hicn_new_data (vm, rt, b0, &next0, tnow, nameptr, namelen, isv6);
+         stats.pkts_data_count++;
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_data_push_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];;
+             t->next_index = next0;
+           }
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, hicn_data_push_node.index,
+                              HICNFWD_ERROR_CACHED, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+always_inline u8 *
+hicn_data_push_format_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 *);
+  hicn_data_push_trace_t *t = va_arg (*args, hicn_data_push_trace_t *);
+
+  s = format (s, "DATA-STORE: pkt: %d, sw_if_index %d, next index %d\n",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+
+  return (s);
+}
+
+
+/*
+ * Node registration for the data forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_data_push_node) =
+{
+       .function = hicn_data_push_fn,
+               .name = "hicn-data-push",
+               .vector_size = sizeof(u32),
+               .runtime_data_bytes = sizeof(hicn_data_push_runtime_t),
+               .format_trace = hicn_data_push_format_trace,
+               .type = VLIB_NODE_TYPE_INTERNAL,
+               .n_errors = ARRAY_LEN(hicn_data_push_error_strings),
+               .error_strings = hicn_data_push_error_strings,
+               .n_next_nodes = HICN_DATA_PUSH_N_NEXT,
+       /* edit / add dispositions here */
+               .next_nodes = {
+               [HICN_DATA_PUSH_NEXT_ERROR_DROP] = "error-drop",
+       },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/error.c b/hicn-plugin/src/error.c
new file mode 100755 (executable)
index 0000000..588ae23
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2019 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 "error.h"
+
+const char *HICN_ERROR_STRING[] = {
+#define _(a,b,c) c,
+  foreach_hicn_error
+#undef _
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/error.h b/hicn-plugin/src/error.h
new file mode 100755 (executable)
index 0000000..978c7f2
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_ERROR_H__
+#define __HICN_ERROR_H__
+
+#define foreach_hicn_error                                              \
+ _(NONE, 0, "Ok")                                                       \
+ _(UNSPECIFIED, -128, "Unspecified Error")                              \
+ _(FACE_NOT_FOUND, -129, "Face not found in Face table")                \
+ _(FACE_NULL, -130, "Face null")                                        \
+ _(FACE_IP_ADJ_NOT_FOUND, -131, "Ip adjacecny for face not found")      \
+ _(FACE_HW_INT_NOT_FOUND, -132, "Hardware interface not found")         \
+ _(FACE_NOMEM, -133, "Face table is full")                              \
+ _(FACE_NO_GLOBAL_IP, -134, "No global ip address for face")            \
+ _(FACE_NOT_FOUND_IN_ENTRY, -135, "Face not found in entry")            \
+ _(FACE_ALREADY_DELETED, -136, "Face alredy deleted")                   \
+ _(FACE_ALREADY_CREATED, -137, "Face alredy created")                   \
+ _(FWD_NOT_ENABLED, -138, "hICN forwarder not enabled")                 \
+ _(FWD_ALREADY_ENABLED, -139, "hICN forwarder alredy enabled")          \
+ _(PARSER_UNSUPPORTED_PROTO, -140, "Unsupported protocol")              \
+ _(PARSER_PKT_INVAL, -141, "Packet null")                               \
+ _(PIT_CONFIG_MINLT_OOB, -142, "Min lifetime ouf of bounds")            \
+ _(PIT_CONFIG_MAXLT_OOB, -143, "Max lifetime ouf of bounds")            \
+ _(PIT_CONFIG_MINMAXLT, -144, "Min lifetime grater than max lifetime") \
+ _(PIT_CONFIG_DFTLT_OOB, -145, "Default lifetime ouf of bounds")        \
+ _(PIT_CONFIG_SIZE_OOB, -146, "Pit size ouf of bounds")                        \
+ _(CS_CONFIG_SIZE_OOB, -147, "CS size ouf of bounds")                  \
+ _(CS_CONFIG_RESERVED_OOB, -148, "Reseved CS must be between 0 and 100 (excluded)") \
+ _(DPO_CTX_NHOPS_NS, -149, "No space for additional next hop")          \
+ _(DPO_CTX_NHOPS_EXISTS, -150, "Next hop already in the route")         \
+ _(DPO_CTX_NOT_FOUND, -151, "Dpo context not found")                    \
+ _(DPO_MGR_ID_NOT_VALID, -152, "Dpo id for strategy and context not valid") \
+ _(HASHTB_HASH_NOT_FOUND, -153, "Hash not found in hash table")         \
+ _(HASHTB_HASH_INVAL, -154, "Error while calculating the hash")         \
+ _(HASHTB_NOMEM, -155, "Unable to allocate new buckets or nodes")       \
+ _(HASHTB_INVAL, -156, "Invalid argument")                              \
+ _(HASHTB_KEY_INVAL, -157, "Invalid hashtb key")                        \
+ _(HASHTB_EXIST, -158, "Hash already in hashtable")                     \
+ _(ROUTE_INVAL, -159, "Invalid face id and weight")                     \
+ _(ROUTE_NO_LD, -160, "Expected load balance dpo")                      \
+ _(ROUTE_MLT_LD, -161, "Unexpected mulitple buckets in load balance dpo") \
+ _(ROUTE_NO_INSERT, -162, "Unable to insert a new FIB entry")           \
+ _(ROUTE_DPO_NO_HICN, -163, "Dpo is not of type hICN")                  \
+ _(ROUTE_NOT_FOUND, -164, "Route not found in FIB")                     \
+ _(ROUTE_NOT_UPDATED, -165, "Unable to update route")                   \
+ _(ROUTE_ALREADY_EXISTS, -166, "Route already in FIB")                  \
+ _(CLI_INVAL, -167, "Invalid input")                                    \
+ _(PUNT_INVAL, -168, "Invalid prefix or subnet or interface")           \
+ _(PUNT_TBL_NOT_FOUND, -169, "Vnet table not found")                    \
+ _(PUNT_TBL_EXIST, -170, "Vnet table already created")                  \
+ _(PUNT_SSN_NOT_FOUND, -171, "Vnet session not found")                  \
+ _(PUNT_SSN_EXIST, -172, "Vnet session already created")                \
+ _(PUNT_SKIP_NOT_SUPPORTED, -173, "Skip size not supported. Skip must be <= 1") \
+ _(PUNT_NOMEM, -174, "Unable to allocate skip_mask")                    \
+ _(IPS_ADDR_TYPE_NONUNIFORM, -175, "Src and dst addr have different ip types") \
+ _(FACE_TYPE_EXISTS, -176, "Face type already registered")              \
+ _(NO_BUFFERS, -177, "No vlib_buffer available for packet cloning.")    \
+ _(NOT_IMPLEMENTED, -178, "Function not yet implemented")               \
+ _(IFACE_IP_ADJ_NOT_FOUND, -179, "IP adjacency on incomplete face not available") \
+ _(APPFACE_ALREADY_ENABLED, -180, "Application face already enabled on interface") \
+ _(APPFACE_FEATURE, -181, "Error while enabling app face feature")      \
+ _(APPFACE_NOT_FOUND, -182, "Application face not found")               \
+ _(APPFACE_PROD_PREFIX_NULL, -183, "Prefix must not be null for producer face") \
+ _(MW_STRATEGY_NH_NOT_FOUND, -184, "Next hop not found")               \
+ _(MW_STRATEGY_SET, -185, "Error while setting weight for next hop")   \
+ _(STRATEGY_NOT_FOUND, -186, "Strategy not found")
+
+
+typedef enum
+{
+#define _(a,b,c) HICN_ERROR_##a = (b),
+  foreach_hicn_error
+#undef _
+    HICN_N_ERROR,
+} hicn_error_t;
+
+extern const char *HICN_ERROR_STRING[];
+
+#define get_error_string(errno) (char *)(errno ? HICN_ERROR_STRING[(-errno) - 127] : HICN_ERROR_STRING[errno])
+
+#endif /* //__HICN_ERROR_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/face_db.h b/hicn-plugin/src/face_db.h
new file mode 100755 (executable)
index 0000000..7b8a088
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_DB_H__
+#define __HICN_FACE_DB_H__
+
+#include <vnet/dpo/dpo.h>
+#include "faces/face.h"
+
+/**
+ * @File
+ *
+ * Define a face db that is store in every pit entry. A face db containes a list
+ * of incoming faces for interest packets that are used to forward data packets
+ * on the interests' reverse path
+ */
+
+/* Must be power of two */
+#define HICN_FACE_DB_INLINE_FACES 4
+
+#define HICN_PIT_N_HOP_BITMAP_SIZE HICN_PARAM_PIT_ENTRY_PHOPS_MAX
+
+#define HICN_PIT_N_HOP_BUCKET (HICN_PARAM_PIT_ENTRY_PHOPS_MAX - HICN_FACE_DB_INLINE_FACES)
+
+STATIC_ASSERT ((HICN_PIT_N_HOP_BUCKET & (HICN_PIT_N_HOP_BUCKET - 1)) == 0,
+              "HICN_PARAM_PIT_ENTRY_PHOP_MAX must be a power of 2 + 4");
+
+/* Takes 2 cache lines */
+typedef struct __attribute__ ((packed)) hicn_face_bucket_s
+{
+  /* Array of indexes of virtual faces */
+  dpo_id_t faces[HICN_PIT_N_HOP_BUCKET];
+
+  CLIB_CACHE_LINE_ALIGN_MARK (cache_line1);
+
+  /* Used to check if interests are retransmission */
+  u8 bitmap[HICN_PIT_N_HOP_BITMAP_SIZE];
+
+} hicn_face_bucket_t;
+
+extern hicn_face_bucket_t *hicn_face_bucket_pool;
+
+typedef struct __attribute__ ((packed)) hicn_face_db_s
+{
+  /* 19B + 1B = 20B */
+  /* Equal to one or zero */
+  u8 is_overflow;
+
+  /* Number of faces in the last bucket */
+  /* Or next availabe entry for storing a dpo_id_t */
+  /* 20B + 4B = 24B */
+  u32 n_faces;
+
+  /* 24B + 32B (8*4) = 56B */
+  /* Array of indexes of virtual faces */
+  dpo_id_t inline_faces[HICN_FACE_DB_INLINE_FACES];
+
+  /* 56B + 4B = 60B */
+  u32 next_bucket;
+
+  /* 60B + 4B = 64B */
+  u32 align;
+  //align back to 64
+
+} hicn_face_db_t;
+
+always_inline dpo_id_t *
+hicn_face_db_get_dpo_face (u32 index, hicn_face_db_t * face_db)
+{
+  ASSERT (index < face_db->n_faces);
+
+  return index < HICN_FACE_DB_INLINE_FACES ? &(face_db->inline_faces[index]) :
+    &(pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket)->faces
+      [(index - HICN_FACE_DB_INLINE_FACES) & (HICN_PIT_N_HOP_BUCKET - 1)]);
+}
+
+always_inline void
+hicn_face_db_init (int max_element)
+{
+  pool_init_fixed (hicn_face_bucket_pool, max_element);
+}
+
+always_inline hicn_face_bucket_t *
+hicn_face_db_get_bucket (u32 bucket_index)
+{
+  return pool_elt_at_index (hicn_face_bucket_pool, bucket_index);
+}
+
+always_inline void
+hicn_face_db_add_face_dpo (dpo_id_t * dpo, hicn_face_db_t * face_db)
+{
+  ASSERT (dpo->dpoi_index != ~0);
+
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+
+  dpo_id_t *face =
+    face_db->n_faces <
+    HICN_FACE_DB_INLINE_FACES ? &(face_db->inline_faces[face_db->n_faces]) :
+    &(faces_bkt->faces
+      [(face_db->n_faces -
+       HICN_FACE_DB_INLINE_FACES) & (HICN_PIT_N_HOP_BUCKET - 1)]);
+
+  clib_memcpy (face, dpo, sizeof (dpo_id_t));
+
+  /* This access the dpoi to increase the lock */
+  dpo_lock (dpo);
+
+  u32 bitmap_index = dpo->dpoi_index % HICN_PIT_N_HOP_BITMAP_SIZE;
+  faces_bkt->bitmap[bitmap_index] |= 0x01;
+  face_db->n_faces++;
+}
+
+always_inline u8
+hicn_face_search (dpo_id_t * dpo, hicn_face_db_t * face_db)
+{
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+  u32 bitmap_index = dpo->dpoi_index % HICN_PIT_N_HOP_BITMAP_SIZE;
+
+  return faces_bkt->bitmap[bitmap_index] & 0x01;
+}
+
+always_inline void
+hicn_faces_flush (hicn_face_db_t * face_db)
+{
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+  clib_memset_u64 (&(faces_bkt->bitmap), 0, HICN_PIT_N_HOP_BITMAP_SIZE / 8);
+  face_db->n_faces = 0;
+  pool_put_index (hicn_face_bucket_pool, face_db->next_bucket);
+}
+
+
+#endif /* // __HICN_FACE_DB_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/address_mgr.c b/hicn-plugin/src/faces/app/address_mgr.c
new file mode 100755 (executable)
index 0000000..76a7e0f
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2017-2019 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) 2017-2019 by cisco systems inc. All rights reserved.
+ *
+ */
+
+#include <dlfcn.h>
+
+#include <vlib/vlib.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip4.h>       //ip4_add_del_ip_address
+#include <vnet/ip/ip6.h>       //ip6_add_del_ip_address
+#include <vnet/fib/fib_types.h>        //FIB_PROTOCOL_IP4/6, FIB_NODE_INDEX_INVALID
+#include <vnet/fib/fib_entry.h>        //FIB_SOURCE_PLUGIN_HI
+#include <vnet/fib/fib_table.h>
+#include <vppinfra/format.h>
+#include <vnet/interface.h>    //appif_flags
+#include <vnet/interface_funcs.h>      //vnet_sw_interface_set_flags
+
+#include "address_mgr.h"
+#include "../../hicn.h"
+#include "../../infra.h"
+#include "../../error.h"
+#include "../face.h"
+#include "../ip/face_ip.h"
+#include "../../strategy_dpo_ctx.h"
+#include "../../route.h"
+
+typedef struct address_mgr_main_s
+{
+  ip4_address_t next_ip4_local_addr;
+  ip6_address_t next_ip6_local_addr;
+} address_mgr_main_t;
+
+address_mgr_main_t address_mgr_main;
+
+static void
+increment_v4_address (ip4_address_t * a, u32 val)
+{
+  u32 v;
+
+  v = clib_net_to_host_u32 (a->as_u32) + val;
+  a->as_u32 = clib_host_to_net_u32 (v);
+}
+
+static void
+increment_v6_address (ip6_address_t * a, u64 val)
+{
+  u64 v;
+
+  v = clib_net_to_host_u64 (a->as_u64[1]) + val;
+  a->as_u64[1] = clib_host_to_net_u64 (v);
+}
+
+void
+get_two_ip4_addresses (ip4_address_t * appif_addr, ip4_address_t * nh_addr)
+{
+  /* We want two consecutives address that fall into a /31 mask */
+  if (address_mgr_main.next_ip4_local_addr.as_u8[3] & 0x01)
+    increment_v4_address (&(address_mgr_main.next_ip4_local_addr), 1);
+
+  *appif_addr = address_mgr_main.next_ip4_local_addr;
+  increment_v4_address (&(address_mgr_main.next_ip4_local_addr), 1);
+  *nh_addr = address_mgr_main.next_ip4_local_addr;
+  fib_prefix_t fib_pfx;
+  fib_node_index_t fib_entry_index = FIB_NODE_INDEX_INVALID;
+  u32 fib_index;
+
+  fib_pfx.fp_proto = FIB_PROTOCOL_IP4;
+  fib_pfx.fp_len = ADDR_MGR_IP4_LEN;
+  /* At this point the face exists in the face table */
+  do
+    {
+      /* Check if the route already exist in the fib */
+      fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 0, appif_addr->as_u8);
+      fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                    HICN_FIB_TABLE,
+                                                    FIB_SOURCE_PLUGIN_HI);
+      fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
+      fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+      if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+       {
+         fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 0, nh_addr->as_u8);
+         fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                        HICN_FIB_TABLE,
+                                                        FIB_SOURCE_PLUGIN_HI);
+         fib_entry_index =
+           fib_table_lookup_exact_match (fib_index, &fib_pfx);
+         fib_table_unlock (fib_index, fib_pfx.fp_proto,
+                           FIB_SOURCE_PLUGIN_HI);
+       }
+      if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+       {
+         increment_v4_address (appif_addr, 2);
+         increment_v4_address (nh_addr, 2);
+       }
+    }
+  while (fib_entry_index != FIB_NODE_INDEX_INVALID);
+
+  address_mgr_main.next_ip4_local_addr = *nh_addr;
+  increment_v4_address (&(address_mgr_main.next_ip4_local_addr), 1);
+}
+
+void
+get_two_ip6_addresses (ip6_address_t * appif_addr, ip6_address_t * nh_addr)
+{
+
+  /* We want two consecutives address that fall into a /127 mask */
+  if (address_mgr_main.next_ip6_local_addr.as_u8[15] & 0x01)
+    increment_v6_address (&(address_mgr_main.next_ip6_local_addr), 1);
+
+  *appif_addr = address_mgr_main.next_ip6_local_addr;
+  increment_v6_address (&(address_mgr_main.next_ip6_local_addr), 1);
+  *nh_addr = address_mgr_main.next_ip6_local_addr;
+
+
+  fib_prefix_t fib_pfx;
+  fib_node_index_t fib_entry_index = FIB_NODE_INDEX_INVALID;
+  u32 fib_index;
+
+  fib_pfx.fp_proto = FIB_PROTOCOL_IP6;
+  fib_pfx.fp_len = ADDR_MGR_IP6_LEN;
+  /* At this point the face exists in the face table */
+  do
+    {
+      /* Check if the route already exist in the fib */
+      fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 1, appif_addr->as_u8);
+      fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                    HICN_FIB_TABLE,
+                                                    FIB_SOURCE_PLUGIN_HI);
+      fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
+      fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+      if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+       {
+         fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 0, nh_addr->as_u8);
+         fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                        HICN_FIB_TABLE,
+                                                        FIB_SOURCE_PLUGIN_HI);
+         fib_entry_index =
+           fib_table_lookup_exact_match (fib_index, &fib_pfx);
+         fib_table_unlock (fib_index, fib_pfx.fp_proto,
+                           FIB_SOURCE_PLUGIN_HI);
+       }
+      if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+       {
+         increment_v6_address (appif_addr, 2);
+         increment_v6_address (nh_addr, 2);
+       }
+    }
+  while (fib_entry_index != FIB_NODE_INDEX_INVALID);
+
+  address_mgr_main.next_ip6_local_addr = *nh_addr;
+  increment_v6_address (&(address_mgr_main.next_ip6_local_addr), 1);
+}
+
+ip4_address_t
+get_ip4_address ()
+{
+  ip4_address_t *prefix = &address_mgr_main.next_ip4_local_addr;
+  fib_prefix_t fib_pfx;
+  fib_node_index_t fib_entry_index = FIB_NODE_INDEX_INVALID;
+  u32 fib_index;
+
+  fib_pfx.fp_proto = FIB_PROTOCOL_IP4;
+  fib_pfx.fp_len = ADDR_MGR_IP4_LEN;
+  /* At this point the face exists in the face table */
+  do
+    {
+      /* Check if the route already exist in the fib */
+      fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 0, prefix->as_u8);
+      fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                    HICN_FIB_TABLE,
+                                                    FIB_SOURCE_PLUGIN_HI);
+      fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
+      fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+      increment_v4_address (prefix, 1);
+    }
+  while (fib_entry_index != FIB_NODE_INDEX_INVALID);
+
+  return fib_pfx.fp_addr.ip4;
+}
+
+ip6_address_t
+get_ip6_address ()
+{
+  ip6_address_t *prefix = &address_mgr_main.next_ip6_local_addr;
+  fib_prefix_t fib_pfx;
+  fib_node_index_t fib_entry_index = FIB_NODE_INDEX_INVALID;
+  u32 fib_index;
+
+  fib_pfx.fp_proto = FIB_PROTOCOL_IP6;
+  fib_pfx.fp_len = ADDR_MGR_IP6_LEN;
+  /* At this point the face exists in the face table */
+  do
+    {
+      /* Check if the route already exist in the fib */
+      fib_pfx.fp_addr = to_ip46 ( /* is_v6 */ 1, prefix->as_u8);
+      fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                    HICN_FIB_TABLE,
+                                                    FIB_SOURCE_PLUGIN_HI);
+      fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
+      fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+      increment_v6_address (prefix, 1);
+    }
+  while (fib_entry_index != FIB_NODE_INDEX_INVALID);
+
+  return fib_pfx.fp_addr.ip6;
+}
+
+void
+address_mgr_init ()
+{
+
+  address_mgr_main.next_ip4_local_addr.as_u8[0] = 169;
+  address_mgr_main.next_ip4_local_addr.as_u8[1] = 254;
+  address_mgr_main.next_ip4_local_addr.as_u8[2] = 1;
+  address_mgr_main.next_ip4_local_addr.as_u8[3] = 1;
+
+  ip6_address_set_zero (&address_mgr_main.next_ip6_local_addr);
+  address_mgr_main.next_ip6_local_addr.as_u16[0] =
+    clib_host_to_net_u16 (0xfc00);
+  address_mgr_main.next_ip6_local_addr.as_u8[15] = 1;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/address_mgr.h b/hicn-plugin/src/faces/app/address_mgr.h
new file mode 100755 (executable)
index 0000000..99450dc
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2019 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 _ADDRESS_MGR_H_
+#define _ADDRESS_MGR_H_
+
+/**
+ * @file
+ *
+ * @brief Address manager.
+ *
+ * Address manager that maintains a pool of ip4 and ip6 addresses to assign to
+ * an interface.
+ */
+
+#define ADDR_MGR_IP4_LEN 32
+#define ADDR_MGR_IP4_CONS_LEN 31
+#define ADDR_MGR_IP6_LEN 128
+#define ADDR_MGR_IP6_CONS_LEN 127
+
+/**
+ * @brief Get two consecutive IP v4 addresses from the same /31 subnet
+ *
+ * @param addr1 first ip address with the least significant bit set to 0
+ * @param addr2 second ip address with the least significant bit set to 1
+ */
+void get_two_ip4_addresses (ip4_address_t * addr1, ip4_address_t * addr2);
+
+/**
+ * @brief Get two consecutive IP v6 addresses from the same /126 subnet
+ *
+ * @param addr1 first ip address with the least significant bit set to 0
+ * @param addr2 second ip address with the least significant bit set to 1
+ */
+void get_two_ip6_addresses (ip6_address_t * addr1, ip6_address_t * addr2);
+
+/**
+ * @brief Get one IP v4 address
+ *
+ * @return ip address
+ */
+ip4_address_t get_ip4_address (void);
+
+/**
+ * @brief Get one IP v6 address
+ *
+ * @return ip address
+ */
+ip6_address_t get_ip6_address (void);
+
+/**
+ * @brief Init the address manager
+ */
+void address_mgr_init (void);
+
+#endif /* _ADDRESS_MGR_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_app_cli.c b/hicn-plugin/src/faces/app/face_app_cli.c
new file mode 100755 (executable)
index 0000000..d55e990
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/vnet.h>
+#include <vnet/dpo/dpo.h>
+#include <vlib/vlib.h>
+#include <vnet/ip/ip6_packet.h>
+
+#include "../ip/face_ip.h"
+#include "../ip/dpo_ip.h"
+#include "../face.h"
+#include "face_prod.h"
+#include "face_cons.h"
+
+#define HICN_FACE_NONE 0
+#define HICN_FACE_DELETE 1
+#define HICN_FACE_ADD 2
+
+static clib_error_t *
+hicn_face_app_cli_set_command_fn (vlib_main_t * vm,
+                                 unformat_input_t * main_input,
+                                 vlib_cli_command_t * cmd)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  ip46_address_t prefix;
+  hicn_face_id_t face_id = HICN_FACE_NULL;
+  u32 cs_reserved = HICN_PARAM_FACE_DFT_CS_RESERVED;
+  int ret = HICN_ERROR_NONE;
+  int sw_if;
+  int face_op = HICN_FACE_NONE;
+  int prod = 0;
+  int len;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       {
+         face_op = HICN_FACE_DELETE;
+       }
+      else if (face_op == HICN_FACE_DELETE
+              && unformat (line_input, "id %d", &face_id))
+       ;
+      else if (unformat (line_input, "add"))
+       {
+         face_op = HICN_FACE_ADD;
+       }
+      else if (face_op == HICN_FACE_ADD)
+       {
+         if (unformat (line_input, "intfc %U",
+                       unformat_vnet_sw_interface, vnm, &sw_if))
+           ;
+         else
+           if (unformat
+               (line_input, "prod prefix %U/%d", unformat_ip46_address,
+                &prefix, IP46_TYPE_ANY, &len))
+           {
+             prod = 1;
+           }
+         else if (prod && unformat (line_input, "cs_size %d", &cs_reserved))
+           ;
+         else if (unformat (line_input, "cons"))
+           ;
+         else
+           {
+             return clib_error_return (0, "%s '%U'",
+                                       get_error_string
+                                       (HICN_ERROR_CLI_INVAL),
+                                       format_unformat_error, line_input);
+           }
+       }
+      else
+       {
+         return clib_error_return (0, "%s '%U'",
+                                   get_error_string (HICN_ERROR_CLI_INVAL),
+                                   format_unformat_error, line_input);
+       }
+    }
+
+  if (face_id != HICN_FACE_NULL)
+    {
+
+      if (!hicn_dpoi_idx_is_valid (face_id))
+       {
+         return clib_error_return (0, "%s, face_id %d not valid",
+                                   get_error_string (ret), face_id);
+       }
+    }
+
+  int rv;
+  switch (face_op)
+    {
+    case HICN_FACE_ADD:
+      {
+       ip46_address_t prod_addr;
+       ip4_address_t cons_addr4;
+       ip6_address_t cons_addr6;
+
+       hicn_prefix_t name_prefix = {
+         .name = prefix,
+         .len = len,
+       };
+       if (prod)
+         {
+           rv =
+             hicn_face_prod_add (&name_prefix, sw_if, &cs_reserved,
+                                 &prod_addr, &face_id);
+           if (rv == HICN_ERROR_NONE)
+             {
+               u8 *sbuf = NULL;
+               sbuf =
+                 format (sbuf, "Face id: %d, producer address %U", face_id,
+                         format_ip46_address, &prod_addr,
+                         0 /*IP46_ANY_TYPE */ );
+               vlib_cli_output (vm, "%s", sbuf);
+             }
+           else
+             {
+               return clib_error_return (0, get_error_string (rv));
+             }
+         }
+       else
+         {
+           rv =
+             hicn_face_cons_add (&cons_addr4, &cons_addr6, sw_if, &face_id);
+           if (rv == HICN_ERROR_NONE)
+             {
+               u8 *sbuf = NULL;
+               sbuf =
+                 format (sbuf, "Face id: %d, consumer addresses v4 %U v6 %U",
+                         face_id, format_ip4_address, &cons_addr4,
+                         format_ip6_address, &cons_addr6);
+               vlib_cli_output (vm, "%s", sbuf);
+             }
+           else
+             {
+               return clib_error_return (0, get_error_string (rv));
+             }
+         }
+       break;
+      }
+    case HICN_FACE_DELETE:
+      {
+       hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+
+       if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS)
+         rv = hicn_face_cons_del (face_id);
+       else
+         rv = hicn_face_prod_del (face_id);
+       if (rv == HICN_ERROR_NONE)
+         {
+           vlib_cli_output (vm, "Face %d deleted", face_id);
+         }
+       else
+         {
+           return clib_error_return (0, get_error_string (rv));
+         }
+       break;
+      }
+    default:
+      return clib_error_return (0, "Operation (%d) not implemented", face_op);
+      break;
+    }
+  return (rv == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n",
+                                                         get_error_string
+                                                         (rv));
+}
+
+/* cli declaration for 'cfg face' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_face_app_cli_set_command, static) =
+{
+  .path = "hicn face app",
+  .short_help = "hicn face app {add intfc <sw_if> { prod prefix <hicn_prefix> cs_size <size_in_packets>} {cons} | {del <face_id>}",
+  .function = hicn_face_app_cli_set_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_cons.c b/hicn-plugin/src/faces/app/face_cons.c
new file mode 100755 (executable)
index 0000000..8278b6a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "face_cons.h"
+#include "address_mgr.h"
+#include "../../infra.h"
+
+int
+hicn_face_cons_add (ip4_address_t * nh_addr4, ip6_address_t * nh_addr6,
+                   u32 swif, hicn_face_id_t * faceid)
+{
+  /* Create the corresponding appif if */
+  /* Retrieve a valid local ip address to assign to the appif */
+  /* Set the ip address and create the face in the face db */
+
+  vlib_main_t *vm = vlib_get_main ();
+  vnet_main_t *vnm = vnet_get_main ();
+
+  hicn_main_t *hm = &hicn_main;
+
+  ip46_address_t if_ip;
+  ip46_address_reset (&if_ip);
+  nh_addr4->as_u32 = 0;
+  nh_addr6->as_u64[0] = 0;
+  nh_addr6->as_u64[1] = 0;
+  u32 if_flags = 0;
+
+  if (!hm->is_enabled)
+    {
+      return HICN_ERROR_FWD_NOT_ENABLED;
+    }
+  if_flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+  vnet_sw_interface_set_flags (vnm, swif, if_flags);
+
+  get_two_ip4_addresses (&(if_ip.ip4), nh_addr4);
+  ip4_add_del_interface_address (vm,
+                                swif,
+                                &(if_ip.ip4),
+                                ADDR_MGR_IP4_CONS_LEN, 0 /* is_del */ );
+
+  ip46_address_t nh_addr = to_ip46 (0, (u8 *) nh_addr4);
+
+  hicn_iface_ip_add (&if_ip, &nh_addr, swif, faceid);
+
+  hicn_face_t *face = hicn_dpoi_get_from_idx (*faceid);
+  face->shared.flags |= HICN_FACE_FLAGS_APPFACE_CONS;
+
+  get_two_ip6_addresses (&(if_ip.ip6), nh_addr6);
+  ip6_add_del_interface_address (vm,
+                                swif,
+                                &(if_ip.ip6),
+                                ADDR_MGR_IP6_CONS_LEN, 0 /* is_del */ );
+
+  hicn_iface_ip_add (&if_ip, (ip46_address_t *) nh_addr6, swif, faceid);
+
+  face = hicn_dpoi_get_from_idx (*faceid);
+  face->shared.flags |= HICN_FACE_FLAGS_APPFACE_CONS;
+
+  return vnet_feature_enable_disable ("ip6-unicast",
+                                     "hicn-iface-ip6-input", swif, 1, 0,
+                                     0) ==
+    0 ? HICN_ERROR_NONE : HICN_ERROR_APPFACE_FEATURE;
+}
+
+int
+hicn_face_cons_del (hicn_face_id_t face_id)
+{
+  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+
+  if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS)
+    {
+      int ret = hicn_face_ip_del (face_id);
+
+      return ret ==
+       HICN_ERROR_NONE
+       ? (vnet_feature_enable_disable
+          ("ip6-unicast", "hicn-iface-ip6-input", face->shared.sw_if, 0,
+           0, 0) == 0 ? HICN_ERROR_NONE : HICN_ERROR_APPFACE_FEATURE) : ret;
+    }
+  else
+    {
+      return HICN_ERROR_APPFACE_NOT_FOUND;
+    }
+}
+
+u8 *
+format_hicn_face_cons (u8 * s, va_list * args)
+{
+  CLIB_UNUSED (index_t index) = va_arg (*args, index_t);
+  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
+
+  s = format (s, " (consumer face)");
+
+  return s;
+}
+
+/* *INDENT-OFF* */
+VNET_FEATURE_INIT(hicn_cons_app, static)=
+{
+  .arc_name = "ip6-unicast",
+  .node_name = "hicn-iface-ip6-input",
+  .runs_before = VNET_FEATURES("ip6-inacl"),
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_cons.h b/hicn-plugin/src/faces/app/face_cons.h
new file mode 100755 (executable)
index 0000000..067b45a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019 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 _FACE_CONSUMER_H_
+#define _FACE_CONSUMER_H_
+
+#include <vnet/vnet.h>
+#include "../face.h"
+
+/**
+ * @file
+ *
+ * @brief Consumer application face.
+ *
+ * A consumer application face is built upon an ip face and identify a local
+ * consumer application (co-located with the forwarder) that acts as a
+ * consumer. The interface used by the consumer application face is
+ * assumed to be reserved only for hICN traffic (e.g.,  dedicated memif that
+ * connects the applictation to the forwarder). Only one application face can be
+ * assigned to an interface.
+ *
+ * In the vlib graph a consumer application face directly connect the
+ * device-input node to the hicn-vface-ip node.
+ */
+
+/**
+ * @brief Add a new consumer application face
+ *
+ * The method creates the internal ip face and set the ip address to the interface.
+ * @param nh_addr4 ipv4 address to assign to interface used by the application to
+ * send interest to the consumer face
+ * @param nh_addr6 ipv6 address to assign to interface used by the application to
+ * send interest to the consumer face
+ * @param swif interface associated to the face
+ */
+int
+hicn_face_cons_add (ip4_address_t * nh_addr4, ip6_address_t * nh_addr6,
+                   u32 swif, hicn_face_id_t * faceid);
+
+/**
+ * @brief Delete an existing consumer application face
+ *
+ * @param face_id Id of the consumer application face
+ */
+int hicn_face_cons_del (hicn_face_id_t face_id);
+
+/**
+ * @brief Format an application consumer face
+ *
+ * @param s Pointer to a previous string. If null it will be initialize
+ * @param args Array storing input values. Expected u32 face_id and u32 indent
+ * @return String with the formatted face
+ */
+u8 *format_hicn_face_cons (u8 * s, va_list * args);
+
+
+#endif /* _FACE_CONSUMER_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_prod.c b/hicn-plugin/src/faces/app/face_prod.c
new file mode 100755 (executable)
index 0000000..d06fe2f
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "face_prod.h"
+#include "address_mgr.h"
+#include "../../infra.h"
+#include "../../route.h"
+#include "../../cache_policies/cs_lru.h"
+
+hicn_face_prod_state_t *face_state_vec;
+
+/* used to check if an interface is already in the vector */
+u32 *face_state_pool;
+
+static int
+hicn_app_state_create (u32 swif, hicn_prefix_t * prefix)
+{
+  /* Make sure that the pool is not empty */
+  pool_validate_index (face_state_pool, 0);
+
+  u32 *swif_app;
+  u8 found = 0;
+  /* *INDENT-OFF* */
+  pool_foreach (swif_app, face_state_pool,{
+      if (*swif_app == swif)
+       {
+         found = 1;
+       }
+    }
+  );
+  /* *INDENT-ON* */
+
+
+  if (found)
+    return HICN_ERROR_APPFACE_ALREADY_ENABLED;
+
+
+  /* Create the appif and store in the vector */
+  vec_validate (face_state_vec, swif);
+  clib_memcpy (&(face_state_vec[swif].prefix), prefix,
+              sizeof (hicn_prefix_t));
+
+  /* Set as busy the element in the vector */
+  pool_get (face_state_pool, swif_app);
+  *swif_app = swif;
+
+  int ret = HICN_ERROR_NONE;
+  if (ip46_address_is_ip4 (&(prefix->name)))
+    {
+      ret =
+       vnet_feature_enable_disable ("ip4-unicast", "hicn-face-prod-input",
+                                    swif, 1, 0, 0);
+    }
+  else
+    {
+      ret =
+       vnet_feature_enable_disable ("ip6-unicast", "hicn-face-prod-input",
+                                    swif, 1, 0, 0);
+    }
+
+  return ret == 0 ? HICN_ERROR_NONE : HICN_ERROR_APPFACE_FEATURE;
+}
+
+static int
+hicn_app_state_del (u32 swif)
+{
+  /* Make sure that the pool is not empty */
+  pool_validate_index (face_state_pool, 0);
+
+  u32 *temp;
+  u32 *swif_app = NULL;
+  u8 found = 0;
+  ip46_address_t *prefix_addr;
+  /* *INDENT-OFF* */
+  pool_foreach (temp, face_state_pool,{
+      if (*temp == swif)
+       {
+         found = 1;
+         swif_app = temp;
+       }
+    }
+  );
+  /* *INDENT-ON* */
+
+  prefix_addr = &(face_state_vec[swif].prefix.name);
+  if (!found)
+    return HICN_ERROR_APPFACE_NOT_FOUND;
+
+  int ret = HICN_ERROR_NONE;
+  if (ip46_address_is_ip4 (prefix_addr))
+    {
+      ret =
+       vnet_feature_enable_disable ("ip4-unicast", "hicn-face-prod-input",
+                                    swif, 0, 0, 0);
+    }
+  else
+    {
+      ret =
+       vnet_feature_enable_disable ("ip6-unicast", "hicn-face-prod-input",
+                                    swif, 0, 0, 0);
+    }
+
+  pool_put (face_state_pool, swif_app);
+  memset (&face_state_vec[swif], 0, sizeof (hicn_face_prod_state_t));
+
+  return ret == 0 ? HICN_ERROR_NONE : HICN_ERROR_APPFACE_FEATURE;
+}
+
+int
+hicn_face_prod_add (hicn_prefix_t * prefix, u32 sw_if, u32 * cs_reserved,
+                   ip46_address_t * prod_addr, hicn_face_id_t * faceid)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vnet_main_t *vnm = vnet_get_main ();
+
+  hicn_main_t *hm = &hicn_main;
+
+  ip46_address_t app_ip;
+  u32 if_flags = 0;
+
+  if (!hm->is_enabled)
+    {
+      return HICN_ERROR_FWD_NOT_ENABLED;
+    }
+  int ret = HICN_ERROR_NONE;
+  hicn_face_t *face = NULL;
+
+  if_flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+  vnet_sw_interface_set_flags (vnm, sw_if, if_flags);
+
+  if (ip46_address_is_zero (&prefix->name))
+    {
+      return HICN_ERROR_APPFACE_PROD_PREFIX_NULL;
+    }
+  /*
+   * Check if a producer face is already existing for the same prefix
+   * and sw_if
+   */
+  if (ip46_address_is_ip4 (&prefix->name))
+    {
+      face =
+       hicn_face_ip4_get (&(prefix->name.ip4), sw_if,
+                          &hicn_face_ip_remote_hashtb);
+    }
+  else
+    {
+      face =
+       hicn_face_ip6_get (&(prefix->name.ip6), sw_if,
+                          &hicn_face_ip_remote_hashtb);
+      if (face != NULL)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+    }
+
+  if (face != NULL)
+    {
+      if (!(face->shared.flags & HICN_FACE_FLAGS_DELETED))
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      /*
+       * Something went worng, a consumer face exists for the
+       * producer's prefix.
+       */
+      /* It should never happens, this is a safety check. */
+      if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      /* If the face exists but is marked as deleted, undelete it */
+      if (face->shared.flags & HICN_FACE_FLAGS_DELETED)
+       {
+         /*
+          * remove the deleted flag and retrieve the face
+          * local addr
+          */
+         face->shared.flags &= HICN_FACE_FLAGS_DELETED;
+         hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+         app_ip = prod_face->ip_face.local_addr;
+       }
+    }
+  else
+    {
+      /* Otherwise create the face */
+      if (ip46_address_is_ip4 (&prefix->name))
+       {
+         /*
+          * Otherwise retrieve an ip address to assign as a
+          * local ip addr.
+          */
+         ip4_address_t app_ip4 = get_ip4_address ();
+         ip4_add_del_interface_address (vm,
+                                        sw_if,
+                                        &app_ip4,
+                                        ADDR_MGR_IP4_CONS_LEN,
+                                        0 /* is_del */ );
+         app_ip = to_ip46 ( /* isv6 */ 0, app_ip4.as_u8);
+       }
+      else
+       {
+         ip6_address_t app_ip6 = get_ip6_address ();
+         ip6_add_del_interface_address (vm,
+                                        sw_if,
+                                        &app_ip6,
+                                        ADDR_MGR_IP6_CONS_LEN,
+                                        0 /* is_del */ );
+         app_ip = to_ip46 ( /* isv6 */ 1, app_ip6.as_u8);
+       }
+
+      /*
+       * Special case: the nh_addr in the face is the appif ip
+       * address
+       */
+      ret = hicn_face_ip_add (&app_ip, &(prefix->name), sw_if, faceid);
+
+      face = hicn_dpoi_get_from_idx (*faceid);
+
+      face->shared.flags |= HICN_FACE_FLAGS_APPFACE_PROD;
+
+      hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+
+      /*
+       * For the moment we keep them here although it would be good
+       * to create a different face for appface
+       */
+      prod_face->policy_vft.hicn_cs_insert = hicn_cs_lru.hicn_cs_insert;
+      prod_face->policy_vft.hicn_cs_update = hicn_cs_lru.hicn_cs_update;
+      prod_face->policy_vft.hicn_cs_dequeue = hicn_cs_lru.hicn_cs_dequeue;
+      prod_face->policy_vft.hicn_cs_delete_get =
+       hicn_cs_lru.hicn_cs_delete_get;
+      prod_face->policy_vft.hicn_cs_trim = hicn_cs_lru.hicn_cs_trim;
+
+    }
+
+  if (ret == HICN_ERROR_NONE
+      && hicn_face_prod_set_lru_max (*faceid, cs_reserved) == HICN_ERROR_NONE)
+    {
+      hicn_app_state_create (sw_if, prefix);
+      ret = hicn_route_add (faceid, 1, &(prefix->name), prefix->len);
+    }
+
+  *prod_addr = app_ip;
+
+  /* Cleanup in case of something went wrong. */
+  if (ret)
+    {
+      hicn_app_state_del (sw_if);
+
+      if (*faceid != HICN_FACE_NULL)
+       hicn_face_ip_del (*faceid);
+    }
+  return ret;
+}
+
+int
+hicn_face_prod_del (hicn_face_id_t face_id)
+{
+  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+
+  if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD)
+    {
+      hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+      /* Free the CS reserved for the face */
+      hicn_main.pitcs.pcs_app_max += prod_face->policy.max;
+      hicn_main.pitcs.pcs_app_count -= prod_face->policy.max;
+      prod_face->policy.max = 0;
+
+      /* Remove the face from the fib */
+      hicn_route_del_nhop (&(face_state_vec[face->shared.sw_if].prefix.name),
+                          (face_state_vec[face->shared.sw_if].prefix.len),
+                          face_id);
+
+      int ret = hicn_face_ip_del (face_id);
+      return ret ==
+       HICN_ERROR_NONE ? hicn_app_state_del (face->shared.sw_if) : ret;
+    }
+  else
+    {
+      return HICN_ERROR_APPFACE_NOT_FOUND;
+    }
+}
+
+int
+hicn_face_prod_set_lru_max (hicn_face_id_t face_id, u32 * requested_size)
+{
+  int ret = HICN_ERROR_NONE;
+  vlib_main_t *vm = vlib_get_main ();
+  hicn_face_t *face;
+  hicn_face_prod_t *face_prod;
+
+  if (!hicn_infra_fwdr_initialized)
+    {
+      ret = HICN_ERROR_FWD_NOT_ENABLED;
+      vlib_cli_output (vm, "hicn: %s\n", get_error_string (ret));
+      return ret;
+    }
+  face = hicn_dpoi_get_from_idx (face_id);
+  face_prod = (hicn_face_prod_t *) face->data;
+
+  if (face == NULL)
+    return HICN_ERROR_FACE_NOT_FOUND;
+
+  if (*requested_size > HICN_PARAM_FACE_MAX_CS_RESERVED)
+    *requested_size = HICN_PARAM_FACE_MAX_CS_RESERVED;
+
+  uint32_t available =
+    hicn_main.pitcs.pcs_app_max - hicn_main.pitcs.pcs_app_count;
+
+  if (*requested_size > available)
+    *requested_size = available;
+
+  face_prod->policy.max = *requested_size;
+  face_prod->policy.count = 0;
+  face_prod->policy.head = face_prod->policy.tail = 0;
+
+  hicn_main.pitcs.pcs_app_count += *requested_size;
+
+  return ret;
+}
+
+u8 *
+format_hicn_face_prod (u8 * s, va_list * args)
+{
+  index_t index = va_arg (*args, index_t);
+  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
+  hicn_face_t *face;
+  hicn_face_prod_t *prod_face;
+
+  face = hicn_dpoi_get_from_idx (index);
+  prod_face = (hicn_face_prod_t *) face->data;
+
+  s =
+    format (s, " (producer face: CS size %d, data cached %d)",
+           prod_face->policy.max, prod_face->policy.count);
+
+  return s;
+}
+
+/* *INDENT-OFF* */
+VNET_FEATURE_INIT(hicn_prod_app_input_ip6, static)=
+{
+  .arc_name = "ip6-unicast",
+  .node_name = "hicn-face-prod-input",
+  .runs_before = VNET_FEATURES("ip6-inacl"),
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VNET_FEATURE_INIT(hicn_prod_app_input_ip4, static)=
+{
+  .arc_name = "ip4-unicast",
+  .node_name = "hicn-face-prod-input",
+  .runs_before = VNET_FEATURES("ip4-inacl"),
+};
+/* *INDENT-ON* */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_prod.h b/hicn-plugin/src/faces/app/face_prod.h
new file mode 100755 (executable)
index 0000000..89b7468
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017-2019 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 _FACE_PRODUCER_H_
+#define _FACE_PRODUCER_H_
+
+#include "../../cache_policies/cs_policy.h"
+#include "../ip/face_ip.h"
+
+/**
+ * @file
+ *
+ * @brief Producer application face.
+ *
+ * A producer application face is built upon an ip face and identify a local
+ * producer application (co-located with the forwarder) that acts as a producer. In the
+ * current design an application face is either a face towards a consumer face
+ * or towards a producer. The interface used by the producer application face is
+ * assumed to be reserved only for hICN traffic (e.g.,  dedicated memif that
+ * connects the applictation to the forwarder). Only one application face can be
+ * assigned to an interface.
+ *
+ * To each producer application face it is assigned a portion of the CS. Every
+ * data arriving to a producer application will be stored in the portion of the
+ * CS assigned to the face. The eviction policy is defined in the
+ * face. Available eviction faces are list in the /cache_policy folder.
+ *
+ * In the vlib graph a producer application face is directly connected to the
+ * device-input node (with the node hicn-face-prod-input) and passes every packet to
+ * the hicn-face-ip node.
+ */
+
+/**
+ * @brief Producer application face state that refer to the hICN producer socket
+ * created by the application.
+ *
+ */
+typedef struct
+{
+  hicn_prefix_t prefix;
+} hicn_face_prod_state_t;
+
+extern hicn_face_prod_state_t *face_state_vec;
+
+typedef struct __attribute__ ((packed)) hicn_face_prod_t_
+{
+  hicn_face_ip_t ip_face;
+
+  hicn_cs_policy_t policy;
+  hicn_cs_policy_vft_t policy_vft;
+
+} hicn_face_prod_t;
+
+/**
+ * @brief Add a new producer application face
+ *
+ * The method creates the internal ip face and the state specific to the
+ * producer application face. This method setups a route in the FIB for the
+ * producer's prefix.
+ * @param prefix hicn prefix name assigned to the producer face
+ * @param len length of the prefix
+ * @param swif interface associated to the face
+ * @param cs_reserved return the amount of cs assigned to the face
+ * @param prod_addr address to assign to interface used by the appliction to
+ * send data to the producer face
+ */
+int
+hicn_face_prod_add (hicn_prefix_t * prefix, u32 swif, u32 * cs_reserved,
+                   ip46_address_t * prod_addr, hicn_face_id_t * faceid);
+
+/**
+ * @brief Delete an existing application face
+ *
+ * @param faceid id of the face to remove
+ */
+int hicn_face_prod_del (hicn_face_id_t faceid);
+
+/**
+ * @brief Set lru queue size for an app face
+ *
+ * @param face_id Id of the producer application face
+ */
+int hicn_face_prod_set_lru_max (hicn_face_id_t face_id, u32 * requested_size);
+
+/**
+ * @brief Format an application producer face
+ *
+ * @param s Pointer to a previous string. If null it will be initialize
+ * @param args Array storing input values. Expected u32 face_id and u32 indent
+ * @return String with the formatted face
+ */
+u8 *format_hicn_face_prod (u8 * s, va_list * args);
+
+
+#endif /* _FACE_PROD_H_ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/app/face_prod_node.c b/hicn-plugin/src/faces/app/face_prod_node.c
new file mode 100755 (executable)
index 0000000..2e746a7
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file
+ *
+ * @brief Application interface node
+ *
+ * This node runs after the device-input node and perfoms some safety checks in
+ * order to avoid unespected interest and data (i.e., hICN packets whose name do
+ * not contain the prefix associated to the application face)
+ */
+
+#include "face_prod.h"
+#include "../../hicn_api.h"
+#include "../../mgmt.h"
+
+#define foreach_face_prod_input_error                   \
+  _(NOT_SOCK_PREFIX, "name not in the socket prefix")
+
+typedef enum
+{
+#define _(f,s) FACE_PROD_INPUT_ERROR_##f,
+  foreach_face_prod_input_error
+#undef _
+    FACE_PROD_INPUT_N_ERROR,
+} face_prod_input_error_t;
+
+static __clib_unused char *face_prod_input_error_strings[] = {
+#define _(n,s) s,
+  foreach_face_prod_input_error
+#undef _
+};
+
+/* Node context data */
+typedef struct hicn_face_prod_runtime_s
+{
+  int id;
+} hicn_face_prod_runtime_t;
+
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+} hicn_face_prod_input_trace_t;
+
+typedef enum
+{
+  HICN_FACE_PROD_NEXT_DATA_IP4,
+  HICN_FACE_PROD_NEXT_DATA_IP6,
+  HICN_FACE_PROD_NEXT_ERROR_DROP,
+  HICN_FACE_PROD_N_NEXT,
+} hicn_face_prod_next_t;
+
+vlib_node_registration_t hicn_face_prod_input_node;
+
+static __clib_unused u8 *
+format_face_prod_input_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 *);
+  hicn_face_prod_input_trace_t *t =
+    va_arg (*args, hicn_face_prod_input_trace_t *);
+  CLIB_UNUSED (u32 indent) = format_get_indent (s);
+
+  s = format (s, "prod-face: sw_if_index %d next-index %d",
+             t->sw_if_index, t->next_index);
+  return s;
+}
+
+static_always_inline int
+match_ip4_name (u32 * name, hicn_prefix_t * prefix)
+{
+  u32 xor = 0;
+
+  xor = *name & prefix->name.ip4.data_u32;
+
+  return xor == prefix->name.ip4.data_u32;
+}
+
+static_always_inline int
+match_ip6_name (u32x4 * name, hicn_prefix_t * prefix)
+{
+  union
+  {
+    u32x4 as_u32x4;
+    u64 as_u64[2];
+    u32 as_u32[4];
+  } xor_sum __attribute__ ((aligned (sizeof (u32x4))));
+
+#ifdef CLIB_HAVE_VEC128
+  if (U32X4_ALIGNED (name))
+    {                          //SSE can't handle unaligned data
+      xor_sum.as_u32x4 = *((u32x4 *) name) &
+       UNION_CAST (prefix->name.ip6.as_u64[0], u32x4);
+    }
+  else
+#endif /* CLIB_HAVE_VEC128 */
+    {
+      xor_sum.as_u64[0] = ((u64 *) name)[0] & prefix->name.ip6.as_u64[0];
+      xor_sum.as_u64[1] = ((u64 *) name)[1] & prefix->name.ip6.as_u64[1];
+    }
+
+  return (xor_sum.as_u64[0] == prefix->name.ip6.as_u64[0]) &&
+    (xor_sum.as_u64[1] == prefix->name.ip6.as_u64[1]);
+}
+
+static_always_inline u32
+hicn_face_prod_next_from_data_hdr (vlib_node_runtime_t * node,
+                                  vlib_buffer_t * b, hicn_prefix_t * prefix)
+{
+  u8 *ptr = vlib_buffer_get_current (b);
+  u8 v = *ptr & 0xf0;
+  int match_res = 1;
+
+  if (PREDICT_TRUE (v == 0x40 && ip46_address_is_ip4 (&prefix->name)))
+    {
+      match_res = match_ip4_name ((u32 *) & (ptr[12]), prefix);
+    }
+  else if (PREDICT_TRUE (v == 0x60 && !ip46_address_is_ip4 (&prefix->name)))
+    {
+      match_res = match_ip6_name ((u32x4 *) & (ptr[8]), prefix);
+    }
+
+  b->error = 0*(1-match_res) + match_res*(node->errors[FACE_PROD_INPUT_ERROR_NOT_SOCK_PREFIX]);
+
+  return match_res ? HICN_FACE_PROD_NEXT_DATA_IP4 + (v ==
+                                                    0x60) :
+    HICN_FACE_PROD_NEXT_ERROR_DROP;
+}
+
+static_always_inline void
+hicn_face_prod_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node,
+                            u32 swif, vlib_buffer_t * b, u32 next)
+{
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                    (b->flags & VLIB_BUFFER_IS_TRACED)))
+    {
+      hicn_face_prod_input_trace_t *t =
+       vlib_add_trace (vm, node, b, sizeof (*t));
+      t->next_index = next;
+      t->sw_if_index = swif;
+    }
+}
+
+static uword
+hicn_face_prod_input_node_fn (vlib_main_t * vm,
+                             vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicn_face_prod_next_t next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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 >= 8 && n_left_to_next >= 4)
+       {
+         vlib_buffer_t *b0, *b1, *b2, *b3;
+         u32 bi0, bi1, bi2, bi3;
+         hicn_face_prod_state_t *prod_face0 = NULL;
+         hicn_face_prod_state_t *prod_face1 = NULL;
+         hicn_face_prod_state_t *prod_face2 = NULL;
+         hicn_face_prod_state_t *prod_face3 = NULL;
+         u32 next0, next1, next2, next3;
+
+         {
+           vlib_buffer_t *b4, *b5, *b6, *b7;
+           b4 = vlib_get_buffer (vm, from[4]);
+           b5 = vlib_get_buffer (vm, from[5]);
+           b6 = vlib_get_buffer (vm, from[6]);
+           b7 = vlib_get_buffer (vm, from[7]);
+           CLIB_PREFETCH (b4, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (b5, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (b6, CLIB_CACHE_LINE_BYTES, STORE);
+           CLIB_PREFETCH (b7, CLIB_CACHE_LINE_BYTES, STORE);
+         }
+
+         bi0 = from[0];
+         bi1 = from[1];
+         bi2 = from[2];
+         bi3 = from[3];
+
+         from += 4;
+         n_left_from -= 4;
+         to_next[0] = bi0;
+         to_next[1] = bi1;
+         to_next[2] = bi2;
+         to_next[3] = bi3;
+
+         to_next += 4;
+         n_left_to_next -= 4;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         b1 = vlib_get_buffer (vm, bi1);
+         b2 = vlib_get_buffer (vm, bi2);
+         b3 = vlib_get_buffer (vm, bi3);
+
+         prod_face0 =
+           &face_state_vec[vnet_buffer (b0)->sw_if_index[VLIB_RX]];
+         prod_face1 =
+           &face_state_vec[vnet_buffer (b1)->sw_if_index[VLIB_RX]];
+         prod_face2 =
+           &face_state_vec[vnet_buffer (b2)->sw_if_index[VLIB_RX]];
+         prod_face3 =
+           &face_state_vec[vnet_buffer (b3)->sw_if_index[VLIB_RX]];
+
+         next0 =
+           hicn_face_prod_next_from_data_hdr (node, b0, &prod_face0->prefix);
+         next1 =
+           hicn_face_prod_next_from_data_hdr (node, b1, &prod_face1->prefix);
+         next2 =
+           hicn_face_prod_next_from_data_hdr (node, b2, &prod_face2->prefix);
+         next3 =
+           hicn_face_prod_next_from_data_hdr (node, b3, &prod_face3->prefix);
+         stats.pkts_data_count += 4;
+
+         /* trace */
+         hicn_face_prod_trace_buffer (vm, node,
+                                      vnet_buffer (b0)->sw_if_index[VLIB_RX],
+                                      b0, next0);
+         hicn_face_prod_trace_buffer (vm, node,
+                                      vnet_buffer (b1)->sw_if_index[VLIB_RX],
+                                      b1, next1);
+         hicn_face_prod_trace_buffer (vm, node,
+                                      vnet_buffer (b2)->sw_if_index[VLIB_RX],
+                                      b2, next2);
+         hicn_face_prod_trace_buffer (vm, node,
+                                      vnet_buffer (b3)->sw_if_index[VLIB_RX],
+                                      b3, next3);
+
+         /* enqueue */
+         vlib_validate_buffer_enqueue_x4 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, bi1, bi2, bi3,
+                                          next0, next1, next2, next3);
+
+         stats.pkts_processed += 4;
+
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u32 bi0, swif;
+         hicn_face_prod_state_t *prod_face = NULL;
+         u32 next0;
+
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);
+           }
+
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         swif = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         prod_face = &face_state_vec[swif];
+
+         next0 =
+           hicn_face_prod_next_from_data_hdr (node, b0, &prod_face->prefix);
+         stats.pkts_data_count++;
+
+         /* trace */
+         hicn_face_prod_trace_buffer (vm, node,
+                                      vnet_buffer (b0)->sw_if_index[VLIB_RX],
+                                      b0, next0);
+
+         /* enqueue */
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+                                          n_left_to_next, bi0, next0);
+
+         stats.pkts_processed += 1;
+
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+  vlib_node_increment_counter (vm, node->node_index, HICNFWD_ERROR_DATAS,
+                              stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_face_prod_input_node) =
+{
+  .function = hicn_face_prod_input_node_fn,
+  .name = "hicn-face-prod-input",
+  .vector_size = sizeof(u32),
+  .format_trace = format_face_prod_input_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(face_prod_input_error_strings),
+  .error_strings = face_prod_input_error_strings,
+  .n_next_nodes = HICN_FACE_PROD_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_FACE_PROD_NEXT_DATA_IP4] = "hicn-face-ip4-input",
+    [HICN_FACE_PROD_NEXT_DATA_IP6] = "hicn-face-ip6-input",
+    [HICN_FACE_PROD_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/faces/face.c b/hicn-plugin/src/faces/face.c
new file mode 100755 (executable)
index 0000000..f0559bb
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2019 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 "face.h"
+#include "ip/face_ip.h"
+#include "ip/face_ip_node.h"
+#include "ip/iface_ip_node.h"
+#include "ip/dpo_ip.h"
+#include "udp/face_udp.h"
+#include "udp/face_udp_node.h"
+#include "udp/iface_udp_node.h"
+#include "udp/dpo_udp.h"
+
+dpo_id_t *face_dpo_vec;
+hicn_face_vft_t *face_vft_vec;
+char **face_type_names_vec;
+
+hicn_face_t *hicn_dpoi_face_pool;
+
+dpo_type_t first_type = DPO_FIRST;
+
+u8 *
+face_show (u8 * s, int face_id, u32 indent)
+{
+  s = format (s, "Faces:\n", indent);
+  indent += 4;
+  int i;
+  vec_foreach_index (i, face_dpo_vec)
+  {
+    s =
+      format (s, "%U", face_vft_vec[i].format_face,
+             face_dpo_vec[face_id].dpoi_index, indent);
+  }
+
+  return (s);
+
+}
+
+void
+register_face_type (hicn_face_type_t face_type, hicn_face_vft_t * vft,
+                   char *name)
+{
+  if (first_type == DPO_FIRST)
+    first_type = face_type;
+
+  int idx = face_type - first_type;
+  ASSERT (idx >= 0);
+  vec_validate (face_vft_vec, idx);
+  vec_validate (face_type_names_vec, idx);
+
+  /* Copy the null char as well */
+  char *name_str = (char *) malloc ((strlen (name) + 1) * sizeof (char));
+  strcpy (name_str, name);
+  face_vft_vec[idx] = *vft;
+  face_type_names_vec[idx] = name_str;
+}
+
+// Make this more flexible for future types face
+void
+hicn_face_module_init (vlib_main_t * vm)
+{
+  pool_validate (hicn_dpoi_face_pool);
+
+  hicn_face_ip_init (vm);
+  hicn_iface_ip_init (vm);
+  hicn_face_udp_init (vm);
+  hicn_iface_udp_init (vm);
+}
+
+u8 *
+format_hicn_face_all (u8 * s, int n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  u32 indent = va_arg (ap, u32);
+
+  s = format (s, "Faces: %d\n", indent);
+
+  hicn_face_t *face;
+
+  /* *INDENT-OFF* */
+  pool_foreach ( face, hicn_dpoi_face_pool,
+                 {
+                   hicn_face_vft_t * vft = hicn_face_get_vft(face->shared.face_type);
+                   hicn_face_id_t face_id = hicn_dpoi_get_index(face);
+                   s = format(s, "%U\n", vft->format_face, face_id, indent);
+                 });
+  /* *INDENT-ON* */
+
+  return s;
+}
+
+hicn_face_vft_t *
+hicn_face_get_vft (hicn_face_type_t face_type)
+{
+  int idx = face_type - first_type;
+  if (idx >= 0)
+    return &face_vft_vec[idx];
+  else
+    return NULL;
+
+}
+
+int
+hicn_face_del (hicn_face_id_t face_id)
+{
+  int ret = HICN_ERROR_NONE;
+
+  if (pool_len (hicn_dpoi_face_pool) > face_id)
+    {
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+      if (face->shared.locks == 0)
+       pool_put_index (hicn_dpoi_face_pool, face_id);
+      else
+       face->shared.flags |= HICN_FACE_FLAGS_DELETED;
+    }
+  else
+    ret = HICN_ERROR_FACE_NOT_FOUND;
+
+  return ret;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/face.h b/hicn-plugin/src/faces/face.h
new file mode 100755 (executable)
index 0000000..2774d9a
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_H__
+#define __HICN_FACE_H__
+
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+#include <vnet/dpo/dpo.h>
+#include <vnet/adj/adj_types.h>
+
+typedef u8 hicn_face_flags_t;
+typedef index_t hicn_face_id_t;
+typedef dpo_type_t hicn_face_type_t;
+
+/**
+ * @file
+ *
+ * @brief Face
+ *
+ * This file implements a general face type. A face is carried through nodes as a
+ * dpo. The face state (hicn_face_t) is the object pointed by the
+ * dpoi_index in the dpo_id_t (see
+ * https://docs.fd.io/vpp/18.07/d0/d37/dpo_8h_source.html).
+ * A face state that does not contain the indication of the l2 adjacency is an
+ * incomplete face (iface), otherwise it is considered to be complete. Each face type
+ * provide specific node for processing packets in input or output of complete
+ * and incomplete faces.
+ */
+
+/**
+ * @brief Fields shared among all the different types of faces
+ */
+typedef struct __attribute__ ((packed)) hicn_face_shared_s
+{
+  /* Flags to idenfity if the face is incomplete (iface), complete (face) */
+  /* And a network or application face (1B) */
+  hicn_face_flags_t flags;
+
+  /* Path label (2B) */
+  u16 pl_id;
+
+  /* Number of dpo holding a reference to the dpoi (4B) */
+  u32 locks;
+
+  /* Adjacency for the neighbor (4B) */
+  adj_index_t adj;
+
+  /* local interface for the local ip address */
+  u32 sw_if;
+
+  /* Face id corresponding to the global face pool (4B) */
+  union
+  {
+    hicn_face_type_t face_type;
+    u32 int_face_type;         //To forse the face_type_t to be 4B
+  };
+
+} hicn_face_shared_t;
+
+/**
+ * @brief Structure holding the face state. It containes the fields shared among
+ * all the types of faces as well it leaves some space for storing additional
+ * information specific to each type.
+ */
+typedef struct __attribute__ ((packed)) hicn_face_s
+{
+  /* Additional space to fill with face_type specific information */
+  u8 data[2 * CLIB_CACHE_LINE_BYTES - sizeof (hicn_face_shared_t)];
+  hicn_face_shared_t shared;
+
+}
+
+hicn_face_t;
+
+/* Pool of faces */
+extern hicn_face_t *hicn_dpoi_face_pool;
+
+/* Flags */
+/* A face is complete and it stores all the information. A iface lacks of the
+   adj index, therefore sending a packet through a iface require a lookup in
+   the FIB. */
+#define HICN_FACE_FLAGS_DEFAULT        0x00
+#define HICN_FACE_FLAGS_FACE           0x01
+#define HICN_FACE_FLAGS_IFACE          0x02
+#define HICN_FACE_FLAGS_APPFACE_PROD   0x04    /* Currently only IP face can be appface */
+#define HICN_FACE_FLAGS_APPFACE_CONS   0x08    /* Currently only IP face can be appface */
+#define HICN_FACE_FLAGS_DELETED        0x10
+
+#define HICN_FACE_NULL (hicn_face_id_t) ~0
+
+/**
+ * @brief Definition of the virtual functin table for an hICN FACE DPO.
+ *
+ * An hICN dpo is a combination of a dpo context (hicn_dpo_ctx or struct that
+ * extends a hicn_dpo_ctx) and a strategy node. The following virtual function table
+ * template that glues together the fuction to interact with the context and the
+ * creating the dpo
+ */
+typedef struct hicn_face_vft_s
+{
+  u8 *(*format_face) (u8 * s, va_list * args);
+  /**< Format an hICN face dpo*/
+  int (*hicn_face_del) (hicn_face_id_t face_id);
+  void (*hicn_face_get_dpo) (hicn_face_t * face, dpo_id_t * dpo);
+} hicn_face_vft_t;
+
+
+/* Vector maintaining a dpo per face */
+extern dpo_id_t *face_dpo_vec;
+extern hicn_face_vft_t *face_vft_vec;
+
+/* Vector holding the set of face names */
+extern char **face_type_names_vec;
+
+/* First face type registered in the sytem.*/
+extern dpo_type_t first_type;
+
+/**
+ * @brief Return the face id from the face state
+ *
+ * @param Pointer to the face state
+ * @return face id
+ */
+always_inline hicn_face_id_t
+hicn_dpoi_get_index (hicn_face_t * face_dpoi)
+{
+  return face_dpoi - hicn_dpoi_face_pool;
+}
+
+/**
+ * @brief Return the face from the face id. Face id must be valid.
+ *
+ * @param dpoi_index Face identifier
+ * @return Pointer to the face
+ */
+always_inline hicn_face_t *
+hicn_dpoi_get_from_idx (hicn_face_id_t dpoi_index)
+{
+  return (hicn_face_t *) pool_elt_at_index (hicn_dpoi_face_pool, dpoi_index);
+}
+
+/**
+ * @brief Return true if the face id belongs to an existing face
+ */
+always_inline int
+hicn_dpoi_idx_is_valid (hicn_face_id_t face_id)
+{
+  return pool_len (hicn_dpoi_face_pool) > face_id
+    && !pool_is_free_index (hicn_dpoi_face_pool, face_id);
+}
+
+/**
+ * @brief Add a lock to the face dpo
+ *
+ * @param dpo Pointer to the face dpo
+ */
+always_inline void
+hicn_face_lock (dpo_id_t * dpo)
+{
+  hicn_face_t *face;
+  face = hicn_dpoi_get_from_idx (dpo->dpoi_index);
+  face->shared.locks++;
+}
+
+/**
+ * @brief Remove a lock to the face dpo. Deallocate the face id locks == 0
+ *
+ * @param dpo Pointer to the face dpo
+ */
+always_inline void
+hicn_face_unlock (dpo_id_t * dpo)
+{
+  hicn_face_t *face;
+  face = hicn_dpoi_get_from_idx (dpo->dpoi_index);
+  face->shared.locks--;
+}
+
+/**
+ * @brief Init the internal structures of the face module
+ *
+ * Must be called before processing any packet
+ */
+void hicn_face_module_init (vlib_main_t * vm);
+
+/**
+ * @brief Format all the existing faces
+ *
+ * @param s Pointer to a previous string. If null it will be initialize
+ * @param n Number of input parameters
+ * @return String with the faces formatted
+ */
+u8 *format_hicn_face_all (u8 * s, int n, ...);
+
+/**
+ * @brief Delete a face
+ *
+ * @param face_id Id of the face to delete
+ * @return HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise
+ * HICN_ERROR_NONE
+ */
+int hicn_face_del (hicn_face_id_t face_id);
+
+/**
+ * @brief Return the virtual function table corresponding to the face type
+ *
+ * @param face_type Type of the face
+ * @return NULL if the face type does not exist
+ */
+hicn_face_vft_t *hicn_face_get_vft (hicn_face_type_t face_type);
+
+/**
+ * @brief Register a new face type
+ *
+ * @param face_type Type of the face
+ * @param vft Virtual Function table for the new face type
+ */
+void register_face_type (hicn_face_type_t face_type, hicn_face_vft_t * vft,
+                        char *name);
+#endif // __HICN_FACE_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/face_cli.c b/hicn-plugin/src/faces/face_cli.c
new file mode 100755 (executable)
index 0000000..3ddf96b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vppinfra/error.h>
+#include "face.h"
+#include "../error.h"
+
+static clib_error_t *
+hicn_face_cli_show_command_fn (vlib_main_t * vm,
+                              unformat_input_t * main_input,
+                              vlib_cli_command_t * cmd)
+{
+
+  hicn_face_id_t face_id = HICN_FACE_NULL;
+  char *face_type_name = NULL;
+  int found = ~0;
+  int deleted = 0;
+
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "%u", &face_id))
+           ;
+         else if (unformat (line_input, "type %s", &face_type_name))
+           ;
+         else if (unformat (line_input, "deleted"))
+           deleted = 1;
+         else
+           {
+             return clib_error_return (0, "%s",
+                                       get_error_string
+                                       (HICN_ERROR_CLI_INVAL));
+           }
+       }
+
+      if (face_type_name != NULL)
+       {
+         int idx = 0;
+         vec_foreach_index (idx, face_type_names_vec)
+         {
+           if (!strcmp (face_type_names_vec[idx], face_type_name))
+             found = idx;
+         }
+         if (found == ~0)
+           return (clib_error_return (0, "Face type unknown"));
+       }
+
+    }
+
+  if (face_id != HICN_FACE_NULL)
+    {
+      if (!hicn_dpoi_idx_is_valid (face_id))
+       return clib_error_return (0, "%s",
+                                 get_error_string
+                                 (HICN_ERROR_FACE_NOT_FOUND));
+
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+      hicn_face_vft_t *vft = hicn_face_get_vft (face->shared.face_type);
+      vlib_cli_output (vm, "%U\n", vft->format_face, face_id, 0 /*indent */ );
+    }
+  else
+    {
+      if (found != ~0)
+       {
+         hicn_face_t *face;
+         dpo_type_t type = (dpo_type_t) (found + first_type);
+         hicn_face_vft_t *vft = hicn_face_get_vft (type);
+         /* *INDENT-OFF* */
+          pool_foreach(face, hicn_dpoi_face_pool,
+                       {
+                         if (!((face->shared.flags & HICN_FACE_FLAGS_DELETED) && !deleted))
+                           {
+                             if ((face->shared.face_type == type) && (face->shared.flags))
+                               vlib_cli_output(vm, "%U\n", vft->format_face, hicn_dpoi_get_index(face), 0);
+                           }
+                       });
+         /* *INDENT-ON* */
+       }
+      else
+       {
+         hicn_face_t *face;
+         /* *INDENT-OFF* */
+          pool_foreach(face, hicn_dpoi_face_pool,
+                       {
+                         if (!((face->shared.flags & HICN_FACE_FLAGS_DELETED) && !deleted))
+                           {
+                             hicn_face_vft_t * vft = hicn_face_get_vft(face->shared.face_type);
+                             vlib_cli_output(vm, "%U\n", vft->format_face, hicn_dpoi_get_index(face), 0);
+                           }
+                       });
+         /* *INDENT-ON* */
+       }
+    }
+
+  return 0;
+}
+
+/* cli declaration for 'show faces' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_face_cli_show_command, static) =
+{
+  .path = "hicn face show",
+  .short_help = "hicn face show [<face_id>| type <ip/udp>]",
+  .function = hicn_face_cli_show_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/dpo_ip.c b/hicn-plugin/src/faces/ip/dpo_ip.c
new file mode 100755 (executable)
index 0000000..1b2dbcf
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2019 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 "dpo_ip.h"
+
+mhash_t hicn_face_ip_local_hashtb;
+mhash_t hicn_face_ip_remote_hashtb;
+dpo_type_t hicn_face_ip_type;
+
+const static char *const hicn_face_ip4dpoi_nodes[] = {
+  "hicn-face-ip4-input",
+  "hicn-face-ip4-output",
+  "hicn-iface-ip4-input",
+  "hicn-iface-ip4-output",
+  NULL,
+};
+
+const static char *const hicn_face_ip6dpoi_nodes[] = {
+  "hicn-face-ip6-input",
+  "hicn-face-ip6-output",
+  "hicn-iface-ip6-input",
+  "hicn-iface-ip6-output",
+  NULL,
+};
+
+const static char *const *const hicn_ip_nodes[DPO_PROTO_NUM] = {
+  [DPO_PROTO_IP4] = hicn_face_ip4dpoi_nodes,
+  [DPO_PROTO_IP6] = hicn_face_ip6dpoi_nodes
+};
+
+const static dpo_vft_t hicn_face_ip_vft = {
+  .dv_lock = hicn_face_lock,
+  .dv_unlock = hicn_face_unlock,
+  .dv_format = format_hicn_face_ip,
+};
+
+/* Must be executed after all the strategy nodes are created */
+void
+hicn_dpo_ip_module_init (void)
+{
+  mhash_init (&hicn_face_ip_local_hashtb,
+             sizeof (hicn_face_id_t) /* value */ ,
+             sizeof (hicn_face_ip_key_t) /* key */ );
+  mhash_init (&hicn_face_ip_remote_hashtb,
+             sizeof (hicn_face_id_t) /* value */ ,
+             sizeof (hicn_face_ip_key_t) /* key */ );
+
+  /*
+   * How much useful is the following registration?
+   * So far it seems that we need it only for setting the dpo_type.
+   */
+  hicn_face_ip_type =
+    dpo_register_new_type (&hicn_face_ip_vft, hicn_ip_nodes);
+}
+
+
+int
+hicn_dpo_ip4_create (dpo_id_t * dpo,
+                    const ip4_address_t * local_addr,
+                    const ip4_address_t * remote_addr,
+                    u32 sw_if,
+                    adj_index_t adj,
+                    u32 node_index,
+                    hicn_face_flags_t flags, hicn_face_id_t * face_id)
+{
+  /* If local matches the dpoi is a face */
+  hicn_face_t *face =
+    hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+  u8 is_appface;
+
+  if (face != NULL)
+    return HICN_ERROR_FACE_ALREADY_CREATED;
+
+  face = hicn_face_ip4_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
+
+  if (face == NULL)
+    {
+      hicn_dpo_ip4_add_and_lock_from_remote (dpo, &is_appface, local_addr,
+                                            remote_addr, sw_if, node_index);
+      *face_id = (hicn_face_id_t) dpo->dpoi_index;
+      face = hicn_dpoi_get_from_idx (*face_id);
+    }
+  else
+    {
+      *face_id = hicn_dpoi_get_index (face);
+      dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, *face_id);
+      dpo->dpoi_next_node = node_index;
+    }
+
+
+  hicn_face_ip_key_t key;
+  hicn_face_ip4_get_key (local_addr, sw_if, &key);
+
+  mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0);
+
+  hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+  ip46_address_set_ip4 (&ip_face->local_addr, local_addr);
+  ip46_address_set_ip4 (&ip_face->remote_addr, remote_addr);
+  face->shared.flags = flags;
+  face->shared.adj = adj;
+
+  return HICN_ERROR_NONE;
+}
+
+int
+hicn_dpo_ip6_create (dpo_id_t * dpo,
+                    const ip6_address_t * local_addr,
+                    const ip6_address_t * remote_addr,
+                    u32 sw_if,
+                    adj_index_t adj,
+                    u32 node_index,
+                    hicn_face_flags_t flags, hicn_face_id_t * face_id)
+{
+  /* If local matches the dpoi is a face */
+  hicn_face_t *face =
+    hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+
+  u8 is_appface;
+
+  if (face != NULL)
+    return HICN_ERROR_FACE_ALREADY_CREATED;
+
+  face = hicn_face_ip6_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
+
+  /* If remote matches the dpoi is a iface */
+  if (face == NULL)
+    {
+      hicn_dpo_ip6_add_and_lock_from_remote (dpo, &is_appface, local_addr,
+                                            remote_addr, sw_if, node_index);
+      *face_id = (hicn_face_id_t) dpo->dpoi_index;
+      face = hicn_dpoi_get_from_idx (*face_id);
+    }
+  else
+    {
+      *face_id = hicn_dpoi_get_index (face);
+      dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, *face_id);
+      dpo->dpoi_next_node = node_index;
+    }
+
+  hicn_face_ip_key_t key;
+  hicn_face_ip6_get_key (local_addr, sw_if, &key);
+
+  mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) face_id, 0);
+
+  hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+  clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
+  clib_memcpy (&ip_face->remote_addr, remote_addr, sizeof (ip6_address_t));
+  face->shared.sw_if = sw_if;
+  face->shared.flags = flags;
+  face->shared.adj = adj;
+
+
+  return HICN_ERROR_NONE;
+}
+
+void
+hicn_dpo_ip_create_from_face (hicn_face_t * face, dpo_id_t * dpo,
+                             u16 dpoi_next_node)
+{
+  hicn_face_id_t face_dpoi_id = hicn_dpoi_get_index (face);
+  hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+  dpo_set (dpo, face->shared.face_type,
+          ip46_address_is_ip4 (&ip_face->
+                               local_addr) ? DPO_PROTO_IP4 : DPO_PROTO_IP6,
+          face_dpoi_id);
+  dpo->dpoi_next_node = dpoi_next_node;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/dpo_ip.h b/hicn-plugin/src/faces/ip/dpo_ip.h
new file mode 100755 (executable)
index 0000000..6754432
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_DPO_IP_H__
+#define __HICN_DPO_IP_H__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip4_packet.h>
+
+#include "face_ip.h"
+#include "../face.h"
+
+/**
+ * @brief Initialize the internal structures of the dpo ip face module.
+ */
+void hicn_dpo_ip_module_init (void);
+
+
+/**
+ * @brief Retrieve a face from the ip4 local address and returns its dpo. This
+ * method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not
+ * @param local_addr: Ip v4 local address of the face
+ * @param sw_if: software interface id of the face
+ *
+ * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE.
+ */
+always_inline int
+hicn_dpo_ip4_lock_from_local (dpo_id_t * dpo,
+                             u8 * is_appface,
+                             const ip4_address_t * local_addr, u32 sw_if)
+{
+  hicn_face_t *face =
+    hicn_face_ip4_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+
+  if (PREDICT_FALSE (face == NULL))
+    return HICN_ERROR_FACE_NOT_FOUND;
+
+  *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index);
+  dpo->dpoi_next_node = ~0;
+  dpo_lock (dpo);
+
+  return HICN_ERROR_NONE;
+}
+
+/**
+ * @brief Retrieve a face from the ip6 local address and returns its dpo. This
+ * method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not
+ * @param local_addr: Ip v6 local address of the face
+ * @param sw_if: software interface id of the face
+ *
+ * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE.
+ */
+always_inline int
+hicn_dpo_ip6_lock_from_local (dpo_id_t * dpo,
+                             u8 * is_appface,
+                             const ip6_address_t * local_addr, u32 sw_if)
+{
+  hicn_face_t *face =
+    hicn_face_ip6_get (local_addr, sw_if, &hicn_face_ip_local_hashtb);
+
+  if (PREDICT_FALSE (face == NULL))
+    return HICN_ERROR_FACE_NOT_FOUND;
+
+  *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, dpoi_index);
+  dpo->dpoi_next_node = ~0;
+  dpo_lock (dpo);
+
+  return HICN_ERROR_NONE;
+}
+
+
+/**
+ * @brief Retrieve, or create if it doesn't exist, a face from the ip6 local
+ * address and returns its dpo. This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not
+ * @param local_addr: Ip v4 local address of the face
+ * @param remote_addr: Ip v4 remote address of the face
+ * @param sw_if: software interface id of the face
+ * @param node_index: vlib edge index to use in the packet processing
+ */
+always_inline void
+hicn_dpo_ip4_add_and_lock_from_remote (dpo_id_t * dpo,
+                                      u8 * is_appface,
+                                      const ip4_address_t * local_addr,
+                                      const ip4_address_t * remote_addr,
+                                      u32 sw_if, u32 node_index)
+{
+  /*All (complete) faces are indexed by remote addess as well */
+  hicn_face_t *face =
+    hicn_face_ip4_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
+
+  if (face == NULL)
+    {
+      hicn_face_id_t dpoi_index;
+      ip46_address_t local_addr46 = to_ip46 (0, (u8 *) local_addr);
+      ip46_address_t remote_addr46 = to_ip46 (0, (u8 *) remote_addr);
+      hicn_iface_ip_add (&local_addr46, &remote_addr46, sw_if, &dpoi_index);
+
+      *is_appface = 0;
+
+      dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index);
+      dpo->dpoi_next_node = node_index;
+      dpo_lock (dpo);
+
+      return;
+    }
+
+  /* Code replicated on purpose */
+  *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index);
+  dpo->dpoi_next_node = node_index;
+  dpo_lock (dpo);
+}
+
+/**
+ * @brief Retrieve, or create if it doesn't exist, a face from the ip6 local
+ * address and returns its dpo. This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not
+ * @param local_addr: Ip v6 local address of the face
+ * @param remote_addr: Ip v6 remote address of the face
+ * @param sw_if: software interface id of the face
+ * @param node_index: vlib edge index to use in the packet processing
+ */
+always_inline void
+hicn_dpo_ip6_add_and_lock_from_remote (dpo_id_t * dpo,
+                                      u8 * is_appface,
+                                      const ip6_address_t * local_addr,
+                                      const ip6_address_t * remote_addr,
+                                      u32 sw_if, u32 node_index)
+{
+  /*All (complete) faces are indexed by remote addess as well */
+  hicn_face_t *face =
+    hicn_face_ip6_get (remote_addr, sw_if, &hicn_face_ip_remote_hashtb);
+
+  if (face == NULL)
+    {
+      hicn_face_id_t dpoi_index;
+      hicn_iface_ip_add ((ip46_address_t *) local_addr,
+                        (ip46_address_t *) remote_addr, sw_if, &dpoi_index);
+
+      *is_appface = 0;
+
+      dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP4, dpoi_index);
+      dpo->dpoi_next_node = node_index;
+      dpo_lock (dpo);
+
+      return;
+    }
+  /* Code replicated on purpose */
+  *is_appface = face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD;
+
+  index_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_ip_type, DPO_PROTO_IP6, dpoi_index);
+  dpo->dpoi_next_node = node_index;
+  dpo_lock (dpo);
+}
+
+
+/**
+ * @brief Create an ip face and its corresponding dpo. Meant to be used for the
+ * control plane.
+ *
+ * @param dpo: Data plane object that point to the face created.
+ * @param local_addr: Ip v4 local address of the face
+ * @param remote_addr: Ip v4 remote address of the face
+ * @param sw_if: software interface id of the face
+ * @param adj: Ip adjacency corresponding to the remote address in the face
+ * @param node_index: vlib edge index to use in the packet processing
+ * @param flags: Flags of the face
+ * @param face_id: Identifier for the face (dpoi_index)
+ * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
+ */
+int hicn_dpo_ip4_create (dpo_id_t * dpo,
+                        const ip4_address_t * local_addr,
+                        const ip4_address_t * remote_addr,
+                        u32 sw_if,
+                        adj_index_t adj,
+                        u32 node_index,
+                        hicn_face_flags_t flags, hicn_face_id_t * face_id);
+
+/**
+ * @brief Create an ip face and its corresponding dpo. Meant to be used for the
+ * control plane.
+ *
+ * @param dpo: Data plane object that point to the face created.
+ * @param local_addr: Ip v6 local address of the face
+ * @param remote_addr: Ip v6 remote address of the face
+ * @param sw_if: software interface id of the face
+ * @param adj: Ip adjacency corresponding to the remote address in the face
+ * @param node_index: vlib edge index to use in the packet processing
+ * @param flags: Flags of the face
+ * @param face_id: Identifier for the face (dpoi_index)
+ * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
+ */
+int hicn_dpo_ip6_create (dpo_id_t * dpo,
+                        const ip6_address_t * local_addr,
+                        const ip6_address_t * remote_addr,
+                        u32 sw_if,
+                        adj_index_t adj,
+                        u32 node_index,
+                        hicn_face_flags_t flags, hicn_face_id_t * face_id);
+
+/**
+ * @brief Create a dpo from an ip face
+ *
+ * @param face Face from which to create the dpo
+ * @param dpoi_next_node Edge index that connects a node to the iface or face nodes
+ * @return the dpo
+ */
+void hicn_dpo_ip_create_from_face (hicn_face_t * face, dpo_id_t * dpo,
+                                  u16 dpoi_next_node);
+
+#endif // __HICN_DPO_IP_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/face_ip.c b/hicn-plugin/src/faces/ip/face_ip.c
new file mode 100755 (executable)
index 0000000..c7f6a1b
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2017-2019 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 "face_ip.h"
+#include "face_ip_node.h"
+#include "dpo_ip.h"
+#include "../../strategy_dpo_manager.h"
+#include "../face.h"
+#include "../../cache_policies/cs_lru.h"
+#include "../../infra.h"
+#include "../../hicn.h"
+#include "../app/face_prod.h"
+#include "../app/face_cons.h"
+
+#include "../../mapme.h"       // HICN_MAPME_EVENT_*
+#include "../../mapme_eventmgr.h"      // hicn_mapme_eventmgr_process_node
+
+extern vlib_node_registration_t hicn_mapme_eventmgr_process_node;
+
+u32 strategy_face_ip4_vlib_edge;
+u32 strategy_face_ip6_vlib_edge;
+
+void
+hicn_face_ip_init (vlib_main_t * vm)
+{
+  int strategy_nodes_n = hicn_strategy_get_all_available ();
+
+  /* Default Strategy has index 0 and it always exists */
+  strategy_face_ip4_vlib_edge = vlib_node_add_next (vm,
+                                                   hicn_dpo_get_strategy_vft
+                                                   (default_dpo.
+                                                    hicn_dpo_get_type ())->
+                                                   get_strategy_node_index
+                                                   (),
+                                                   hicn_face_ip4_output_node.
+                                                   index);
+
+  strategy_face_ip6_vlib_edge = vlib_node_add_next (vm,
+                                                   hicn_dpo_get_strategy_vft
+                                                   (default_dpo.
+                                                    hicn_dpo_get_type ())->
+                                                   get_strategy_node_index
+                                                   (),
+                                                   hicn_face_ip6_output_node.
+                                                   index);
+  /*
+   * Create and edge between al the other strategy nodes
+   * and the ip_encap nodes.
+   */
+  for (int i = 1; i < strategy_nodes_n; i++)
+    {
+      u32 temp_index4 = vlib_node_add_next (vm,
+                                           hicn_dpo_get_strategy_vft_from_id
+                                           (i)->get_strategy_node_index (),
+                                           hicn_face_ip4_output_node.index);
+      u32 temp_index6 = vlib_node_add_next (vm,
+                                           hicn_dpo_get_strategy_vft_from_id
+                                           (i)->get_strategy_node_index (),
+                                           hicn_face_ip6_output_node.index);
+      ASSERT (temp_index4 == strategy_face_ip4_vlib_edge);
+      ASSERT (temp_index6 == strategy_face_ip6_vlib_edge);
+    }
+
+  hicn_dpo_ip_module_init ();
+
+  register_face_type (hicn_face_ip_type, &ip_vft, "ip");
+}
+
+int
+hicn_face_ip_del (hicn_face_id_t face_id)
+{
+  hicn_face_t *face = hicn_dpoi_get_from_idx (face_id);
+  hicn_face_ip_t *face_ip = (hicn_face_ip_t *) face->data;
+  hicn_face_ip_key_t key;
+  hicn_face_ip_key_t old_key;
+
+  if (ip46_address_is_ip4 (&face_ip->local_addr))
+    {
+      hicn_face_ip4_get_key (&(face_ip->local_addr.ip4), face->shared.sw_if,
+                            &key);
+      mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
+      hicn_face_ip4_get_key (&(face_ip->remote_addr.ip4), face->shared.sw_if,
+                            &key);
+      mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key);
+    }
+  else
+    {
+      hicn_face_ip6_get_key (&(face_ip->local_addr.ip6), face->shared.sw_if,
+                            &key);
+      mhash_unset (&hicn_face_ip_local_hashtb, &key, (uword *) & old_key);
+      hicn_face_ip6_get_key (&(face_ip->remote_addr.ip6), face->shared.sw_if,
+                            &key);
+      mhash_unset (&hicn_face_ip_remote_hashtb, &key, (uword *) & old_key);
+    }
+  return hicn_face_del (face_id);
+}
+
+
+/*
+ * Utility that adds a new face cache entry. For the moment we assume that the
+ * ip_adjacency has already been set up.
+ */
+int
+hicn_face_ip_add (const ip46_address_t * local_addr,
+                 const ip46_address_t * remote_addr,
+                 int sw_if, hicn_face_id_t * pfaceid)
+{
+  fib_protocol_t fib_type;
+  vnet_link_t link_type;
+  adj_index_t adj;
+  dpo_proto_t dpo_proto;
+
+  /* Check if we found at least one ip address */
+  if (ip46_address_is_zero (local_addr) || ip46_address_is_zero (remote_addr))
+    return HICN_ERROR_FACE_NO_GLOBAL_IP;
+
+  if (ip46_address_is_ip4 (local_addr) && ip46_address_is_ip4 (remote_addr))
+    {
+      link_type = VNET_LINK_IP4;
+      fib_type = FIB_PROTOCOL_IP4;
+    }
+  else
+    {
+      link_type = VNET_LINK_IP6;
+      fib_type = FIB_PROTOCOL_IP6;
+    }
+
+
+  adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, sw_if);
+
+  hicn_face_flags_t flags = (hicn_face_flags_t) 0;
+  flags |= HICN_FACE_FLAGS_FACE;
+
+  hicn_face_t *face;
+  if (ip46_address_is_ip4 (local_addr))
+    {
+      face =
+       hicn_face_ip4_get (&(local_addr->ip4), sw_if,
+                          &hicn_face_ip_local_hashtb);
+
+      if (face != NULL)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      face =
+       hicn_face_ip4_get (&(remote_addr->ip4), sw_if,
+                          &hicn_face_ip_remote_hashtb);
+
+      /* If remote matches the face is a iface */
+      if (face == NULL)
+       {
+         hicn_iface_ip_add (local_addr, remote_addr, sw_if, pfaceid);
+         face = hicn_dpoi_get_from_idx (*pfaceid);
+       }
+      else
+       {
+         *pfaceid = hicn_dpoi_get_index (face);
+       }
+
+      hicn_face_ip_key_t key;
+      hicn_face_ip4_get_key (&(local_addr->ip4), sw_if, &key);
+
+      mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0);
+
+      hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+      clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip4_address_t));
+      clib_memcpy (&ip_face->remote_addr, remote_addr,
+                  sizeof (ip4_address_t));
+      face->shared.sw_if = sw_if;
+      face->shared.flags = flags;
+      face->shared.adj = adj;
+
+      dpo_proto = DPO_PROTO_IP4;
+    }
+  else
+    {
+      face =
+       hicn_face_ip6_get (&(local_addr->ip6), sw_if,
+                          &hicn_face_ip_local_hashtb);
+
+      if (face != NULL)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      face =
+       hicn_face_ip6_get (&(remote_addr->ip6), sw_if,
+                          &hicn_face_ip_remote_hashtb);
+
+      /* If remote matches the face is a iface */
+      if (face == NULL)
+       {
+         hicn_iface_ip_add (local_addr, remote_addr, sw_if, pfaceid);
+         face = hicn_dpoi_get_from_idx (*pfaceid);
+       }
+      else
+       {
+         *pfaceid = hicn_dpoi_get_index (face);
+       }
+
+      hicn_face_ip_key_t key;
+      hicn_face_ip6_get_key (&(local_addr->ip6), sw_if, &key);
+
+      mhash_set_mem (&hicn_face_ip_local_hashtb, &key, (uword *) pfaceid, 0);
+
+      hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+      clib_memcpy (&ip_face->local_addr, local_addr, sizeof (ip6_address_t));
+      clib_memcpy (&ip_face->remote_addr, remote_addr,
+                  sizeof (ip6_address_t));
+      face->shared.sw_if = sw_if;
+      face->shared.flags = flags;
+      face->shared.adj = adj;
+
+      dpo_proto = DPO_PROTO_IP6;
+    }
+
+  retx_t *retx = vlib_process_signal_event_data (vlib_get_main (),
+                                                hicn_mapme_eventmgr_process_node.
+                                                index,
+                                                HICN_MAPME_EVENT_FACE_ADD, 1,
+                                                sizeof (retx_t));
+  *retx = (retx_t)
+  {
+    .prefix = 0,.dpo = (dpo_id_t)
+    {
+    .dpoi_type = hicn_face_ip_type,.dpoi_proto = dpo_proto,.dpoi_next_node =
+       0,.dpoi_index = *pfaceid,}
+  };
+
+  return HICN_ERROR_NONE;
+}
+
+u8 *
+format_hicn_face_ip (u8 * s, va_list * args)
+{
+  index_t index = va_arg (*args, index_t);
+  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
+  hicn_face_t *face;
+  hicn_face_ip_t *ip_face;
+  ip_adjacency_t *adj;
+  vnet_main_t *vnm = vnet_get_main ();
+
+  face = hicn_dpoi_get_from_idx (index);
+  ip_face = (hicn_face_ip_t *) face->data;
+
+  if (face->shared.flags & HICN_FACE_FLAGS_FACE)
+    {
+      ASSERT (face->shared.adj != (adj_index_t) ~ 0);
+      adj = adj_get (face->shared.adj);
+
+      hicn_face_id_t face_id = hicn_dpoi_get_index (face);
+      s = format (s, "%U Face %d: ", format_white_space, indent, face_id);
+      s = format (s, "type IP local %U ",
+                 format_ip46_address, &ip_face->local_addr, IP46_TYPE_ANY);
+      s =
+       format (s, "remote %U ", format_ip46_address, &ip_face->remote_addr,
+               IP46_TYPE_ANY);
+      s = format (s, "%U", format_vnet_link, adj->ia_link);
+      s = format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+                 vnet_get_sw_interface (vnm, face->shared.sw_if));
+
+      if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD))
+       s = format (s, " %U", format_hicn_face_prod, face_id, 0);
+      else if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS))
+       s = format (s, " %U", format_hicn_face_cons, face_id, 0);
+
+      if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+       s = format (s, " (deleted)");
+    }
+  else
+    {
+      hicn_face_id_t face_id = hicn_dpoi_get_index (face);
+      s = format (s, "%U iFace %d: ", format_white_space, indent, face_id);
+      s = format (s, "type IP local %U remote %U",
+                 format_ip46_address, &ip_face->local_addr, IP46_TYPE_ANY,
+                 format_ip46_address, &ip_face->remote_addr, IP46_TYPE_ANY);
+      s =
+       format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+               vnet_get_sw_interface (vnm, face->shared.sw_if));
+
+      if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD))
+       s = format (s, " %U", format_hicn_face_prod, face_id, 0);
+      else if ((face->shared.flags & HICN_FACE_FLAGS_APPFACE_CONS))
+       s = format (s, " %U", format_hicn_face_cons, face_id, 0);
+
+      if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+       s = format (s, " (deleted)");
+    }
+
+  return s;
+}
+
+void
+hicn_face_ip_get_dpo (hicn_face_t * face, dpo_id_t * dpo)
+{
+
+  hicn_face_ip_t *face_ip = (hicn_face_ip_t *) face->data;
+  return hicn_dpo_ip_create_from_face (face, dpo,
+                                      ip46_address_is_ip4 (&face_ip->
+                                                           remote_addr) ?
+                                      strategy_face_ip4_vlib_edge :
+                                      strategy_face_ip6_vlib_edge);
+}
+
+hicn_face_vft_t ip_vft = {
+  .format_face = format_hicn_face_ip,
+  .hicn_face_del = hicn_face_ip_del,
+  .hicn_face_get_dpo = hicn_face_ip_get_dpo,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/face_ip.h b/hicn-plugin/src/faces/ip/face_ip.h
new file mode 100755 (executable)
index 0000000..8c31f6d
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_IP_H__
+#define __HICN_FACE_IP_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include "../face.h"
+#include "../../cache_policies/cs_policy.h"
+
+/**
+ * @file
+ *
+ * @brief IP face
+ *
+ * A face is carried through nodes as a dpo. The face state is the object
+ * pointed by the dpoi_index in the dpo_id_t (see
+ * https://docs.fd.io/vpp/18.07/d0/d37/dpo_8h_source.html)
+ */
+typedef struct hicn_ip_face_t_
+{
+  /**
+   * The headers to paint, in packet painting order
+   */
+  /* Local address of the interface sw_if */
+  ip46_address_t local_addr;
+
+  /* Remote address of neighbor */
+  ip46_address_t remote_addr;
+
+} hicn_face_ip_t;
+
+
+/**
+ * Hash tables that indexes a face by local address. For fast lookup when an
+ * data arrives.
+ */
+extern mhash_t hicn_face_ip_local_hashtb;
+
+/**
+ * Hash tables that indexes a face by remote address. For fast lookup when an
+ * interest arrives.
+ */
+extern mhash_t hicn_face_ip_remote_hashtb;
+
+/**
+ * Key definition for the mhash table. An ip face is uniquely identified by ip
+ * address and the interface id. The ip address can correspond to the remote ip
+ * address of the next hicn hop, or to the local address of the receiving
+ * interface. The former is used to retrieve the incoming face when an interest
+ * is received, the latter when the arring packet is a data.
+ */
+typedef struct hicn_face_ip_key_s
+{
+  ip46_address_t addr;
+  u32 sw_if;
+} hicn_face_ip_key_t;
+
+
+extern hicn_face_type_t hicn_face_ip_type;
+extern hicn_face_vft_t ip_vft;
+
+/**
+ * @brief Create the key object for the mhash. Fill in the key object with the
+ * expected values.
+ *
+ * @param addr Local or remote ip v6 address of the face
+ * @param sw_if interface associated to the face
+ * @param key Pointer to an allocated hicn_face_ip_key_t object
+ */
+always_inline void
+hicn_face_ip6_get_key (const ip6_address_t * addr,
+                      u32 sw_if, hicn_face_ip_key_t * key)
+{
+  key->addr.ip6 = *addr;
+  key->sw_if = sw_if;
+}
+
+
+/**
+ * @brief Create the key object for the mhash. Fill in the key object with the
+ * expected values.
+ *
+ * @param addr Local or remote ip v4 address of the face
+ * @param sw_if interface associated to the face
+ * @param key Pointer to an allocated hicn_face_ip_key_t object
+ */
+always_inline void
+hicn_face_ip4_get_key (const ip4_address_t * addr,
+                      u32 sw_if, hicn_face_ip_key_t * key)
+{
+  ip46_address_set_ip4 (&(key->addr), addr);
+  key->sw_if = sw_if;
+}
+
+/**
+ * @brief Get the dpoi from the ip v4 address. Does not add any lock.
+ *
+ * @param addr Ip v4 address used to create the key for the hash table.
+ * @param sw_if Software interface id used to create the key for the hash table.
+ * @param hashtb Hash table (remote or local) where to perform the lookup.
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_t *
+hicn_face_ip4_get (const ip4_address_t * addr, u32 sw_if, mhash_t * hashtb)
+{
+  hicn_face_ip_key_t key;
+
+  hicn_face_ip4_get_key (addr, sw_if, &key);
+
+  hicn_face_id_t *dpoi_index = (hicn_face_id_t *) mhash_get (hashtb,
+                                                            &key);
+
+  return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index);
+}
+
+/**
+ * @brief Get the dpoi from the ip v6 address. Does not add any lock.
+ *
+ * @param addr Ip v6 address used to create the key for the hash table.
+ * @param sw_if Software interface id used to create the key for the hash table.
+ * @param hashtb Hash table (remote or local) where to perform the lookup.
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_t *
+hicn_face_ip6_get (const ip6_address_t * addr, u32 sw_if, mhash_t * hashtb)
+{
+  hicn_face_ip_key_t key;
+
+  hicn_face_ip6_get_key (addr, sw_if, &key);
+
+  hicn_face_id_t *dpoi_index = (hicn_face_id_t *) mhash_get (hashtb,
+                                                            &key);
+
+  return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index);
+}
+
+/**
+ * @brief Create a new face ip. API for other modules (e.g., routing)
+ *
+ * @param local_addr Local ip v4 or v6 address of the face
+ * @param remote_addr Remote ip v4 or v6 address of the face
+ * @param sw_if interface associated to the face
+ * @param is_app_face Boolean to set the face as an application face
+ * @param pfaceid Pointer to return the face id
+ * @return HICN_ERROR_FACE_NO_GLOBAL_IP if the face does not have a globally
+ * reachable ip address, otherwise HICN_ERROR_NONE
+ */
+int hicn_face_ip_add (const ip46_address_t * local_addr,
+                     const ip46_address_t * remote_addr,
+                     int swif, hicn_face_id_t * pfaceid);
+
+/**
+ * @brief Create a new incomplete face ip. (Meant to be used by the data plane)
+ *
+ * @param local_addr Local ip v4 or v6 address of the face
+ * @param remote_addr Remote ip v4 or v6 address of the face
+ * @param sw_if interface associated to the face
+ * @param pfaceid Pointer to return the face id
+ * @return HICN_ERROR_FACE_NO_GLOBAL_IP if the face does not have a globally
+ * reachable ip address, otherwise HICN_ERROR_NONE
+ */
+always_inline void
+hicn_iface_ip_add (const ip46_address_t * local_addr,
+                  const ip46_address_t * remote_addr,
+                  int sw_if, hicn_face_id_t * pfaceid)
+{
+  hicn_face_t *face;
+  pool_get (hicn_dpoi_face_pool, face);
+
+  hicn_face_ip_t *ip_face = (hicn_face_ip_t *) (face->data);
+
+  clib_memcpy (&(ip_face->local_addr.ip6), local_addr,
+              sizeof (ip6_address_t));
+  clib_memcpy (&(ip_face->remote_addr.ip6), remote_addr,
+              sizeof (ip6_address_t));
+  face->shared.sw_if = sw_if;
+
+  face->shared.adj = ADJ_INDEX_INVALID;
+  face->shared.pl_id = (u16) 0;
+  face->shared.face_type = hicn_face_ip_type;
+  face->shared.flags = HICN_FACE_FLAGS_IFACE;
+  face->shared.locks = 0;
+
+  hicn_face_ip_key_t key;
+  hicn_face_ip6_get_key (&(remote_addr->ip6), sw_if, &key);
+  *pfaceid = hicn_dpoi_get_index (face);
+
+  mhash_set_mem (&hicn_face_ip_remote_hashtb, &key, (uword *) pfaceid, 0);
+}
+
+/**
+ * @brief Delete an ip face
+ *
+ * @param face_id Id of the face to delete
+ * @return HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise
+ * HICN_ERROR_NONE
+ */
+int hicn_face_ip_del (hicn_face_id_t face_id);
+
+/**
+ * @brief Format a IP face
+ *
+ * @param s Pointer to a previous string. If null it will be initialize
+ * @param args Array storing input values. Expected u32 face_id and u32 indent
+ * @return String with the formatted face
+ */
+u8 *format_hicn_face_ip (u8 * s, va_list * args);
+
+/**
+ * @brief Create a dpo from an ip face
+ *
+ * @param face Face from which to create the dpo
+ * @return the dpo
+ */
+void hicn_face_ip_get_dpo (hicn_face_t * face, dpo_id_t * dpo);
+
+#endif // __HICN_FACE_IP_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/face_ip_cli.c b/hicn-plugin/src/faces/ip/face_ip_cli.c
new file mode 100755 (executable)
index 0000000..1558c82
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/vnet.h>
+#include <vnet/dpo/dpo.h>
+#include <vlib/vlib.h>
+
+#include "face_ip.h"
+#include "dpo_ip.h"
+#include "../face.h"
+
+#define HICN_FACE_NONE 0
+#define HICN_FACE_DELETE 1
+#define HICN_FACE_ADD 2
+
+static clib_error_t *
+hicn_face_ip_cli_set_command_fn (vlib_main_t * vm,
+                                unformat_input_t * main_input,
+                                vlib_cli_command_t * cmd)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  ip46_address_t local_addr;
+  ip46_address_t remote_addr;
+  hicn_face_id_t face_id = HICN_FACE_NULL;
+  int app_face = 0;
+  u32 cs_reserved = HICN_PARAM_FACE_DFT_CS_RESERVED;
+  int ret = HICN_ERROR_NONE;
+  int sw_if;
+  int face_op = HICN_FACE_NONE;
+
+  ip46_address_reset (&local_addr);
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       {
+         if (unformat (line_input, "id %d", &face_id))
+           face_op = HICN_FACE_DELETE;
+         else
+           {
+             return clib_error_return (0, "missing face id");
+           }
+       }
+      else if (unformat (line_input, "add"))
+       {
+         face_op = HICN_FACE_ADD;
+         if (unformat (line_input, "local %U remote %U intfc %U",
+                       unformat_ip46_address, &local_addr, IP46_TYPE_ANY,
+                       unformat_ip46_address, &remote_addr, IP46_TYPE_ANY,
+                       unformat_vnet_sw_interface, vnm, &sw_if));
+         else
+           {
+             return clib_error_return (0, "%s '%U'",
+                                       get_error_string
+                                       (HICN_ERROR_CLI_INVAL),
+                                       format_unformat_error, line_input);
+           }
+       }
+      else if (unformat (line_input, "app_face %d", &app_face))
+       {
+         if (unformat (line_input, "cs_size %d", &cs_reserved));
+       }
+      else
+       {
+         return clib_error_return (0, "%s '%U'",
+                                   get_error_string (HICN_ERROR_CLI_INVAL),
+                                   format_unformat_error, line_input);
+       }
+    }
+
+  if (face_id != HICN_FACE_NULL)
+    {
+
+      if (!hicn_dpoi_idx_is_valid (face_id))
+       {
+         return clib_error_return (0, "%s, face_id %d not valid",
+                                   get_error_string (ret), face_id);
+       }
+    }
+
+  int rv;
+  switch (face_op)
+    {
+    case HICN_FACE_ADD:
+
+      /* Check for presence of next hop address */
+      if ((remote_addr.as_u64[0] == (u64) 0)
+         && (remote_addr.as_u64[1] == (u64) 0))
+       {
+         return clib_error_return (0, "next hop address not specified");
+       }
+
+      rv = hicn_face_ip_add (&local_addr, &remote_addr, sw_if, &face_id);
+
+      if (rv == HICN_ERROR_NONE)
+       {
+         vlib_cli_output (vm, "Face id: %d", face_id);
+       }
+      else
+       {
+         return clib_error_return (0, get_error_string (rv));
+       }
+      break;
+    case HICN_FACE_DELETE:
+      rv = hicn_face_ip_del (face_id);
+      if (rv == HICN_ERROR_NONE)
+       {
+         vlib_cli_output (vm, "Face %d deleted", face_id);
+       }
+      else
+       {
+         return clib_error_return (0, get_error_string (rv));
+       }
+      break;
+    default:
+      return clib_error_return (0, "Operation (%d) not implemented", face_op);
+      break;
+    }
+  return (rv == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n",
+                                                         get_error_string
+                                                         (rv));
+}
+
+/* cli declaration for 'cfg face' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_face_ip_cli_set_command, static) =
+{
+  .path = "hicn face ip",
+  .short_help = "hicn face ip {add local <local_address> remote <remote_address> intfc <sw_if>} {app_face <0/1>} {cs_size <size_in_packets>} | {del id <face_id>}",
+  .function = hicn_face_ip_cli_set_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/face_ip_node.c b/hicn-plugin/src/faces/ip/face_ip_node.c
new file mode 100755 (executable)
index 0000000..6081e47
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/adj/adj.h>
+
+#include "face_ip.h"
+#include "face_ip_node.h"
+#include "dpo_ip.h"
+#include "../../strategy_dpo_manager.h"
+#include "../face.h"
+#include "../../cache_policies/cs_lru.h"
+#include "../../infra.h"
+#include "../../hicn.h"
+
+/**
+ * @File
+ *
+ * Definition of the nodes for ip incomplete faces.
+ */
+
+vlib_node_registration_t hicn_face_ip4_input_node;
+vlib_node_registration_t hicn_face_ip4_output_node;
+vlib_node_registration_t hicn_face_ip6_input_node;
+vlib_node_registration_t hicn_face_ip6_output_node;
+
+#define ip_v4 4
+#define ip_v6 6
+
+static char *hicn_face_ip4_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_face_ip6_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_ip4_input_trace_t;
+
+typedef enum
+{
+  HICN_FACE_IP4_INPUT_NEXT_DATA,
+  HICN_FACE_IP4_INPUT_NEXT_MAPME,
+  HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP,
+  HICN_FACE_IP4_INPUT_N_NEXT,
+} hicn_face_ip4_input_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_ip6_input_trace_t;
+
+typedef enum
+{
+  HICN_FACE_IP6_INPUT_NEXT_DATA,
+  HICN_FACE_IP6_INPUT_NEXT_MAPME,
+  HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP,
+  HICN_FACE_IP6_INPUT_N_NEXT,
+} hicn_face_ip6_input_next_t;
+
+#define NEXT_MAPME_IP4 HICN_FACE_IP4_INPUT_NEXT_MAPME
+#define NEXT_MAPME_IP6 HICN_FACE_IP6_INPUT_NEXT_MAPME
+#define NEXT_DATA_IP4 HICN_FACE_IP4_INPUT_NEXT_DATA
+#define NEXT_DATA_IP6 HICN_FACE_IP6_INPUT_NEXT_DATA
+
+#define NEXT_ERROR_DROP_IP4 HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP
+#define NEXT_ERROR_DROP_IP6 HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define LOCK_FROM_LOCAL_IP4 hicn_dpo_ip4_lock_from_local
+#define LOCK_FROM_LOCAL_IP6 hicn_dpo_ip6_lock_from_local
+
+#define TRACE_INPUT_PKT_IP4 hicn_face_ip4_input_trace_t
+#define TRACE_INPUT_PKT_IP6 hicn_face_ip6_input_trace_t
+
+/*
+ * NOTE: Both hicn_face_ip4_input_node_fn and hicn_face_ip6_input_node_fn
+ * present a similar codebase. Macro are hard to debug, although the
+ * followind code is pretty straighforward and most of the complexity is in
+ * functions that can be easily debug.
+ */
+#define face_input_x1(ipv)                                              \
+  do{                                                                   \
+  vlib_buffer_t *b0;                                                    \
+  u32 bi0;                                                              \
+  u32 next0 = NEXT_ERROR_DROP_IP##ipv;                                  \
+  IP_HEADER_##ipv * ip_hdr = NULL;                                      \
+  hicn_buffer_t * hicnb0;                                               \
+  int ret;                                                              \
+  /* Prefetch for next iteration. */                                    \
+  if (n_left_from > 1)                                                  \
+    {                                                                   \
+      vlib_buffer_t *b1;                                                \
+      b1 = vlib_get_buffer (vm, from[1]);                               \
+      CLIB_PREFETCH (b1, 2*CLIB_CACHE_LINE_BYTES, STORE);               \
+      CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);           \
+    }                                                                   \
+  /* Dequeue a packet buffer */                                         \
+  bi0 = from[0];                                                        \
+  from += 1;                                                            \
+  n_left_from -= 1;                                                     \
+  to_next[0] = bi0;                                                     \
+  to_next += 1;                                                         \
+  n_left_to_next -= 1;                                                  \
+                                                                        \
+  b0 = vlib_get_buffer (vm, bi0);                                       \
+  hicnb0 = hicn_get_buffer(b0);                                         \
+  ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);             \
+                                                                        \
+  u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv;                  \
+                                                                        \
+  next0 = is_icmp*NEXT_MAPME_IP##ipv +                                  \
+    (1-is_icmp)*NEXT_DATA_IP##ipv;                                      \
+                                                                        \
+  ret = LOCK_FROM_LOCAL_IP##ipv                                         \
+    (&(hicnb0->face_dpo_id),                                            \
+     &hicnb0->is_appface,                                               \
+     &(ip_hdr->dst_address),                                            \
+     vnet_buffer (b0)->sw_if_index[VLIB_RX]);                           \
+                                                                        \
+  if ( PREDICT_FALSE(ret != HICN_ERROR_NONE) )                          \
+    next0 = NEXT_ERROR_DROP_IP##ipv;                                    \
+  else                                                                  \
+    stats.pkts_data_count += 1;                                         \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_INPUT_PKT_IP##ipv *t =                                      \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* 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);                         \
+  }while(0)
+
+
+#define face_input_x2(ipv)                                              \
+  do{                                                                   \
+    vlib_buffer_t *b0, *b1;                                             \
+    u32 bi0, bi1;                                                       \
+    u32 next0 = NEXT_ERROR_DROP_IP##ipv;                                \
+    u32 next1 = NEXT_ERROR_DROP_IP##ipv;                                \
+    IP_HEADER_##ipv * ip_hdr0 = NULL;                                   \
+    IP_HEADER_##ipv * ip_hdr1 = NULL;                                   \
+    hicn_buffer_t * hicnb0;                                             \
+    hicn_buffer_t * hicnb1;                                             \
+    int ret0, ret1;                                                     \
+    /* Prefetch for next iteration. */                                  \
+    {                                                                   \
+      vlib_buffer_t *b2, *b3;                                           \
+      b2 = vlib_get_buffer (vm, from[2]);                               \
+      b3 = vlib_get_buffer (vm, from[3]);                               \
+      CLIB_PREFETCH (b2, 2*CLIB_CACHE_LINE_BYTES, STORE);              \
+      CLIB_PREFETCH (b3, 2*CLIB_CACHE_LINE_BYTES, STORE);              \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);           \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);           \
+    }                                                                   \
+    /* Dequeue a packet buffer */                                       \
+    bi0 = from[0];                                                      \
+    bi1 = from[1];                                                      \
+    from += 2;                                                          \
+    n_left_from -= 2;                                                   \
+    to_next[0] = bi0;                                                   \
+    to_next[1] = bi1;                                                   \
+    to_next += 2;                                                       \
+    n_left_to_next -= 2;                                                \
+                                                                        \
+    b0 = vlib_get_buffer (vm, bi0);                                     \
+    b1 = vlib_get_buffer (vm, bi1);                                     \
+    hicnb0 = hicn_get_buffer(b0);                                       \
+    hicnb1 = hicn_get_buffer(b1);                                       \
+    ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);          \
+    ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1);          \
+                                                                        \
+    u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv;              \
+    u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv;              \
+                                                                        \
+    next0 = is_icmp0*NEXT_MAPME_IP##ipv +                               \
+      (1-is_icmp0)*NEXT_DATA_IP##ipv;                                   \
+                                                                        \
+    next1 = is_icmp1*NEXT_MAPME_IP##ipv +                               \
+      (1-is_icmp1)*NEXT_DATA_IP##ipv;                                   \
+                                                                        \
+                                                                        \
+    ret0 = LOCK_FROM_LOCAL_IP##ipv                                      \
+      (&(hicnb0->face_dpo_id),                                          \
+       &hicnb0->is_appface,                                             \
+       &(ip_hdr0->dst_address),                                         \
+       vnet_buffer (b0)->sw_if_index[VLIB_RX]);                         \
+                                                                        \
+    ret1 = LOCK_FROM_LOCAL_IP##ipv                                      \
+      (&(hicnb1->face_dpo_id),                                          \
+       &hicnb1->is_appface,                                             \
+       &(ip_hdr1->dst_address),                                         \
+       vnet_buffer (b1)->sw_if_index[VLIB_RX]);                         \
+                                                                        \
+    if ( PREDICT_FALSE(ret0 != HICN_ERROR_NONE) )                       \
+      next0 = NEXT_ERROR_DROP_IP##ipv;                                  \
+    else                                                                \
+      stats.pkts_data_count += 1;                                       \
+                                                                        \
+    if ( PREDICT_FALSE(ret1 != HICN_ERROR_NONE) )                       \
+      next1 = NEXT_ERROR_DROP_IP##ipv;                                  \
+    else                                                                \
+      stats.pkts_data_count += 1;                                       \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_INPUT_PKT_IP##ipv *t =                                      \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b1->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_INPUT_PKT_IP##ipv *t =                                      \
+        vlib_add_trace (vm, node, b1, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];          \
+      t->next_index = next1;                                            \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* Verify speculative enqueue, 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(0)
+
+
+static uword
+hicn_face_ip4_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                            vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_input_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_input_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_ip4_input_format_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 *);
+  hicn_face_ip4_input_trace_t *t =
+    va_arg (*args, hicn_face_ip4_input_trace_t *);
+
+  s = format (s, "FACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_face_ip4_input_node) =
+{
+  .function = hicn_face_ip4_input_node_fn,
+  .name = "hicn-face-ip4-input",
+  .vector_size = sizeof(u32),
+  .format_trace = hicn_face_ip4_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_face_ip4_input_error_strings),
+  .error_strings = hicn_face_ip4_input_error_strings,
+  .n_next_nodes = HICN_FACE_IP4_INPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_FACE_IP4_INPUT_NEXT_DATA] = "hicn-data-pcslookup",
+    [HICN_FACE_IP4_INPUT_NEXT_MAPME] = "hicn-mapme-ack",
+    [HICN_FACE_IP4_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/**
+ * @brief IPv6 face input node function
+ * @see hicn_face_ip4_input_node_fn
+ */
+static uword
+hicn_face_ip6_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                            vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_input_x2 (6);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_input_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_ip6_input_format_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 *);
+  hicn_face_ip6_input_trace_t *t =
+    va_arg (*args, hicn_face_ip6_input_trace_t *);
+
+  s = format (s, "FACE_IP6_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_face_ip6_input_node) =
+{
+  .function = hicn_face_ip6_input_node_fn,
+  .name = "hicn-face-ip6-input",
+  .vector_size = sizeof(u32),
+  .format_trace = hicn_face_ip6_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_face_ip6_input_error_strings),
+  .error_strings = hicn_face_ip6_input_error_strings,
+  .n_next_nodes = HICN_FACE_IP6_INPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_FACE_IP6_INPUT_NEXT_DATA] = "hicn-data-pcslookup",
+    [HICN_FACE_IP6_INPUT_NEXT_MAPME] = "hicn-mapme-ack",
+    [HICN_FACE_IP6_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/**** FACE OUTPUT *****/
+
+static inline void
+hicn_face_rewrite_interest (vlib_main_t * vm, vlib_buffer_t * b0,
+                           const hicn_face_t * face, u32 * next)
+{
+  ip_adjacency_t *adj = adj_get (face->shared.adj);
+
+  /* We assume the ip adjacency has already the MAC/link layer address */
+  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = face->shared.adj;
+  hicn_header_t *hicn = vlib_buffer_get_current (b0);
+
+  hicn_face_ip_t *ip_face = (hicn_face_ip_t *) face->data;
+
+  ip46_address_t temp_addr;
+  ip46_address_reset (&temp_addr);
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  hicn_ops_vft[type.l1]->rewrite_interest (type, &hicn->protocol,
+                                          &ip_face->local_addr, &temp_addr);
+
+  /* We rewrite the dst address to send an arp/neighbour discovert request */
+  if (PREDICT_FALSE
+      (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP
+       || adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN))
+    hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol,
+                                        &ip_face->remote_addr, &temp_addr,
+                                        0);
+
+  *next = adj->lookup_next_index;
+}
+
+static char *hicn_face_ip4_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_face_ip6_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_ip4_output_trace_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_ip6_output_trace_t;
+
+#define TRACE_OUTPUT_PKT_IP4 hicn_face_ip4_output_trace_t
+#define TRACE_OUTPUT_PKT_IP6 hicn_face_ip6_output_trace_t
+
+#define face_output_x1(ipv)                                         \
+  do {                                                              \
+    vlib_buffer_t *b0;                                              \
+    u32 bi0;                                                        \
+    u32 next0 = IP_LOOKUP_NEXT_DROP;                               \
+    hicn_face_t * face;                                             \
+                                                                    \
+    /* Prefetch for next iteration. */                              \
+    if (n_left_from > 1)                                            \
+      {                                                             \
+        vlib_buffer_t *b1;                                          \
+        b1 = vlib_get_buffer (vm, from[1]);                         \
+        CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);          \
+        CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , STORE);    \
+      }                                                             \
+    /* Dequeue a packet buffer */                                   \
+    bi0 = from[0];                                                  \
+    from += 1;                                                      \
+    n_left_from -= 1;                                               \
+    to_next[0] = bi0;                                               \
+    to_next += 1;                                                   \
+    n_left_to_next -= 1;                                            \
+                                                                    \
+    b0 = vlib_get_buffer (vm, bi0);                                 \
+                                                                    \
+    face =                                                              \
+      hicn_dpoi_get_from_idx (vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+                                                                        \
+    if (PREDICT_TRUE(face != NULL))                                     \
+      {                                                                 \
+        hicn_face_rewrite_interest                                     \
+          (vm, b0, face, &next0);                                      \
+       stats.pkts_interest_count += 1;                                 \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_OUTPUT_PKT_IP##ipv *t =                                   \
+          vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+        t->next_index = next0;                                          \
+      }                                                                 \
+                                                                        \
+                                                                        \
+    /* 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);                       \
+  }while(0)
+
+#define face_output_x2(ipv)                                         \
+  do {                                                              \
+    vlib_buffer_t *b0, *b1;                                         \
+    u32 bi0, bi1;                                                   \
+    u32 next0 = IP_LOOKUP_NEXT_DROP;                               \
+    u32 next1 = IP_LOOKUP_NEXT_DROP;                               \
+    hicn_face_t *face0, *face1;                                     \
+                                                                    \
+    /* Prefetch for next iteration. */                              \
+    {                                                               \
+      vlib_buffer_t *b2, *b3;                                       \
+      b2 = vlib_get_buffer (vm, from[2]);                           \
+      b3 = vlib_get_buffer (vm, from[3]);                           \
+      CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , STORE);      \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , STORE);      \
+    }                                                               \
+  /* Dequeue a packet buffer */                                     \
+    bi0 = from[0];                                                  \
+    bi1 = from[1];                                                  \
+    from += 2;                                                      \
+    n_left_from -= 2;                                               \
+    to_next[0] = bi0;                                               \
+    to_next[1] = bi1;                                               \
+    to_next += 2;                                                   \
+    n_left_to_next -= 2;                                            \
+                                                                    \
+    b0 = vlib_get_buffer (vm, bi0);                                 \
+    b1 = vlib_get_buffer (vm, bi1);                                 \
+                                                                    \
+    face0 =                                                             \
+      hicn_dpoi_get_from_idx (vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+    face1 =                                                             \
+      hicn_dpoi_get_from_idx (vnet_buffer (b1)->ip.adj_index[VLIB_TX]); \
+                                                                        \
+    if (PREDICT_TRUE(face0 != NULL))                                    \
+      {                                                                 \
+        hicn_face_rewrite_interest                                     \
+          (vm, b0, face0, &next0);                                     \
+       stats.pkts_interest_count += 1;                                 \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_TRUE(face1 != NULL))                                    \
+      {                                                                 \
+        hicn_face_rewrite_interest                                     \
+          (vm, b1, face1, &next1);                                     \
+       stats.pkts_interest_count += 1;                                 \
+      }                                                                 \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_OUTPUT_PKT_IP##ipv *t =                                     \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b1->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_OUTPUT_PKT_IP##ipv *t =                                     \
+        vlib_add_trace (vm, node, b1, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];          \
+      t->next_index = next1;                                            \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* Verify speculative enqueue, 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(0)
+
+
+static uword
+hicn_face_ip4_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_output_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_output_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_ip4_output_format_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 *);
+  hicn_face_ip4_output_trace_t *t =
+    va_arg (*args, hicn_face_ip4_output_trace_t *);
+
+  s = format (s, "FACE_IP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_face_ip4_output_node) =
+{
+  .function = hicn_face_ip4_output_node_fn,
+  .name = "hicn-face-ip4-output",
+  .vector_size = sizeof(u32),
+  .format_trace = hicn_face_ip4_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_face_ip4_output_error_strings),
+  .error_strings = hicn_face_ip4_output_error_strings,
+  .n_next_nodes = IP4_LOOKUP_N_NEXT,
+  /* Reusing the list of nodes from lookup to be compatible with arp */
+  .next_nodes = IP4_LOOKUP_NEXT_NODES,
+};
+/* *INDENT-ON* */
+
+
+static uword
+hicn_face_ip6_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_output_x2 (6);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_output_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_ip6_output_format_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 *);
+  hicn_face_ip6_output_trace_t *t =
+    va_arg (*args, hicn_face_ip6_output_trace_t *);
+
+  s = format (s, "FACE_IP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_face_ip6_output_node) =
+{
+  .function = hicn_face_ip6_output_node_fn,
+  .name = "hicn-face-ip6-output",
+  .vector_size = sizeof(u32),
+  .format_trace = hicn_face_ip6_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_face_ip6_output_error_strings),
+  .error_strings = hicn_face_ip6_output_error_strings,
+  .n_next_nodes = IP6_LOOKUP_N_NEXT,
+  /* Reusing the list of nodes from lookup to be compatible with neighbour discovery */
+  .next_nodes = IP6_LOOKUP_NEXT_NODES,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/face_ip_node.h b/hicn-plugin/src/faces/ip/face_ip_node.h
new file mode 100755 (executable)
index 0000000..000395a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_IP_NODE_H__
+#define __HICN_FACE_IP_NODE_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+extern vlib_node_registration_t hicn_face_ip4_input_node;
+extern vlib_node_registration_t hicn_face_ip4_output_node;
+extern vlib_node_registration_t hicn_face_ip6_input_node;
+extern vlib_node_registration_t hicn_face_ip6_output_node;
+
+/**
+ * @brief Initialize the ip face module
+ */
+void hicn_face_ip_init (vlib_main_t * vm);
+
+#endif // __HICN_FACE_IP_NODE_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/iface_ip_node.c b/hicn-plugin/src/faces/ip/iface_ip_node.c
new file mode 100755 (executable)
index 0000000..8df0467
--- /dev/null
@@ -0,0 +1,845 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/hicn.h>
+#include "face_ip.h"
+#include "dpo_ip.h"
+#include "../../strategy_dpo_manager.h"
+#include "../face.h"
+#include "../../infra.h"
+#include "../../cache_policies/cs_lru.h"
+
+/**
+ * @File
+ *
+ * Definition of the nodes for ip incomplete faces.
+ */
+
+vlib_node_registration_t hicn_iface_ip4_input_node;
+vlib_node_registration_t hicn_iface_ip4_output_node;
+vlib_node_registration_t hicn_iface_ip6_input_node;
+vlib_node_registration_t hicn_iface_ip6_output_node;
+
+u32 data_fwd_iface_ip4_vlib_edge;
+u32 data_fwd_iface_ip6_vlib_edge;
+
+void
+hicn_iface_ip_init (vlib_main_t * vm)
+{
+  u32 temp_index4 = vlib_node_add_next (vm,
+                                       hicn_interest_hitcs_node.index,
+                                       hicn_iface_ip4_output_node.index);
+  u32 temp_index6 = vlib_node_add_next (vm,
+                                       hicn_interest_hitcs_node.index,
+                                       hicn_iface_ip6_output_node.index);
+
+  data_fwd_iface_ip4_vlib_edge = vlib_node_add_next (vm,
+                                                    hicn_data_fwd_node.index,
+                                                    hicn_iface_ip4_output_node.
+                                                    index);
+
+  data_fwd_iface_ip6_vlib_edge = vlib_node_add_next (vm,
+                                                    hicn_data_fwd_node.index,
+                                                    hicn_iface_ip6_output_node.
+                                                    index);
+
+  ASSERT (temp_index4 == data_fwd_iface_ip4_vlib_edge);
+  ASSERT (temp_index6 == data_fwd_iface_ip6_vlib_edge);
+}
+
+static char *hicn_iface_ip4_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_iface_ip6_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_ip4_input_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_IP4_INPUT_NEXT_INTEREST,
+  HICN_IFACE_IP4_INPUT_NEXT_MAPME,
+  HICN_IFACE_IP4_INPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_IP4_INPUT_N_NEXT,
+} hicn_iface_ip4_input_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_ip6_input_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_IP6_INPUT_NEXT_INTEREST,
+  HICN_IFACE_IP6_INPUT_NEXT_MAPME,
+  HICN_IFACE_IP6_INPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_IP6_INPUT_N_NEXT,
+} hicn_iface_ip6_input_next_t;
+
+#define NEXT_MAPME_IP4 HICN_IFACE_IP4_INPUT_NEXT_MAPME
+#define NEXT_MAPME_IP6 HICN_IFACE_IP6_INPUT_NEXT_MAPME
+
+#define NEXT_INTEREST_IP4 HICN_IFACE_IP6_INPUT_NEXT_INTEREST
+#define NEXT_INTEREST_IP6 HICN_IFACE_IP6_INPUT_NEXT_INTEREST
+
+#define ADDRESS_IP4 ip_interface_address_t *ia = 0;ip4_address_t *local_address = ip4_interface_first_address(&ip4_main, swif, &ia)
+#define ADDRESS_IP6 ip6_address_t *local_address = ip6_interface_first_address(&ip6_main, swif)
+
+#define ADDRESSX2_IP4 ip_interface_address_t *ia0, *ia1; ia0 = ia1 = 0;                \
+  ip4_address_t *local_address0 = ip4_interface_first_address(&ip4_main, swif0, &ia0); \
+  ip4_address_t *local_address1 = ip4_interface_first_address(&ip4_main, swif1, &ia1);
+
+#define ADDRESSX2_IP6 ip6_address_t *local_address0 = ip6_interface_first_address(&ip6_main, swif0); \
+  ip6_address_t *local_address1 = ip6_interface_first_address(&ip6_main, swif1);
+
+#define DPO_ADD_LOCK_IP4 hicn_dpo_ip4_add_and_lock_from_remote
+#define DPO_ADD_LOCK_IP6 hicn_dpo_ip6_add_and_lock_from_remote
+
+#define VLIB_EDGE_IP4 data_fwd_iface_ip4_vlib_edge
+#define VLIB_EDGE_IP6 data_fwd_iface_ip6_vlib_edge
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define TRACE_INPUT_PKT_IP4 hicn_iface_ip4_input_trace_t
+#define TRACE_INPUT_PKT_IP6 hicn_iface_ip6_input_trace_t
+
+#define iface_input_x1(ipv)                                             \
+  do {                                                                  \
+  vlib_buffer_t *b0;                                                    \
+  u32 bi0, next0;                                                       \
+  IP_HEADER_##ipv * ip_hdr = NULL;                                      \
+  hicn_buffer_t * hicnb0;                                               \
+  u32 swif;                                                             \
+  /* Prefetch for next iteration. */                                    \
+  if (n_left_from > 1)                                                  \
+    {                                                                   \
+      vlib_buffer_t *b1;                                                \
+      b1 = vlib_get_buffer (vm, from[1]);                               \
+      CLIB_PREFETCH (b1, 2*CLIB_CACHE_LINE_BYTES, STORE);              \
+      CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);           \
+    }                                                                   \
+  /* Dequeue a packet buffer */                                         \
+  bi0 = from[0];                                                        \
+  from += 1;                                                            \
+  n_left_from -= 1;                                                     \
+  to_next[0] = bi0;                                                     \
+  to_next += 1;                                                         \
+  n_left_to_next -= 1;                                                  \
+                                                                        \
+  b0 = vlib_get_buffer (vm, bi0);                                       \
+  hicnb0 = hicn_get_buffer(b0);                                         \
+  ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);             \
+                                                                        \
+  stats.pkts_interest_count += 1;                                       \
+                                                                        \
+  u8 is_icmp = ip_hdr->protocol == IPPROTO_ICMPV##ipv;                  \
+                                                                        \
+  next0 = is_icmp*NEXT_MAPME_IP##ipv +                                  \
+    (1-is_icmp)*NEXT_INTEREST_IP##ipv;                                  \
+                                                                        \
+  swif = vnet_buffer (b0)->sw_if_index[VLIB_RX];                        \
+                                                                        \
+  ADDRESS_IP##ipv;                                                      \
+                                                                        \
+  DPO_ADD_LOCK_IP##ipv                                                  \
+  (&(hicnb0->face_dpo_id),                                              \
+   &hicnb0->is_appface,                                                 \
+   local_address,                                                       \
+   &(ip_hdr->src_address),                                              \
+   vnet_buffer(b0)->sw_if_index[VLIB_RX],                               \
+   VLIB_EDGE_IP##ipv);                                                  \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_INPUT_PKT_IP##ipv *t =                                      \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* 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);                         \
+  }while(0)
+
+
+#define iface_input_x2(ipv)                                             \
+  do {                                                                  \
+    vlib_buffer_t *b0, *b1;                                             \
+    u32 bi0, bi1, next0, next1;                                         \
+    IP_HEADER_##ipv * ip_hdr0 = NULL;                                   \
+    IP_HEADER_##ipv * ip_hdr1 = NULL;                                   \
+    hicn_buffer_t *hicnb0, *hicnb1;                                     \
+    u32 swif0, swif1;                                                   \
+                                                                        \
+    /* Prefetch for next iteration. */                                  \
+    vlib_buffer_t *b2, *b3;                                             \
+    b2 = vlib_get_buffer (vm, from[2]);                                 \
+    b3 = vlib_get_buffer (vm, from[3]);                                 \
+    CLIB_PREFETCH (b2, 2*CLIB_CACHE_LINE_BYTES, STORE);                        \
+    CLIB_PREFETCH (b3, 2*CLIB_CACHE_LINE_BYTES, STORE);                        \
+    CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);             \
+    CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);             \
+                                                                        \
+    /* Dequeue a packet buffer */                                       \
+    bi0 = from[0];                                                      \
+    bi1 = from[1];                                                      \
+    from += 2;                                                          \
+    n_left_from -= 2;                                                   \
+    to_next[0] = bi0;                                                   \
+    to_next[1] = bi1;                                                   \
+    to_next += 2;                                                       \
+    n_left_to_next -= 2;                                                \
+                                                                        \
+    b0 = vlib_get_buffer (vm, bi0);                                     \
+    b1 = vlib_get_buffer (vm, bi1);                                     \
+    hicnb0 = hicn_get_buffer(b0);                                       \
+    hicnb1 = hicn_get_buffer(b1);                                       \
+    ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);          \
+    ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1);          \
+                                                                        \
+    stats.pkts_interest_count += 2;                                     \
+                                                                        \
+    u8 is_icmp0 = ip_hdr0->protocol == IPPROTO_ICMPV##ipv;              \
+    u8 is_icmp1 = ip_hdr1->protocol == IPPROTO_ICMPV##ipv;              \
+                                                                        \
+    next0 = is_icmp0*NEXT_MAPME_IP##ipv +                               \
+      (1-is_icmp0)*NEXT_INTEREST_IP##ipv;                               \
+                                                                        \
+    next1 = is_icmp1*NEXT_MAPME_IP##ipv +                               \
+      (1-is_icmp1)*NEXT_INTEREST_IP##ipv;                               \
+                                                                        \
+    swif0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];                     \
+    swif1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];                     \
+                                                                        \
+    ADDRESSX2_IP##ipv;                                                  \
+                                                                        \
+    DPO_ADD_LOCK_IP##ipv                                                \
+      (&(hicnb0->face_dpo_id),                                          \
+       &hicnb0->is_appface,                                             \
+       local_address0,                                                  \
+       &(ip_hdr0->src_address),                                         \
+       vnet_buffer(b0)->sw_if_index[VLIB_RX],                           \
+       VLIB_EDGE_IP##ipv);                                              \
+                                                                        \
+    DPO_ADD_LOCK_IP##ipv                                                \
+      (&(hicnb1->face_dpo_id),                                          \
+       &hicnb1->is_appface,                                             \
+       local_address1,                                                  \
+       &(ip_hdr1->src_address),                                         \
+       vnet_buffer(b1)->sw_if_index[VLIB_RX],                           \
+       VLIB_EDGE_IP##ipv);                                              \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_INPUT_PKT_IP##ipv *t =                                    \
+          vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+        t->next_index = next0;                                          \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b1->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_INPUT_PKT_IP##ipv *t =                                    \
+          vlib_add_trace (vm, node, b1, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];        \
+        t->next_index = next1;                                          \
+      }                                                                 \
+                                                                        \
+    /* Verify speculative enqueue, 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(0)
+
+static uword
+hicn_iface_ip4_input_node_fn (vlib_main_t * vm,
+                             vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         iface_input_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_input_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_ip4_input_format_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 *);
+  hicn_iface_ip4_input_trace_t *t =
+    va_arg (*args, hicn_iface_ip4_input_trace_t *);
+
+  s = format (s, "IFACE_IP4_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_ip4_input_node) =
+{
+  .function = hicn_iface_ip4_input_node_fn,
+  .name = "hicn-iface-ip4-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_ip4_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_ip4_input_error_strings),
+  .error_strings = hicn_iface_ip4_input_error_strings,
+  .n_next_nodes = HICN_IFACE_IP4_INPUT_N_NEXT,
+  /* edit / add dispositions*/
+  .next_nodes =
+  {
+    [HICN_IFACE_IP4_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup",
+    [HICN_IFACE_IP4_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl",
+    [HICN_IFACE_IP4_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+static uword
+hicn_iface_ip6_input_node_fn (vlib_main_t * vm,
+                             vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         iface_input_x2 (6);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_input_x1 (6);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_ip6_input_format_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 *);
+  hicn_iface_ip6_input_trace_t *t =
+    va_arg (*args, hicn_iface_ip6_input_trace_t *);
+
+  s = format (s, "IFACE_IP6_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_ip6_input_node) =
+{
+  .function = hicn_iface_ip6_input_node_fn,
+  .name = "hicn-iface-ip6-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_ip6_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_ip6_input_error_strings),
+  .error_strings = hicn_iface_ip6_input_error_strings,
+  .n_next_nodes = HICN_IFACE_IP6_INPUT_N_NEXT,
+  /* edit / add dispositions*/
+  .next_nodes =
+  {
+    [HICN_IFACE_IP6_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup",
+    [HICN_IFACE_IP6_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl",
+    [HICN_IFACE_IP6_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+/**** IFACE OUTPUT *****/
+
+static inline void
+hicn_rewrite_iface_data4 (vlib_main_t * vm, vlib_buffer_t * b0,
+                         const hicn_face_t * iface)
+{
+  ip4_header_t *ip0;
+
+  /* Get the pointer to the old ip and tcp header */
+  ip0 = vlib_buffer_get_current (b0);
+
+  /* Set up the ip6 header */
+  /* IP4 lenght contains the size of the ip4 header too */
+  u16 sval = (vlib_buffer_length_in_chain (vm, b0));
+  ip0->length = clib_host_to_net_u16 (sval);
+  ip0->ttl = 254;              // FIXME TTL
+
+  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ~0;
+  hicn_header_t *hicn = vlib_buffer_get_current (b0);
+
+  ip46_address_t temp_addr;
+  ip46_address_reset (&temp_addr);
+  hicn_face_ip_t *iface_ip = (hicn_face_ip_t *) iface->data;
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol,
+                                      &(iface_ip->remote_addr), &(temp_addr),
+                                      iface->shared.pl_id);
+}
+
+static inline void
+hicn_rewrite_iface_data6 (vlib_main_t * vm, vlib_buffer_t * b0,
+                         const hicn_face_t * iface)
+{
+  ip6_header_t *ip0;
+
+  /* Get the pointer to the old ip and tcp header */
+  /* Copy the previous ip and tcp header to the new portion of memory */
+  ip0 = vlib_buffer_get_current (b0);
+
+  /* Set up the ip6 header */
+  /* IP6 lenght does not include the size of the ip6 header */
+  u16 sval = (vlib_buffer_length_in_chain (vm, b0) - (sizeof (ip6_header_t)));
+  ip0->payload_length = clib_host_to_net_u16 (sval);
+  ip0->hop_limit = HICN_IP6_HOP_LIMIT;
+
+  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = ~0;
+  hicn_header_t *hicn = vlib_buffer_get_current (b0);
+
+  ip46_address_t temp_addr;
+  ip46_address_reset (&temp_addr);
+  hicn_face_ip_t *iface_ip = (hicn_face_ip_t *) iface->data;
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  hicn_ops_vft[type.l1]->rewrite_data (type, &hicn->protocol,
+                                      &(iface_ip->remote_addr), &(temp_addr),
+                                      iface->shared.pl_id);
+}
+
+static char *hicn_iface_ip4_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_iface_ip6_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_ip4_output_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP,
+  HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_IP4_OUTPUT_N_NEXT,
+} hicn_iface_ip4_output_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_ip6_output_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP,
+  HICN_IFACE_IP6_OUTPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_IP6_OUTPUT_N_NEXT,
+} hicn_iface_ip6_output_next_t;
+
+#define ERROR_OUTPUT_IP4 HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP
+#define ERROR_OUTPUT_IP6 HICN_IFACE_IP6_OUTPUT_NEXT_ERROR_DROP
+
+#define NEXT_DATA_LOOKUP_IP4 HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP
+#define NEXT_DATA_LOOKUP_IP6 HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP
+
+#define HICN_REWRITE_DATA_IP4 hicn_rewrite_iface_data4
+#define HICN_REWRITE_DATA_IP6 hicn_rewrite_iface_data6
+
+#define TRACE_OUTPUT_PKT_IP4 hicn_iface_ip4_output_trace_t
+#define TRACE_OUTPUT_PKT_IP6 hicn_iface_ip6_output_trace_t
+
+#define iface_output_x1(ipv)                                            \
+  do {                                                                  \
+    vlib_buffer_t *b0;                                                  \
+    u32 bi0;                                                            \
+    u32 next0 = ERROR_OUTPUT_IP##ipv;                                   \
+    hicn_face_t * face;                                                 \
+                                                                       \
+  /* Prefetch for next iteration. */                                   \
+    if (n_left_from > 1)                                                \
+      {                                                                 \
+        vlib_buffer_t *b1;                                              \
+        b1 = vlib_get_buffer (vm, from[1]);                             \
+        CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);               \
+        CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , STORE);       \
+      }                                                                 \
+    /* Dequeue a packet buffer */                                       \
+    bi0 = from[0];                                                      \
+    from += 1;                                                          \
+    n_left_from -= 1;                                                   \
+    to_next[0] = bi0;                                                   \
+    to_next += 1;                                                       \
+    n_left_to_next -= 1;                                                \
+                                                                        \
+    b0 = vlib_get_buffer (vm, bi0);                                     \
+                                                                        \
+    face =                                                              \
+      hicn_dpoi_get_from_idx (vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+                                                                        \
+    if (PREDICT_TRUE(face != NULL))                                     \
+      {                                                                 \
+        HICN_REWRITE_DATA_IP##ipv                                      \
+          (vm, b0, face);                                               \
+       next0 = NEXT_DATA_LOOKUP_IP##ipv;                               \
+       stats.pkts_data_count += 1;                                     \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_OUTPUT_PKT_IP##ipv *t =                                   \
+          vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+        t->next_index = next0;                                          \
+      }                                                                 \
+                                                                        \
+                                                                        \
+    /* 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);                       \
+  }while(0);                                                            \
+
+
+#define iface_output_x2(ipv)                                            \
+  do {                                                                  \
+    vlib_buffer_t *b0, *b1;                                             \
+    u32 bi0, bi1;                                                       \
+    u32 next0 = ERROR_OUTPUT_IP##ipv;                                   \
+    u32 next1 = ERROR_OUTPUT_IP##ipv;                                   \
+    hicn_face_t *face0, *face1;                                         \
+                                                                        \
+    /* Prefetch for next iteration. */                                  \
+    {                                                                   \
+      vlib_buffer_t *b2, *b3;                                           \
+      b2 = vlib_get_buffer (vm, from[2]);                               \
+      b3 = vlib_get_buffer (vm, from[3]);                               \
+      CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);                 \
+      CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);                 \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , STORE);         \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , STORE);         \
+    }                                                                   \
+                                                                        \
+    /* Dequeue a packet buffer */                                       \
+    bi0 = from[0];                                                      \
+    bi1 = from[1];                                                      \
+    from += 2;                                                          \
+    n_left_from -= 2;                                                   \
+    to_next[0] = bi0;                                                   \
+    to_next[1] = bi1;                                                   \
+    to_next += 2;                                                       \
+    n_left_to_next -= 2;                                                \
+                                                                        \
+    b0 = vlib_get_buffer (vm, bi0);                                     \
+    b1 = vlib_get_buffer (vm, bi1);                                     \
+                                                                        \
+    face0 =                                                             \
+      hicn_dpoi_get_from_idx (vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+    face1 =                                                             \
+      hicn_dpoi_get_from_idx (vnet_buffer (b1)->ip.adj_index[VLIB_TX]); \
+                                                                        \
+    if (PREDICT_TRUE(face0 != NULL))                                    \
+      {                                                                 \
+        HICN_REWRITE_DATA_IP##ipv                                      \
+          (vm, b0, face0);                                              \
+       next0 = NEXT_DATA_LOOKUP_IP##ipv;                               \
+       stats.pkts_data_count += 1;                                     \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_TRUE(face1 != NULL))                                    \
+      {                                                                 \
+        HICN_REWRITE_DATA_IP##ipv                                      \
+          (vm, b1, face1);                                              \
+        next1 = NEXT_DATA_LOOKUP_IP##ipv;                              \
+       stats.pkts_data_count += 1;                                     \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_OUTPUT_PKT_IP##ipv *t =                                   \
+          vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+        t->next_index = next0;                                          \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b1->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_OUTPUT_PKT_IP##ipv *t =                                   \
+          vlib_add_trace (vm, node, b1, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];        \
+        t->next_index = next1;                                          \
+      }                                                                 \
+                                                                        \
+                                                                        \
+    /* Verify speculative enqueue, 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(0);                                                            \
+
+
+
+static uword
+hicn_iface_ip4_output_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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)
+       {
+         iface_output_x2 (4);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_output_x1 (4);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_ip4_output_format_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 *);
+  hicn_iface_ip4_output_trace_t *t =
+    va_arg (*args, hicn_iface_ip4_output_trace_t *);
+
+  s = format (s, "IFACE_IP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_ip4_output_node) =
+{
+  .function = hicn_iface_ip4_output_node_fn,
+  .name = "hicn-iface-ip4-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_ip4_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_ip4_output_error_strings),
+  .error_strings = hicn_iface_ip4_output_error_strings,
+  .n_next_nodes = HICN_IFACE_IP4_OUTPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_IFACE_IP4_OUTPUT_NEXT_LOOKUP] = "ip4-lookup",
+    [HICN_IFACE_IP4_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+static uword
+hicn_iface_ip6_output_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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)
+       {
+         iface_output_x2 (6);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_output_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_ip6_output_format_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 *);
+  hicn_iface_ip6_output_trace_t *t =
+    va_arg (*args, hicn_iface_ip6_output_trace_t *);
+
+  s = format (s, "IFACE_IP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_ip6_output_node) =
+{
+  .function = hicn_iface_ip6_output_node_fn,
+  .name = "hicn-iface-ip6-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_ip6_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_ip6_output_error_strings),
+  .error_strings = hicn_iface_ip6_output_error_strings,
+  .n_next_nodes = HICN_IFACE_IP6_OUTPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_IFACE_IP6_OUTPUT_NEXT_LOOKUP] = "ip6-lookup",
+    [HICN_IFACE_IP6_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/ip/iface_ip_node.h b/hicn-plugin/src/faces/ip/iface_ip_node.h
new file mode 100755 (executable)
index 0000000..36923f0
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_IFACE_IP_NODE_H__
+#define __HICN_IFACE_IP_NODE_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+/**
+ * @brief Initialize the ip iface module
+ */
+void hicn_iface_ip_init (vlib_main_t * vm);
+
+#endif // __HICN_IFACE_IP_NODE_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/dpo_udp.c b/hicn-plugin/src/faces/udp/dpo_udp.c
new file mode 100755 (executable)
index 0000000..e58fc97
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017-2019 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 "dpo_udp.h"
+
+#include <vnet/ip/format.h>
+#include <vnet/adj/adj.h>
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+
+const static char *const hicn_face_ip4udp_nodes[] = {
+  "hicn-face-encap-udp4",
+  "hicn-face-decap-udp4",
+  "hicn-iface-decap-udp4",
+  "hicn-iface-encap-udp4",
+  NULL,
+};
+
+const static char *const hicn_face_ip6udp_nodes[] = {
+  "hicn-face-encap-udp6",
+  "hicn-face-decap-udp6",
+  "hicn-iface-decap-udp6",
+  "hicn-iface-encap-udp6",
+  NULL,
+};
+
+const static char *const *const hicn_ipudp_nodes[DPO_PROTO_NUM] = {
+  [DPO_PROTO_IP4] = hicn_face_ip4udp_nodes,
+  [DPO_PROTO_IP6] = hicn_face_ip6udp_nodes
+};
+
+
+const static dpo_vft_t hicn_dpoi_udp_vft = {
+  .dv_lock = hicn_face_lock,
+  .dv_unlock = hicn_face_unlock,
+  .dv_format = format_hicn_face_udp,
+};
+
+/* Must be executed after all the strategy nodes are created */
+void
+hicn_dpo_udp_module_init (void)
+{
+  mhash_init (&hicn_face_udp_hashtb, sizeof (hicn_face_id_t) /* value */ ,
+             sizeof (hicn_face_udp_key_t) /* key */ );
+
+  /*
+   * How much useful is the following registration?
+   * So far it seems that we need it only for setting the dpo_type.
+   */
+  hicn_face_udp_type =
+    dpo_register_new_type (&hicn_dpoi_udp_vft, hicn_ipudp_nodes);
+}
+
+
+/* Here udp ports are in host order, move them to network order to do the lookup */
+int
+hicn_dpo_udp4_create (dpo_id_t * dpo,
+                     const ip4_address_t * src_ip,
+                     const ip4_address_t * dst_ip,
+                     u16 src_port, u16 dst_port,
+                     u32 sw_if,
+                     adj_index_t ip_adj,
+                     u32 node_index,
+                     hicn_face_flags_t flags, hicn_face_id_t * face_id)
+{
+  u16 net_src_port = clib_host_to_net_u16 (src_port);
+  u16 net_dst_port = clib_host_to_net_u16 (dst_port);
+  hicn_face_t *face = hicn_face_udp4_get (src_ip, dst_ip, src_port, dst_port);
+
+  u8 is_appface;
+  /* ip_csum_t sum0; */
+
+  if (face != NULL)
+    return HICN_ERROR_FACE_ALREADY_CREATED;
+
+  hicn_dpo_udp4_add_and_lock (dpo, src_ip, dst_ip, net_src_port, net_dst_port,
+                             node_index, &is_appface);
+
+  face = hicn_dpoi_get_from_idx (dpo->dpoi_index);
+
+  hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data;
+
+  udp_face->hdrs.ip4.ip.checksum =
+    ip4_header_checksum (&(udp_face->hdrs.ip4.ip));
+
+  face->shared.flags = flags;
+  face->shared.adj = ip_adj;
+  face->shared.sw_if = sw_if;
+  *face_id = hicn_dpoi_get_index (face);
+
+  return HICN_ERROR_NONE;
+}
+
+
+int
+hicn_dpo_udp6_create (dpo_id_t * dpo,
+                     const ip6_address_t * src_ip,
+                     const ip6_address_t * dst_ip,
+                     u16 src_port, u16 dst_port,
+                     u32 sw_if,
+                     adj_index_t ip_adj,
+                     u32 node_index,
+                     hicn_face_flags_t flags, hicn_face_id_t * face_id)
+{
+  u16 net_src_port = clib_host_to_net_u16 (src_port);
+  u16 net_dst_port = clib_host_to_net_u16 (dst_port);
+  hicn_face_t *face =
+    hicn_face_udp6_get (src_ip, dst_ip, net_src_port, net_dst_port);
+  u8 is_appface;
+
+  if (face != NULL)
+    return HICN_ERROR_FACE_ALREADY_CREATED;
+
+  hicn_dpo_udp6_add_and_lock (dpo, src_ip, dst_ip, net_src_port, net_dst_port,
+                             node_index, &is_appface);
+
+  face = hicn_dpoi_get_from_idx (dpo->dpoi_index);
+
+  face->shared.flags = flags;
+  face->shared.adj = ip_adj;
+  face->shared.sw_if = sw_if;
+  *face_id = hicn_dpoi_get_index (face);
+
+  return HICN_ERROR_NONE;
+}
+
+void
+hicn_dpo_udp_create_from_face (hicn_face_t * face, dpo_id_t * dpo,
+                              u16 dpoi_next_node)
+{
+  hicn_face_id_t face_dpoi_id = hicn_dpoi_get_index (face);
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+  u8 version =
+    (face_udp->hdrs.ip4.ip.ip_version_and_header_length & 0xf0) >> 4;
+  dpo_set (dpo, face->shared.face_type,
+          version == 4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6, face_dpoi_id);
+  dpo->dpoi_next_node = dpoi_next_node;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/dpo_udp.h b/hicn-plugin/src/faces/udp/dpo_udp.h
new file mode 100755 (executable)
index 0000000..fdde419
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_DPO_UDP_H__
+#define __HICN_DPO_UDP_H__
+
+#include <vnet/adj/adj_types.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+
+#include "face_udp.h"
+#include "../face.h"
+#include "../../error.h"
+
+
+/**
+ * @brief Initialize the internal structures of the dpo udp face module.
+ */
+void hicn_dpo_udp_module_init (void);
+
+/**
+ * @brief Create a udp face and its corresponding dpo. Meant to be used for the
+ * control plane.
+ *
+ * @param dpo: Data plane object that point to the face created.
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param adj: Ip adjacency corresponding to the remote address in the face
+ * @param node_index: vlib edge index to use in the packet processing
+ * @param flags: Flags of the face
+ * @param face_id: Identifier for the face (dpoi_index)
+ * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
+ */
+int
+hicn_dpo_udp4_create (dpo_id_t * dpo,
+                     const ip4_address_t * local_addr,
+                     const ip4_address_t * remote_addr,
+                     u16 local_port, u16 remote_port,
+                     u32 sw_if,
+                     adj_index_t adj,
+                     u32 node_index,
+                     hicn_face_flags_t flags, hicn_face_id_t * face_id);
+
+/**
+ * @brief Retrieve a face using the face identifier, i.e., the  quadruplet (local_addr, remote_addr,
+ * local_port, remote_port). This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not. (Currently only IP faces can be appface)
+ *
+ * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE.
+ */
+always_inline int
+hicn_dpo_udp4_lock (dpo_id_t * dpo,
+                   const ip4_address_t * local_addr,
+                   const ip4_address_t * remote_addr,
+                   u16 local_port, u16 remote_port, u8 * is_appface)
+{
+  hicn_face_t *face =
+    hicn_face_udp4_get (local_addr, remote_addr, local_port, remote_port);
+
+  if (PREDICT_FALSE (face == NULL))
+    return HICN_ERROR_FACE_NOT_FOUND;
+
+  index_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index);
+  dpo->dpoi_next_node = ~0;
+  dpo_lock (dpo);
+
+  *is_appface = 0;
+
+  return HICN_ERROR_NONE;
+}
+
+/**
+ * @brief Retrieve, or create if it doesn't exist, a face from the face
+ * identifier (local_addr, remote_addr, local_port, remote_port) and returns its
+ * dpo. This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not. (Currently only IP faces can be appface)
+ * @param node_index: vlib edge index to use in the packet processing
+ */
+always_inline void
+hicn_dpo_udp4_add_and_lock (dpo_id_t * dpo,
+                           const ip4_address_t * local_addr,
+                           const ip4_address_t * remote_addr,
+                           u16 local_port, u16 remote_port,
+                           u32 node_index, u8 * is_appface)
+{
+  hicn_face_t *face =
+    hicn_face_udp4_get (local_addr, remote_addr, local_port, remote_port);
+
+  if (face == NULL)
+    {
+      pool_get (hicn_dpoi_face_pool, face);
+
+      hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data;
+
+      clib_memcpy (&(udp_face->hdrs.ip4.ip), &ip4_header_skl,
+                  sizeof (ip4_header_t));
+      clib_memcpy (&(udp_face->hdrs.ip4.ip.src_address), local_addr,
+                  sizeof (ip4_address_t));
+      clib_memcpy (&(udp_face->hdrs.ip4.ip.dst_address), remote_addr,
+                  sizeof (ip4_address_t));
+
+      udp_face->hdrs.ip4.udp.src_port = local_port;
+      udp_face->hdrs.ip4.udp.dst_port = remote_port;
+
+      face->shared.adj = ADJ_INDEX_INVALID;
+      face->shared.pl_id = (u16) 0;
+      face->shared.face_type = hicn_face_udp_type;
+      face->shared.flags = HICN_FACE_FLAGS_IFACE;
+      face->shared.locks = 0;
+
+      hicn_face_udp_key_t key;
+      hicn_face_udp4_get_key (local_addr, remote_addr, local_port,
+                             remote_port, &key);
+      hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+
+      mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0);
+      face = face;
+
+      *is_appface = 0;
+      dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index);
+      dpo->dpoi_next_node = node_index;
+      dpo_lock (dpo);
+
+      return;
+    }
+
+  *is_appface = 0;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index);
+  dpo->dpoi_next_node = node_index;
+  dpo_lock (dpo);
+}
+
+/**
+ * @brief Create a udp face and its corresponding dpo. Meant to be used for the
+ * control plane.
+ *
+ * @param dpo: Data plane object that point to the face created.
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param adj: Ip adjacency corresponding to the remote address in the face
+ * @param node_index: vlib edge index to use in the packet processing
+ * @param flags: Flags of the face
+ * @param face_id: Identifier for the face (dpoi_index)
+ * @return HICN_ERROR_FACE_ALREADY_CREATED if the face exists, otherwise HICN_ERROR_NONE
+ */
+int
+hicn_dpo_udp6_create (dpo_id_t * dpo,
+                     const ip6_address_t * local_addr,
+                     const ip6_address_t * remote_addr,
+                     u16 local_port, u16 remote_port,
+                     u32 sw_if,
+                     adj_index_t adj,
+                     u32 node_index,
+                     hicn_face_flags_t flags, hicn_face_id_t * face_id);
+
+
+/**
+ * @brief Retrieve a face using the face identifier, i.e., the  quadruplet (local_addr, remote_addr,
+ * local_port, remote_port). This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup. If the face doesn't exist dpo = NULL
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not. (Currently only IP faces can be appface)
+ *
+ * @result HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise HICN_ERROR_NONE.
+ */
+always_inline int
+hicn_dpo_udp6_lock (dpo_id_t * dpo,
+                   const ip6_address_t * local_addr,
+                   const ip6_address_t * remote_addr,
+                   u16 local_port, u16 remote_port, u8 * is_appface)
+{
+  hicn_face_t *face =
+    hicn_face_udp6_get (local_addr, remote_addr, local_port, remote_port);
+
+
+  if (PREDICT_FALSE (face == NULL))
+    return HICN_ERROR_FACE_NOT_FOUND;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP4, dpoi_index);
+  dpo->dpoi_next_node = ~0;
+  dpo_lock (dpo);
+  *is_appface = 0;
+
+  return HICN_ERROR_NONE;
+}
+
+/**
+ * @brief Retrieve, or create if it doesn't exist, a face from the face
+ * identifier (local_addr, remote_addr, local_port, remote_port) and returns its
+ * dpo. This method adds a lock on the face state.
+ *
+ * @param dpo: Result of the lookup
+ * @param local_addr: Local address of the UDP tunnel
+ * @param remote_addr: Remote address of the UDP tunnel
+ * @param local_port: Local port of the UDP tunnel
+ * @param remote_port: Remote port of the UDP tunnel
+ * @param is_appface: Boolean that indicates whether the face is an application
+ * face or not. (Currently only IP faces can be appface)
+ * @param node_index: vlib edge index to use in the packet processing
+ */
+always_inline void
+hicn_dpo_udp6_add_and_lock (dpo_id_t * dpo,
+                           const ip6_address_t * local_addr,
+                           const ip6_address_t * remote_addr,
+                           u16 local_port, u16 remote_port,
+                           u32 node_index, u8 * is_appface)
+{
+  hicn_face_t *face =
+    hicn_face_udp6_get (local_addr, remote_addr, local_port, remote_port);
+
+  if (face == NULL)
+    {
+      pool_get (hicn_dpoi_face_pool, face);
+
+      hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data;
+
+      clib_memcpy (&(udp_face->hdrs.ip6.ip), &ip6_header_skl,
+                  sizeof (ip6_header_t));
+      clib_memcpy (&(udp_face->hdrs.ip6.ip.src_address), local_addr,
+                  sizeof (ip6_address_t));
+      clib_memcpy (&(udp_face->hdrs.ip6.ip.dst_address), remote_addr,
+                  sizeof (ip6_address_t));
+
+      udp_face->hdrs.ip6.udp.src_port = local_port;
+      udp_face->hdrs.ip6.udp.dst_port = remote_port;
+
+      face->shared.adj = ADJ_INDEX_INVALID;
+      face->shared.pl_id = (u16) 0;
+      face->shared.face_type = hicn_face_udp_type;
+      face->shared.flags = HICN_FACE_FLAGS_IFACE;
+      face->shared.locks = 0;
+
+      hicn_face_udp_key_t key;
+      hicn_face_udp6_get_key (local_addr, remote_addr, local_port,
+                             remote_port, &key);
+      hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+
+      mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0);
+
+      *is_appface = 0;
+      dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP6, dpoi_index);
+      dpo->dpoi_next_node = node_index;
+      dpo_lock (dpo);
+
+      return;
+    }
+
+  *is_appface = 0;
+
+  hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+  dpo_set (dpo, hicn_face_udp_type, DPO_PROTO_IP6, dpoi_index);
+  dpo->dpoi_next_node = node_index;
+  dpo_lock (dpo);
+}
+
+/**
+ * @brief Create a dpo from a udp face
+ *
+ * @param face Face from which to create the dpo
+ * @return the dpo
+ */
+void hicn_dpo_udp_create_from_face (hicn_face_t * face, dpo_id_t * dpo,
+                                   u16 dpoi_next_node);
+
+#endif // __HICN_DPO_UDP_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/face_udp.c b/hicn-plugin/src/faces/udp/face_udp.c
new file mode 100755 (executable)
index 0000000..9233527
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "face_udp.h"
+#include "face_udp_node.h"
+#include "dpo_udp.h"
+#include "../face.h"
+#include "../../strategy.h"
+#include "../../strategy_dpo_manager.h"
+#include "../../hicn.h"
+
+#include "../../mapme.h"       // HICN_MAPME_EVENT_*
+#include "../../mapme_eventmgr.h"      // hicn_mapme_eventmgr_process_node
+extern vlib_node_registration_t hicn_mapme_eventmgr_process_node;
+
+mhash_t hicn_face_udp_hashtb;
+
+dpo_type_t hicn_face_udp_type;
+
+ip4_header_t ip4_header_skl = {
+  .ip_version_and_header_length = 0x45,
+  .tos = 0x00,
+  .length = (u16) 0,
+  .fragment_id = (u16) 0,
+  .flags_and_fragment_offset = (u16) 0,
+  .ttl = 254,
+  .protocol = IP_PROTOCOL_UDP,
+  .checksum = 0,
+  .src_address = {{0}},
+  .dst_address = {{0}},
+};
+
+ip6_header_t ip6_header_skl = {
+#if CLIB_ARCH_IS_BIG_ENDIAN
+  .ip_version_traffic_class_and_flow_label = 0x60000000,
+#else
+  .ip_version_traffic_class_and_flow_label = 0x00000060,
+#endif
+  .payload_length = (u16) 0,
+  .protocol = IP_PROTOCOL_UDP,
+  .hop_limit = 254,
+  .src_address = {{0}},
+  .dst_address = {{0}}
+};
+
+u32 strategy_face_udp4_vlib_edge;
+u32 strategy_face_udp6_vlib_edge;
+
+/* Separated from the hicn_face_udp_init because it cannot be called by the
+   init macro due to dependencies with other modules not yet initialied */
+void
+hicn_face_udp_init_internal ()
+{
+  ip4_header_t *ip4_hdr = &ip4_header_skl;
+  ip4_header_skl.checksum = ip4_header_checksum (ip4_hdr);
+}
+
+void
+hicn_face_udp_init (vlib_main_t * vm)
+{
+  int strategy_nodes_n = hicn_strategy_get_all_available ();
+
+  /* Default Strategy has index 0 and it always exists */
+  strategy_face_udp4_vlib_edge = vlib_node_add_next (vm,
+                                                    hicn_dpo_get_strategy_vft
+                                                    (default_dpo.
+                                                     hicn_dpo_get_type ())->
+                                                    get_strategy_node_index
+                                                    (),
+                                                    hicn_face_udp4_output_node.
+                                                    index);
+  strategy_face_udp6_vlib_edge =
+    vlib_node_add_next (vm,
+                       hicn_dpo_get_strategy_vft (default_dpo.
+                                                  hicn_dpo_get_type ())->
+                       get_strategy_node_index (),
+                       hicn_face_udp6_output_node.index);
+
+  /*
+   * Create and edge between al the other strategy nodes
+   * and the udp_output nodes.
+   */
+  for (int i = 1; i < strategy_nodes_n; i++)
+    {
+      u32 temp_index4 = vlib_node_add_next (vm,
+                                           hicn_dpo_get_strategy_vft_from_id
+                                           (i)->get_strategy_node_index (),
+                                           hicn_face_udp4_output_node.index);
+      u32 temp_index6 = vlib_node_add_next (vm,
+                                           hicn_dpo_get_strategy_vft_from_id
+                                           (i)->get_strategy_node_index (),
+                                           hicn_face_udp6_output_node.index);
+      ASSERT (temp_index4 == strategy_face_udp4_vlib_edge);
+      ASSERT (temp_index6 == strategy_face_udp6_vlib_edge);
+    }
+
+  hicn_dpo_udp_module_init ();
+
+  register_face_type (hicn_face_udp_type, &udp_vft, "udp");;
+}
+
+int
+hicn_face_udp_add (const ip46_address_t * local_addr,
+                  const ip46_address_t * remote_addr, u16 local_port,
+                  u16 remote_port, u32 swif, hicn_face_id_t * pfaceid)
+{
+  fib_protocol_t fib_type;
+  vnet_link_t link_type;
+  adj_index_t ip_adj;
+  int ret = HICN_ERROR_NONE;
+  dpo_proto_t dpo_proto;
+
+  hicn_face_flags_t flags = (hicn_face_flags_t) 0;
+  flags |= HICN_FACE_FLAGS_FACE;
+
+
+  if (ip46_address_is_ip4 (local_addr) && ip46_address_is_ip4 (remote_addr))
+    {
+      link_type = VNET_LINK_IP4;
+      fib_type = FIB_PROTOCOL_IP4;
+      ip_adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, swif);
+
+      hicn_face_t *face =
+       hicn_face_udp4_get (&local_addr->ip4, &remote_addr->ip4, local_port,
+                           remote_port);
+
+      if (face != NULL)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      pool_get (hicn_dpoi_face_pool, face);
+
+      hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data;
+
+      clib_memcpy (&(udp_face->hdrs.ip4.ip), &ip4_header_skl,
+                  sizeof (ip4_header_t));
+      clib_memcpy (&(udp_face->hdrs.ip4.ip.src_address), &(local_addr->ip4),
+                  sizeof (ip4_address_t));
+      clib_memcpy (&(udp_face->hdrs.ip4.ip.dst_address), &(remote_addr->ip4),
+                  sizeof (ip4_address_t));
+
+      udp_face->hdrs.ip4.udp.src_port = local_port;
+      udp_face->hdrs.ip4.udp.dst_port = remote_port;
+
+      ip_csum_t csum = udp_face->hdrs.ip4.ip.checksum;
+      csum = ip_csum_sub_even (csum, ip4_header_skl.src_address.as_u32);
+      csum = ip_csum_sub_even (csum, ip4_header_skl.dst_address.as_u32);
+      csum =
+       ip_csum_add_even (csum, udp_face->hdrs.ip4.ip.src_address.as_u32);
+      csum =
+       ip_csum_add_even (csum, udp_face->hdrs.ip4.ip.dst_address.as_u32);
+      udp_face->hdrs.ip4.ip.checksum = ip_csum_fold (csum);
+
+      face->shared.adj = ip_adj;
+      face->shared.sw_if = swif;
+      face->shared.pl_id = (u16) 0;
+      face->shared.face_type = hicn_face_udp_type;
+      face->shared.flags = flags;
+      face->shared.locks = 0;
+
+      hicn_face_udp_key_t key;
+      hicn_face_udp4_get_key (&local_addr->ip4, &remote_addr->ip4, local_port,
+                             remote_port, &key);
+      hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+
+      mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0);
+
+      *pfaceid = hicn_dpoi_get_index (face);
+      dpo_proto = DPO_PROTO_IP4;
+    }
+  else if (!ip46_address_is_ip4 (local_addr)
+          && !ip46_address_is_ip4 (remote_addr))
+    {
+      link_type = VNET_LINK_IP6;
+      fib_type = FIB_PROTOCOL_IP6;
+      ip_adj = adj_nbr_add_or_lock (fib_type, link_type, remote_addr, swif);
+
+      hicn_face_t *face =
+       hicn_face_udp6_get (&local_addr->ip6, &remote_addr->ip6, local_port,
+                           remote_port);
+
+      if (face != NULL)
+       return HICN_ERROR_FACE_ALREADY_CREATED;
+
+      pool_get (hicn_dpoi_face_pool, face);
+
+      hicn_face_udp_t *udp_face = (hicn_face_udp_t *) face->data;
+
+      clib_memcpy (&(udp_face->hdrs.ip6.ip), &ip6_header_skl,
+                  sizeof (ip6_header_t));
+      clib_memcpy (&(udp_face->hdrs.ip6.ip.src_address), local_addr,
+                  sizeof (ip6_address_t));
+      clib_memcpy (&(udp_face->hdrs.ip6.ip.dst_address), remote_addr,
+                  sizeof (ip6_address_t));
+
+      udp_face->hdrs.ip6.udp.src_port = local_port;
+      udp_face->hdrs.ip6.udp.dst_port = remote_port;
+
+      face->shared.adj = ip_adj;
+      face->shared.sw_if = swif;
+      face->shared.pl_id = (u16) 0;
+      face->shared.face_type = hicn_face_udp_type;
+      face->shared.flags = flags;
+      face->shared.locks = 0;
+
+      hicn_face_udp_key_t key;
+      hicn_face_udp6_get_key (&local_addr->ip6, &remote_addr->ip6, local_port,
+                             remote_port, &key);
+      hicn_face_id_t dpoi_index = hicn_dpoi_get_index (face);
+
+      mhash_set_mem (&hicn_face_udp_hashtb, &key, (uword *) & dpoi_index, 0);
+
+      *pfaceid = hicn_dpoi_get_index (face);
+      dpo_proto = DPO_PROTO_IP6;
+    }
+  else
+    {
+      return HICN_ERROR_IPS_ADDR_TYPE_NONUNIFORM;
+    }
+
+  retx_t *retx = vlib_process_signal_event_data (vlib_get_main (),
+                                                hicn_mapme_eventmgr_process_node.
+                                                index,
+                                                HICN_MAPME_EVENT_FACE_ADD, 1,
+                                                sizeof (retx_t));
+  *retx = (retx_t)
+  {
+    .prefix = 0,.dpo = (dpo_id_t)
+    {
+    .dpoi_type = hicn_face_udp_type,.dpoi_proto =
+       dpo_proto,.dpoi_next_node = 0,.dpoi_index = *pfaceid,}
+  };
+
+  return ret;
+}
+
+int
+hicn_face_udp_del (u32 faceid)
+{
+  return hicn_face_del (faceid);
+}
+
+u8 *
+format_hicn_face_udp (u8 * s, va_list * args)
+{
+  hicn_face_id_t face_id = va_arg (*args, index_t);
+  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
+  hicn_face_t *face;
+  hicn_face_udp_t *udp_face;
+  ip_adjacency_t *adj;
+  u8 ipv = 0x40;
+  vnet_main_t *vnm = vnet_get_main ();
+
+
+  face = hicn_dpoi_get_from_idx (face_id);
+  udp_face = (hicn_face_udp_t *) (face->data);
+
+  if (face->shared.flags & HICN_FACE_FLAGS_FACE)
+    {
+      ASSERT (face->shared.adj != (adj_index_t) ~ 0);
+      adj = adj_get (face->shared.adj);
+
+      s = format (s, "%U Face %d: ", format_white_space, indent, face_id);
+      if (udp_face->hdrs.ip4.ip.ip_version_and_header_length == ipv)
+       {
+         s = format (s, "type UDP local %U|%u ",
+                     format_ip4_address, &udp_face->hdrs.ip4.ip.src_address,
+                     clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.src_port));
+         s =
+           format (s, "remote %U|%u ", format_ip4_address,
+                   &udp_face->hdrs.ip4.ip.dst_address,
+                   clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.dst_port));
+         s = format (s, "%U", format_vnet_link, adj->ia_link);
+         s = format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+                     vnet_get_sw_interface (vnm, face->shared.sw_if));
+         if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+           s = format (s, " (deleted)");
+       }
+      else
+       {
+         s = format (s, "type UDP local %U|%u ",
+                     format_ip6_address, &udp_face->hdrs.ip6.ip.src_address,
+                     clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.src_port));
+         s =
+           format (s, "remote %U|%u", format_ip6_address,
+                   &udp_face->hdrs.ip6.ip.dst_address,
+                   clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.dst_port));
+         s = format (s, "%U", format_vnet_link, adj->ia_link);
+         s = format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+                     vnet_get_sw_interface (vnm, face->shared.sw_if));
+         if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+           s = format (s, " (deleted)");
+       }
+    }
+  else
+    {
+      s = format (s, "IFace %d: ", format_white_space, indent, face_id);
+      if (udp_face->hdrs.ip4.ip.ip_version_and_header_length == ipv)
+       {
+         s = format (s, "type UDP local %U|%u",
+                     format_ip4_address, &udp_face->hdrs.ip4.ip.src_address,
+                     clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.src_port));
+         s =
+           format (s, " local %U|%u", format_ip4_address,
+                   &udp_face->hdrs.ip4.ip.dst_address,
+                   clib_net_to_host_u16 (udp_face->hdrs.ip4.udp.dst_port));
+         s =
+           format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+                   vnet_get_sw_interface (vnm, face->shared.sw_if));
+         if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+           s = format (s, " (deleted)");
+       }
+      else
+       {
+         s = format (s, "type UDP local %U|%u",
+                     format_ip6_address, &udp_face->hdrs.ip6.ip.src_address,
+                     clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.src_port));
+         s =
+           format (s, " remote %U|%u", format_ip6_address,
+                   &udp_face->hdrs.ip6.ip.dst_address,
+                   clib_net_to_host_u16 (udp_face->hdrs.ip6.udp.dst_port));
+         s =
+           format (s, " dev %U", format_vnet_sw_interface_name, vnm,
+                   vnet_get_sw_interface (vnm, face->shared.sw_if));
+         if ((face->shared.flags & HICN_FACE_FLAGS_DELETED))
+           s = format (s, " (deleted)");
+       }
+    }
+
+  return s;
+}
+
+void
+hicn_face_udp_get_dpo (hicn_face_t * face, dpo_id_t * dpo)
+{
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+  u8 version =
+    (face_udp->hdrs.ip4.ip.ip_version_and_header_length & 0xf0) >> 4;
+  return hicn_dpo_udp_create_from_face (face, dpo,
+                                       version ==
+                                       (u8) 4 ? strategy_face_udp4_vlib_edge
+                                       : strategy_face_udp6_vlib_edge);
+}
+
+hicn_face_vft_t udp_vft = {
+  .format_face = format_hicn_face_udp,
+  .hicn_face_del = hicn_face_udp_del,
+  .hicn_face_get_dpo = hicn_face_udp_get_dpo,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/face_udp.h b/hicn-plugin/src/faces/udp/face_udp.h
new file mode 100755 (executable)
index 0000000..8694bad
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_UDP_H__
+#define __HICN_FACE_UDP_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/udp/udp_packet.h>
+
+#include "../face.h"
+
+/**
+ * @file
+ * @brief UDP face
+ *
+ * This file containes the definition of UDP faces.
+ * UDP faces encap and decap an hicn packet into a UDP tunnel.
+ * Src and dst address in interest and data packets are not considered and
+ * should be set to 0 (not checked in the forwarder).
+ */
+
+/* Pre-instantiated ip header to fast fill an newly encapsulated packet */
+extern ip4_header_t ip4_header_skl;
+extern ip6_header_t ip6_header_skl;
+
+#define INVALID_UDP_DPO_INDEX ~0
+
+/**
+ * @brief UDP face representation. The following is stored in the data field of
+ * an hicn_face_t object (see hicn_face.h). A UDP face is identifies by the
+ * quadruplet (src addr, dst addr, src port, dst port).
+ */
+typedef struct hicn_face_udp_t_
+{
+  /**
+   * The headers to paint, in packet painting order
+   */
+  union
+  {
+    struct
+    {
+      ip4_header_t ip;
+      udp_header_t udp;
+    } __attribute__ ((packed)) ip4;
+    struct
+    {
+      ip6_header_t ip;
+      udp_header_t udp;
+    } __attribute__ ((packed)) ip6;
+  } __attribute__ ((packed)) hdrs;
+} hicn_face_udp_t;
+
+/* Hast table mapping the udp key with the face id (dpoi_index pointing to and
+   element in the face pool defined in hicn_face.h)*/
+extern mhash_t hicn_face_udp_hashtb;
+
+/**
+ * @brief Hash table key.
+ */
+typedef struct hicn_face_udp_key_s
+{
+  ip46_address_t local_addr;
+  ip46_address_t remote_addr;
+  u16 local_port;
+  u16 remote_port;
+} hicn_face_udp_key_t;
+
+/* DPO type for the udp face */
+extern dpo_type_t hicn_face_udp_type;
+
+/* VFT table for the udp face. Mainly used to format the face in the right way */
+extern hicn_face_vft_t udp_vft;
+
+/**
+ * @brief Create the key object for the mhash. Fill in the key object with the
+ * expected values.
+ *
+ * @param local_addr Local address of the UDP tunnel
+ * @param remote_addr Remote address of the UDP tunnel
+ * @param local_port Local port of the UDP tunnel
+ * @param remote_port Remote port of the UDP tunnel
+ * @param key Pointer to an allocated hicn_face_udp_key_t object
+ */
+always_inline void
+hicn_face_udp4_get_key (const ip4_address_t * local_addr,
+                       const ip4_address_t * remote_addr,
+                       u16 local_port, u16 remote_port,
+                       hicn_face_udp_key_t * key)
+{
+
+  ip46_address_set_ip4 (&(key->local_addr), local_addr);
+  ip46_address_set_ip4 (&(key->remote_addr), remote_addr);
+  key->local_port = local_port;
+  key->remote_port = remote_port;
+}
+
+/**
+ * @brief Create the key object for the mhash. Fill in the key object with the
+ * expected values.
+ *
+ * @param local_addr Local address of the UDP tunnel
+ * @param remote_addr Remote address of the UDP tunnel
+ * @param local_port Local port of the UDP tunnel
+ * @param remote_port Remote port of the UDP tunnel
+ * @param key Pointer to an allocated hicn_face_udp_key_t object
+ */
+always_inline void
+hicn_face_udp6_get_key (const ip6_address_t * local_addr,
+                       const ip6_address_t * remote_addr,
+                       u16 local_port, u16 remote_port,
+                       hicn_face_udp_key_t * key)
+{
+  key->local_addr.ip6 = *local_addr;
+  key->remote_addr.ip6 = *remote_addr;
+  key->local_port = local_port;
+  key->remote_port = remote_port;
+}
+
+/**
+ * @brief Get the dpoi from the quadruplet that identifies the face. Does not add any lock.
+ *
+ * @param local_addr Local address of the UDP tunnel
+ * @param remote_addr Remote address of the UDP tunnel
+ * @param local_port Local port of the UDP tunnel
+ * @param remote_port Remote port of the UDP tunnel
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_t *
+hicn_face_udp4_get (const ip4_address_t * local_addr,
+                   const ip4_address_t * remote_addr,
+                   u16 local_port, u16 remote_port)
+{
+  hicn_face_udp_key_t key;
+
+  hicn_face_udp4_get_key (local_addr, remote_addr, local_port, remote_port,
+                         &key);
+
+  hicn_face_id_t *dpoi_index =
+    (hicn_face_id_t *) mhash_get (&hicn_face_udp_hashtb,
+                                 &key);
+
+  return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index);
+}
+
+/**
+ * @brief Get the dpoi from the quadruplet that identifies the face. Does not add any lock.
+ *
+ * @param local_addr Local address of the UDP tunnel (network order)
+ * @param remote_addr Remote address of the UDP tunnel (network order)
+ * @param local_port Local port of the UDP tunnel (network order)
+ * @param remote_port Remote port of the UDP tunnel (network order)
+ *
+ * @result Pointer to the face.
+ */
+always_inline hicn_face_t *
+hicn_face_udp6_get (const ip6_address_t * local_addr,
+                   const ip6_address_t * remote_addr,
+                   u16 local_port, u16 remote_port)
+{
+  hicn_face_udp_key_t key;
+
+  hicn_face_udp6_get_key (local_addr, remote_addr, local_port, remote_port,
+                         &key);
+
+  hicn_face_id_t *dpoi_index =
+    (hicn_face_id_t *) mhash_get (&hicn_face_udp_hashtb,
+                                 &key);
+
+  return dpoi_index == NULL ? NULL : hicn_dpoi_get_from_idx (*dpoi_index);
+}
+
+
+/**
+ * @brief Initialize the udp face module
+ */
+void hicn_face_udp_init (vlib_main_t * vm);
+
+/**
+ * @brief Create a new face ip. API for other modules (e.g., routing)
+ *
+ * @param local_addr Local ip v4 or v6 address of the face (network order)
+ * @param remote_addr Remote ip v4 or v6 address of the face (network order)
+ * @param local_port Local udp port of the face (network order)
+ * @param remote_port Remote udp port of the face (network order)
+ * @param sw_if interface associated to the face
+ * @param pfaceid Pointer to return the face id
+ * @return HICN_ERROR_FACE_NO_GLOBAL_IP if the face does not have a globally
+ * reachable ip address, otherwise HICN_ERROR_NONE
+ */
+int hicn_face_udp_add (const ip46_address_t * local_addr,
+                      const ip46_address_t * remote_addr, u16 local_port,
+                      u16 remote_port, u32 swif, hicn_face_id_t * pfaceid);
+
+/**
+ * @brief Delete an ip face
+ *
+ * @param face_id Id of the face to delete
+ * @return HICN_ERROR_FACE_NOT_FOUND if the face does not exist, otherwise
+ * HICN_ERROR_NONE
+ */
+int hicn_face_udp_del (hicn_face_id_t faceid);
+
+/**
+ * @brief Format a UDP face
+ *
+ * @param s Pointer to a previous string. If null it will be initialize
+ * @param args Array storing input values. Expected u32 indent and u32 face_id
+ * @return String with the formatted face
+ */
+u8 *format_hicn_face_udp (u8 * s, va_list * args);
+
+/**
+ * @brief Create a dpo from a udp face
+ *
+ * @param face Face from which to create the dpo
+ * @return the dpo
+ */
+void hicn_face_udp_get_dpo (hicn_face_t * face, dpo_id_t * dpo);
+
+/**
+ * @brief Init some internal structures
+ */
+void hicn_face_udp_init_internal (void);
+
+#endif // __HICN_FACE_UDP_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/face_udp_cli.c b/hicn-plugin/src/faces/udp/face_udp_cli.c
new file mode 100755 (executable)
index 0000000..7bb172c
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017-2019 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 "face_udp.h"
+#include "dpo_udp.h"
+
+#include <vnet/vnet.h>
+#include <vnet/dpo/dpo.h>
+#include <vlib/vlib.h>
+#include <vnet/ip/format.h>
+
+#define HICN_FACE_NONE 0
+#define HICN_FACE_DELETE 1
+#define HICN_FACE_ADD 2
+
+
+static clib_error_t *
+hicn_face_udp_cli_set_command_fn (vlib_main_t * vm,
+                                 unformat_input_t * main_input,
+                                 vlib_cli_command_t * cmd)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  ip46_address_t src_addr;
+  u32 src_port = 0;
+  ip46_address_t dst_addr;
+  u32 dst_port = 0;
+  hicn_face_id_t face_id = HICN_FACE_NULL;
+  int ret = HICN_ERROR_NONE;
+  int sw_if;
+  int face_op = HICN_FACE_NONE;
+
+  ip46_address_reset (&src_addr);
+  ip46_address_reset (&dst_addr);
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (!unformat_user (main_input, unformat_line_input, line_input))
+    {
+      return (0);
+    }
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "del"))
+       {
+         if (unformat (line_input, "id %d", &face_id))
+           face_op = HICN_FACE_DELETE;
+         else
+           {
+             return clib_error_return (0, "missing face id");
+           }
+       }
+      else if (unformat (line_input, "add"))
+       {
+         face_op = HICN_FACE_ADD;
+         if (unformat
+             (line_input, "src_addr %U port %u dst_addr %U port %u intfc %U",
+              unformat_ip46_address, &src_addr, IP46_TYPE_ANY, &src_port,
+              unformat_ip46_address, &dst_addr, IP46_TYPE_ANY, &dst_port,
+              unformat_vnet_sw_interface, vnm, &sw_if));
+         else
+           {
+             return clib_error_return (0, "%s '%U'",
+                                       get_error_string
+                                       (HICN_ERROR_CLI_INVAL),
+                                       format_unformat_error, line_input);
+           }
+       }
+      else
+       {
+         return clib_error_return (0, "%s '%U'",
+                                   get_error_string (HICN_ERROR_CLI_INVAL),
+                                   format_unformat_error, line_input);
+       }
+    }
+
+  if (face_id != HICN_FACE_NULL)
+    {
+      if (!hicn_dpoi_idx_is_valid (face_id))
+       {
+         return clib_error_return (0, "%s, face_id %d not valid",
+                                   get_error_string (ret), face_id);
+       }
+    }
+
+  int rv;
+  switch (face_op)
+    {
+    case HICN_FACE_ADD:
+
+      /* Check for presence of next hop address */
+      if (((dst_addr.as_u64[0] == (u64) 0) && (dst_addr.as_u64[1] == (u64) 0))
+         || dst_port == 0)
+       {
+         return clib_error_return (0, "dst address and port not specified");
+       }
+
+      if (((src_addr.as_u64[0] == (u64) 0) && (src_addr.as_u64[1] == (u64) 0))
+         || src_port == 0)
+       {
+         return clib_error_return (0, "src address not specified");
+       }
+
+      rv =
+       hicn_face_udp_add (&src_addr, &dst_addr,
+                          clib_host_to_net_u16 (src_port),
+                          clib_host_to_net_u16 (dst_port), sw_if, &face_id);
+      if (rv == HICN_ERROR_NONE)
+       {
+         vlib_cli_output (vm, "Face id: %d", face_id);
+       }
+      else
+       {
+         return clib_error_return (0, get_error_string (rv));
+       }
+      break;
+    case HICN_FACE_DELETE:
+      rv = hicn_face_udp_del (face_id);
+      if (rv == HICN_ERROR_NONE)
+       {
+         vlib_cli_output (vm, "Face %d deleted", face_id);
+       }
+      else
+       {
+         return clib_error_return (0, get_error_string (rv));
+       }
+      break;
+    default:
+      return clib_error_return (0, "Operation (%d) not implemented", face_op);
+      break;
+    }
+  return (rv == HICN_ERROR_NONE) ? 0 : clib_error_return (0, "%s\n",
+                                                         get_error_string
+                                                         (rv));
+}
+
+/* cli declaration for 'cfg face' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_face_udp_cli_set_command, static) =
+{
+  .path = "hicn face udp",
+  .short_help = "hicn face udp {add src_addr <src_address> port <src_port > dst_addr <dst_address> port <dst_port>} intfc <interface> | {del id <face_id>}",
+  .function = hicn_face_udp_cli_set_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/face_udp_node.c b/hicn-plugin/src/faces/udp/face_udp_node.c
new file mode 100755 (executable)
index 0000000..74d0b18
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/ip/ip_packet.h>
+
+#include "face_udp.h"
+#include "face_udp_node.h"
+#include "dpo_udp.h"
+#include "../face.h"
+#include "../../strategy.h"
+#include "../../strategy_dpo_manager.h"
+#include "../../hicn.h"
+
+/**
+ * @File
+ *
+ * Definition of the nodes for udp faces.
+ */
+
+vlib_node_registration_t hicn_face_udp4_input_node;
+vlib_node_registration_t hicn_face_udp6_input_node;
+vlib_node_registration_t hicn_face_udp4_output_node;
+vlib_node_registration_t hicn_face_udp6_output_node;
+
+static char *hicn_face_udp4_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_face_udp6_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_udp4_input_trace_t;
+
+typedef enum
+{
+  HICN_FACE_UDP4_INPUT_NEXT_DATA,
+  HICN_FACE_UDP4_INPUT_NEXT_MAPME,
+  HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP,
+  HICN_FACE_UDP4_INPUT_N_NEXT,
+} hicn_face_udp4_input_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_udp6_input_trace_t;
+
+typedef enum
+{
+  HICN_FACE_UDP6_INPUT_NEXT_DATA,
+  HICN_FACE_UDP6_INPUT_NEXT_MAPME,
+  HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP,
+  HICN_FACE_UDP6_INPUT_N_NEXT,
+} hicn_face_udp6_input_next_t;
+
+#define ERROR_INPUT_UDP4 HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP
+#define ERROR_INPUT_UDP6 HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP
+
+#define NEXT_MAPME_UDP4 HICN_FACE_UDP4_INPUT_NEXT_MAPME
+#define NEXT_MAPME_UDP6 HICN_FACE_UDP6_INPUT_NEXT_MAPME
+#define NEXT_DATA_UDP4 HICN_FACE_UDP4_INPUT_NEXT_DATA
+#define NEXT_DATA_UDP6 HICN_FACE_UDP6_INPUT_NEXT_DATA
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define HICN_DPO_UDP_LOCK_IP4 hicn_dpo_udp4_lock
+#define HICN_DPO_UDP_LOCK_IP6 hicn_dpo_udp6_lock
+
+#define TRACE_INPUT_PKT_UDP4 hicn_face_udp4_input_trace_t
+#define TRACE_INPUT_PKT_UDP6 hicn_face_udp6_input_trace_t
+
+#define face_input_x1(ipv)                                          \
+  do {                                                              \
+    int ret;                                                        \
+    vlib_buffer_t *b0;                                              \
+    u32 bi0;                                                        \
+    u32 next0 = ERROR_INPUT_UDP##ipv;                               \
+    IP_HEADER_##ipv * ip_hdr = NULL;                                \
+    u8 * inner_ip_hdr = NULL;                                      \
+    udp_header_t * udp_hdr = NULL;                                  \
+    hicn_buffer_t * hicnb0;                                         \
+    /* Prefetch for next iteration. */                              \
+    if (n_left_from > 1)                                            \
+      {                                                             \
+        vlib_buffer_t *b1;                                          \
+        b1 = vlib_get_buffer (vm, from[1]);                         \
+        CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);           \
+        CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);     \
+      }                                                             \
+    /* Dequeue a packet buffer */                                   \
+    bi0 = from[0];                                                  \
+    from += 1;                                                      \
+    n_left_from -= 1;                                               \
+    to_next[0] = bi0;                                               \
+    to_next += 1;                                                   \
+    n_left_to_next -= 1;                                            \
+                                                                    \
+    b0 = vlib_get_buffer (vm, bi0);                                 \
+    ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);       \
+    udp_hdr = (udp_header_t *) (ip_hdr + 1);                        \
+    hicnb0 = hicn_get_buffer(b0);                                   \
+                                                                   \
+    inner_ip_hdr = (u8 *)(udp_hdr + 1);                                    \
+    u8 is_v6 = ((inner_ip_hdr[0] & 2) >> 1);                        \
+    u8 is_icmp = is_v6*(inner_ip_hdr[7] == IPPROTO_ICMPV6) +       \
+      (1 - is_v6)*(inner_ip_hdr[10] == IPPROTO_ICMPV4);                    \
+                                                                    \
+    ret = HICN_DPO_UDP_LOCK_IP##ipv                                 \
+      (&(hicnb0->face_dpo_id),                                      \
+       &(ip_hdr->dst_address),                                      \
+       &(ip_hdr->src_address),                                      \
+       (udp_hdr->dst_port),                                         \
+       (udp_hdr->src_port),                                         \
+       &hicnb0->is_appface);                                        \
+                                                                    \
+    if ( PREDICT_FALSE(ret != HICN_ERROR_NONE) )                    \
+      {                                                             \
+        next0 = ERROR_INPUT_UDP##ipv;                               \
+      }                                                             \
+    else                                                            \
+      {                                                             \
+       next0 = is_icmp*NEXT_MAPME_UDP##ipv +                       \
+         (1-is_icmp)*NEXT_DATA_UDP##ipv;                           \
+       stats.pkts_data_count += 1;                                 \
+                                                                   \
+        vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) +           \
+                            sizeof(udp_header_t));                  \
+      }                                                             \
+                                                                   \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&     \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))        \
+      {                                                             \
+        TRACE_INPUT_PKT_UDP##ipv *t =                               \
+          vlib_add_trace (vm, node, b0, sizeof (*t));               \
+        t->pkt_type = HICN_PKT_TYPE_CONTENT;                        \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];    \
+        t->next_index = next0;                                      \
+      }                                                             \
+                                                                   \
+                                                                    \
+    /* 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);                       \
+  }while(0)                                                             \
+
+#define face_input_x2(ipv)                                          \
+  do {                                                              \
+    int ret0, ret1;                                                 \
+    vlib_buffer_t *b0, *b1;                                         \
+    u32 bi0, bi1;                                                   \
+    u32 next0 = ERROR_INPUT_UDP##ipv;                               \
+    u32 next1 = ERROR_INPUT_UDP##ipv;                               \
+    IP_HEADER_##ipv * ip_hdr0 = NULL;                               \
+    IP_HEADER_##ipv * ip_hdr1 = NULL;                               \
+    u8 * inner_ip_hdr0 = NULL;                                     \
+    u8 * inner_ip_hdr1 = NULL;                                     \
+    udp_header_t * udp_hdr0 = NULL;                                 \
+    udp_header_t * udp_hdr1 = NULL;                                 \
+    hicn_buffer_t *hicnb0, *hicnb1;                                 \
+                                                                    \
+    /* Prefetch for next iteration. */                              \
+    {                                                               \
+      vlib_buffer_t *b2, *b3;                                       \
+      b2 = vlib_get_buffer (vm, from[2]);                           \
+      b3 = vlib_get_buffer (vm, from[3]);                           \
+      CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+    }                                                               \
+                                                                    \
+    /* Dequeue a packet buffer */                                   \
+    bi0 = from[0];                                                  \
+    bi1 = from[1];                                                  \
+    from += 2;                                                      \
+    n_left_from -= 2;                                               \
+    to_next[0] = bi0;                                               \
+    to_next[1] = bi1;                                               \
+    to_next += 2;                                                   \
+    n_left_to_next -= 2;                                            \
+                                                                    \
+    b0 = vlib_get_buffer (vm, bi0);                                 \
+    b1 = vlib_get_buffer (vm, bi1);                                 \
+    ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);      \
+    ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1);      \
+    udp_hdr0 = (udp_header_t *) (ip_hdr0 + 1);                      \
+    udp_hdr1 = (udp_header_t *) (ip_hdr1 + 1);                      \
+    hicnb0 = hicn_get_buffer(b0);                                   \
+    hicnb1 = hicn_get_buffer(b1);                                   \
+                                                                    \
+    inner_ip_hdr0 = (u8 *)(udp_hdr0 + 1);                          \
+    u8 is_v6_0 = ((inner_ip_hdr0[0] & 2) >> 1);                     \
+     u8 is_icmp0 = is_v6_0*(inner_ip_hdr0[7] == IPPROTO_ICMPV6) +   \
+      (1 - is_v6_0)*(inner_ip_hdr0[10] == IPPROTO_ICMPV4);         \
+                                                                   \
+    inner_ip_hdr1 = (u8 *)(udp_hdr1 + 1);                          \
+    u8 is_v6_1 = ((inner_ip_hdr1[0] & 2) >> 1);                     \
+    u8 is_icmp1 = is_v6_1*(inner_ip_hdr1[7] == IPPROTO_ICMPV6) +    \
+      (1 - is_v6_1)*(inner_ip_hdr1[10] == IPPROTO_ICMPV4);         \
+                                                                   \
+    ret0 = HICN_DPO_UDP_LOCK_IP##ipv                                \
+      (&(hicnb0->face_dpo_id),                                      \
+       &(ip_hdr0->dst_address),                                     \
+       &(ip_hdr0->src_address),                                     \
+       (udp_hdr0->dst_port),                                        \
+       (udp_hdr0->src_port),                                        \
+       &hicnb0->is_appface);                                        \
+                                                                    \
+    ret1 = HICN_DPO_UDP_LOCK_IP##ipv                                \
+      (&(hicnb1->face_dpo_id),                                      \
+       &(ip_hdr1->dst_address),                                     \
+       &(ip_hdr1->src_address),                                     \
+       (udp_hdr1->dst_port),                                        \
+       (udp_hdr1->src_port),                                        \
+       &hicnb1->is_appface);                                        \
+                                                                   \
+    if ( PREDICT_FALSE(ret0 != HICN_ERROR_NONE) )                   \
+      {                                                             \
+        next0 = ERROR_INPUT_UDP##ipv;                               \
+      }                                                             \
+    else                                                            \
+      {                                                             \
+       stats.pkts_data_count += 1;                                 \
+       next0 = is_icmp0*NEXT_MAPME_UDP##ipv +                      \
+         (1-is_icmp0)*NEXT_DATA_UDP##ipv;                          \
+                                                                   \
+        vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) +           \
+                            sizeof(udp_header_t));                  \
+      }                                                             \
+                                                                    \
+    if ( PREDICT_FALSE(ret1 != HICN_ERROR_NONE) )                   \
+      {                                                             \
+        next1 = ERROR_INPUT_UDP##ipv;                               \
+      }                                                             \
+    else                                                            \
+      {                                                             \
+       stats.pkts_data_count += 1;                                 \
+       next1 = is_icmp1*NEXT_MAPME_UDP##ipv +                      \
+         (1-is_icmp1)*NEXT_DATA_UDP##ipv;                          \
+                                                                   \
+        vlib_buffer_advance(b1, sizeof(IP_HEADER_##ipv) +           \
+                            sizeof(udp_header_t));                  \
+      }                                                             \
+                                                                    \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&      \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))        \
+      {                                                             \
+        TRACE_INPUT_PKT_UDP##ipv *t =                               \
+          vlib_add_trace (vm, node, b0, sizeof (*t));               \
+        t->pkt_type = HICN_PKT_TYPE_CONTENT;                        \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];    \
+        t->next_index = next0;                                      \
+      }                                                             \
+                                                                    \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&      \
+                       (b1->flags & VLIB_BUFFER_IS_TRACED)))        \
+      {                                                             \
+        TRACE_INPUT_PKT_UDP##ipv *t =                               \
+          vlib_add_trace (vm, node, b1, sizeof (*t));               \
+        t->pkt_type = HICN_PKT_TYPE_CONTENT;                        \
+        t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];    \
+        t->next_index = next1;                                      \
+      }                                                             \
+                                                                    \
+                                                                    \
+    /* Verify speculative enqueue, 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(0)                                                             \
+
+static uword
+hicn_face_udp4_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_input_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_input_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_udp4_input_format_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 *);
+  hicn_face_udp4_input_trace_t *t =
+    va_arg (*args, hicn_face_udp4_input_trace_t *);
+
+  s = format (s, "FACE_UDP4_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_face_udp4_input_node) =
+{
+  .function = hicn_face_udp4_input_node_fn,
+  .name = "hicn-face-udp4-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_face_udp4_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_face_udp4_input_error_strings),
+  .error_strings = hicn_face_udp4_input_error_strings,
+  .n_next_nodes = HICN_FACE_UDP4_INPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_FACE_UDP4_INPUT_NEXT_DATA] = "hicn-data-pcslookup",
+    [HICN_FACE_UDP4_INPUT_NEXT_MAPME] = "hicn-mapme-ack",
+    [HICN_FACE_UDP4_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+static uword
+hicn_face_udp6_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+
+  while (n_left_from > 0)
+    {
+      u32 n_left_to_next;
+      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_input_x2 (6);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_input_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_udp6_input_format_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 *);
+  hicn_face_udp6_input_trace_t *t =
+    va_arg (*args, hicn_face_udp6_input_trace_t *);
+
+  s = format (s, "FACE_UDP6_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_face_udp6_input_node) =
+{
+  .function = hicn_face_udp6_input_node_fn,
+  .name = "hicn-face-udp6-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_face_udp6_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_face_udp6_input_error_strings),
+  .error_strings = hicn_face_udp6_input_error_strings,
+  .n_next_nodes = HICN_FACE_UDP6_INPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_FACE_UDP6_INPUT_NEXT_DATA] = "hicn-data-pcslookup",
+    [HICN_FACE_UDP6_INPUT_NEXT_MAPME] = "hicn-mapme-ack",
+    [HICN_FACE_UDP6_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/******* Face Output *******/
+
+always_inline void
+hicn_face_udp4_encap (vlib_main_t * vm,
+                     vlib_buffer_t * outer_b0,
+                     hicn_face_t * face, u32 * next)
+{
+  u16 old_l0 = 0, new_l0;
+  ip_csum_t sum0;
+  ip4_header_t *ip0;
+  udp_header_t *udp0;
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+  ip_adjacency_t *adj = adj_get (face->shared.adj);
+
+  /* ip */
+  ip0 = vlib_buffer_get_current (outer_b0);
+  clib_memcpy (ip0, &(face_udp->hdrs.ip4.ip), sizeof (ip4_header_t) +
+              sizeof (udp_header_t));
+
+  /* Fix UDP length */
+  udp0 = (udp_header_t *) (ip0 + 1);
+
+  new_l0 =
+    clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0) -
+                         sizeof (*ip0));
+  udp0->length = new_l0;
+
+  old_l0 = ip0->length;
+  ip0->length =
+    clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0));
+
+  sum0 = ip0->checksum;
+
+  //old_l0 always 0, see the rewrite setup
+  new_l0 = ip0->length;
+
+  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
+                        length /* changed member */ );
+  ip0->checksum = sum0;
+
+  vnet_buffer (outer_b0)->ip.adj_index[VLIB_TX] = face->shared.adj;
+
+  *next = adj->lookup_next_index;
+}
+
+always_inline void
+hicn_face_udp6_encap (vlib_main_t * vm,
+                     vlib_buffer_t * outer_b0,
+                     hicn_face_t * face, u32 * next)
+{
+  int bogus0;
+  u16 new_l0;
+  ip6_header_t *ip0;
+  udp_header_t *udp0;
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+  ip_adjacency_t *adj = adj_get (face->shared.adj);
+
+  /* ip */
+  ip0 = vlib_buffer_get_current (outer_b0);
+  clib_memcpy (ip0, &(face_udp->hdrs.ip6.ip), sizeof (ip6_header_t) +
+              sizeof (udp_header_t));
+  new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, outer_b0)
+                                - sizeof (*ip0));
+  ip0->payload_length = new_l0;
+
+  /* Fix UDP length */
+  udp0 = (udp_header_t *) (ip0 + 1);
+  udp0->length = new_l0;
+
+  udp0->checksum =
+    ip6_tcp_udp_icmp_compute_checksum (vm, outer_b0, ip0, &bogus0);
+
+  ASSERT (bogus0 == 0);
+
+  if (udp0->checksum == 0)
+    udp0->checksum = 0xffff;
+
+  vnet_buffer (outer_b0)->ip.adj_index[VLIB_TX] = face->shared.adj;
+
+  *next = adj->lookup_next_index;
+}
+
+static char *hicn_face_udp4_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_face_udp6_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_udp4_output_trace_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_face_udp6_output_trace_t;
+
+#define HICN_FACE_UDP_ENCAP_IP4 hicn_face_udp4_encap
+#define HICN_FACE_UDP_ENCAP_IP6 hicn_face_udp6_encap
+
+#define TRACE_OUTPUT_PKT_UDP4 hicn_face_udp4_output_trace_t
+#define TRACE_OUTPUT_PKT_UDP6 hicn_face_udp6_output_trace_t
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define face_output_x1(ipv)                                         \
+  do {                                                              \
+  vlib_buffer_t *b0;                                                \
+  u32 bi0;                                                          \
+  u32 next0 = IP_LOOKUP_NEXT_DROP;                                 \
+  hicn_face_t * face;                                               \
+                                                                    \
+  /* Prefetch for next iteration. */                                \
+  if (n_left_from > 1)                                              \
+    {                                                               \
+      vlib_buffer_t *b1;                                            \
+      b1 = vlib_get_buffer (vm, from[1]);                           \
+      CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+    }                                                               \
+  /* Dequeue a packet buffer */                                     \
+  bi0 = from[0];                                                    \
+  from += 1;                                                        \
+  n_left_from -= 1;                                                 \
+                                                                    \
+  b0 = vlib_get_buffer (vm, bi0);                                       \
+  face =                                                                \
+    hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]);    \
+                                                                        \
+  if (PREDICT_TRUE(face != NULL))                                       \
+    {                                                                   \
+      /* Adjust vlib buffer. Create space for the udp tunnel. */        \
+      vlib_buffer_advance(b0, -(sizeof (IP_HEADER_##ipv) +             \
+                              sizeof (udp_header_t)));                 \
+                                                                        \
+                                                                        \
+      HICN_FACE_UDP_ENCAP_IP##ipv                                       \
+        (vm, b0, face, &next0);                                                \
+      stats.pkts_interest_count += 1;                                  \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_OUTPUT_PKT_UDP##ipv *t =                                    \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+  to_next[0] = bi0;                                                     \
+  to_next += 1;                                                         \
+  n_left_to_next -= 1;                                                  \
+                                                                        \
+                                                                        \
+  /* 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);                         \
+  } while(0)                                                            \
+
+
+#define face_output_x2(ipv)                                         \
+  do {                                                              \
+    vlib_buffer_t *b0, *b1;                                         \
+    u32 bi0, bi1;                                                   \
+    u32 next0 = IP_LOOKUP_NEXT_DROP;                               \
+    u32 next1 = IP_LOOKUP_NEXT_DROP;                               \
+    hicn_face_t *face0, *face1;                                     \
+                                                                    \
+    /* Prefetch for next iteration. */                              \
+    {                                                               \
+      vlib_buffer_t *b2, *b3;                                       \
+      b2 = vlib_get_buffer (vm, from[2]);                           \
+      b3 = vlib_get_buffer (vm, from[3]);                           \
+      CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+    }                                                               \
+                                                                    \
+    /* Dequeue a packet buffer */                                   \
+    bi0 = from[0];                                                  \
+    bi1 = from[1];                                                  \
+    from += 2;                                                      \
+    n_left_from -= 2;                                               \
+    to_next[0] = bi0;                                               \
+    to_next[1] = bi1;                                               \
+    to_next += 2;                                                   \
+    n_left_to_next -= 2;                                            \
+                                                                    \
+    b0 = vlib_get_buffer (vm, bi0);                                     \
+    b1 = vlib_get_buffer (vm, bi1);                                     \
+                                                                        \
+    face0 =                                                             \
+      hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]);  \
+    face1 =                                                             \
+      hicn_dpoi_get_from_idx(vnet_buffer (b1)->ip.adj_index[VLIB_TX]);  \
+                                                                        \
+    if (PREDICT_TRUE(face0 != NULL))                                    \
+      {                                                                 \
+        /* Adjust vlib buffer. Create space for the udp tunnel. */      \
+        vlib_buffer_advance(b0, -(sizeof (IP_HEADER_##ipv) +           \
+                                 sizeof (udp_header_t)));              \
+                                                                        \
+                                                                        \
+        HICN_FACE_UDP_ENCAP_IP##ipv                                     \
+          (vm, b0, face0, &next0);                                     \
+       stats.pkts_interest_count += 1;                                 \
+      }                                                                 \
+                                                                        \
+    if (PREDICT_TRUE(face1 != NULL))                                    \
+      {                                                                 \
+        /* Adjust vlib buffer. Create space for the udp tunnel. */      \
+        vlib_buffer_advance(b1, -(sizeof (IP_HEADER_##ipv) +           \
+                                 sizeof (udp_header_t)));              \
+                                                                        \
+                                                                        \
+        HICN_FACE_UDP_ENCAP_IP##ipv                                     \
+          (vm, b1, face1, &next1);                                     \
+       stats.pkts_interest_count += 1;                                 \
+      }                                                                 \
+                                                                        \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&          \
+                       (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                 \
+        TRACE_OUTPUT_PKT_UDP##ipv *t =                                  \
+          vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+        t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+        t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+        t->next_index = next0;                                          \
+      }                                                                 \
+                                                                        \
+    /* Verify speculative enqueue, 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(0)                                                            \
+
+
+static uword
+hicn_face_udp4_output_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_output_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_output_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_udp4_output_format_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 *);
+  hicn_face_udp4_output_trace_t *t =
+    va_arg (*args, hicn_face_udp4_output_trace_t *);
+
+  s = format (s, "FACE_UDP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/* *INDENT-OFF* */
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_face_udp4_output_node) =
+{
+  .function = hicn_face_udp4_output_node_fn,
+  .name = "hicn-face-udp4-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_face_udp4_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_face_udp4_output_error_strings),
+  .error_strings = hicn_face_udp4_output_error_strings,
+  .n_next_nodes = IP4_LOOKUP_N_NEXT,
+  /* Reusing the list of nodes from lookup to be compatible with arp */
+  .next_nodes = IP4_LOOKUP_NEXT_NODES,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+
+static uword
+hicn_face_udp6_output_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         face_output_x2 (6);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         face_output_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_face_udp6_output_format_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 *);
+  hicn_face_udp6_output_trace_t *t =
+    va_arg (*args, hicn_face_udp6_output_trace_t *);
+
+  s = format (s, "FACE_UDP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/* *INDENT-OFF* */
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_face_udp6_output_node) =
+{
+  .function = hicn_face_udp6_output_node_fn,
+  .name = "hicn-face-udp6-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_face_udp6_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_face_udp6_output_error_strings),
+  .error_strings = hicn_face_udp6_output_error_strings,
+  .n_next_nodes = IP6_LOOKUP_N_NEXT,
+  /* Reusing the list of nodes from lookup to be compatible with neighbour discovery */
+  .next_nodes = IP6_LOOKUP_NEXT_NODES,
+};
+/* *INDENT-ON* */
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/face_udp_node.h b/hicn-plugin/src/faces/udp/face_udp_node.h
new file mode 100755 (executable)
index 0000000..c759312
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_UDP_NODE_H__
+#define __HICN_FACE_UDP_NODE_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+extern vlib_node_registration_t hicn_face_udp4_input_node;
+extern vlib_node_registration_t hicn_face_udp6_input_node;
+extern vlib_node_registration_t hicn_face_udp4_output_node;
+extern vlib_node_registration_t hicn_face_udp6_output_node;
+
+#endif // __HICN_FACE_UDP_NODE_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/iface_udp_node.c b/hicn-plugin/src/faces/udp/iface_udp_node.c
new file mode 100755 (executable)
index 0000000..ddea31b
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2017-2019 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 "iface_udp_node.h"
+#include "dpo_udp.h"
+#include "../face.h"
+
+#include "../../infra.h"
+#include "../../hicn.h"
+
+/**
+ * @File
+ *
+ * Definition of the nodes for udp incomplete faces.
+ */
+
+vlib_node_registration_t hicn_iface_udp4_input_node;
+vlib_node_registration_t hicn_iface_udp6_input_node;
+vlib_node_registration_t hicn_iface_udp4_output_node;
+vlib_node_registration_t hicn_iface_udp6_output_node;
+
+u32 data_fwd_face_udp4_vlib_edge;
+u32 data_fwd_face_udp6_vlib_edge;
+
+void
+hicn_iface_udp_init (vlib_main_t * vm)
+{
+  data_fwd_face_udp4_vlib_edge = vlib_node_add_next (vm,
+                                                    hicn_data_fwd_node.index,
+                                                    hicn_iface_udp4_output_node.
+                                                    index);
+
+  data_fwd_face_udp6_vlib_edge = vlib_node_add_next (vm,
+                                                    hicn_data_fwd_node.index,
+                                                    hicn_iface_udp6_output_node.
+                                                    index);
+
+  u32 temp_index4 = vlib_node_add_next (vm,
+                                       hicn_interest_hitcs_node.index,
+                                       hicn_iface_udp4_output_node.index);
+  u32 temp_index6 = vlib_node_add_next (vm,
+                                       hicn_interest_hitcs_node.index,
+                                       hicn_iface_udp6_output_node.index);
+
+  ASSERT (temp_index4 == data_fwd_face_udp4_vlib_edge);
+  ASSERT (temp_index6 == data_fwd_face_udp6_vlib_edge);
+}
+
+static char *hicn_iface_udp4_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_iface_udp6_input_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+u32
+get_face_udp4_output_node (void)
+{
+  return data_fwd_face_udp4_vlib_edge;
+}
+
+u32
+get_face_udp6_output_node (void)
+{
+  return data_fwd_face_udp6_vlib_edge;
+}
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_udp4_input_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_UDP4_INPUT_NEXT_INTEREST,
+  HICN_IFACE_UDP4_INPUT_NEXT_MAPME,
+  HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_UDP4_INPUT_N_NEXT,
+} hicn_iface_udp4_input_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_udp6_input_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_UDP6_INPUT_NEXT_INTEREST,
+  HICN_IFACE_UDP6_INPUT_NEXT_MAPME,
+  HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_UDP6_INPUT_N_NEXT,
+} hicn_iface_udp6_input_next_t;
+
+#define ERROR_INPUT_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP
+#define ERROR_INPUT_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define NEXT_MAPME_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_MAPME
+#define NEXT_MAPME_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_MAPME
+
+#define NEXT_INTEREST_UDP4 HICN_IFACE_UDP4_INPUT_NEXT_INTEREST
+#define NEXT_INTEREST_UDP6 HICN_IFACE_UDP6_INPUT_NEXT_INTEREST
+
+#define HICN_IFACE_UDP_ADD_LOCK_IP4 hicn_dpo_udp4_add_and_lock
+#define HICN_IFACE_UDP_ADD_LOCK_IP6 hicn_dpo_udp6_add_and_lock
+
+#define GET_FACE_UDP4  get_face_udp4_output_node
+#define GET_FACE_UDP6  get_face_udp6_output_node
+
+#define TRACE_INPUT_PKT_UDP4 hicn_iface_udp4_input_trace_t
+#define TRACE_INPUT_PKT_UDP6 hicn_iface_udp6_input_trace_t
+
+#define iface_input_x1(ipv)                                         \
+  do {                                                                 \
+    vlib_buffer_t *b0;                                                 \
+    u32 bi0;                                                           \
+    u32 next0 = ERROR_INPUT_UDP##ipv;                                  \
+    IP_HEADER_##ipv * ip_hdr = NULL;                                   \
+    u8 * inner_ip_hdr = NULL;                                          \
+    udp_header_t * udp_hdr = NULL;                                     \
+    hicn_buffer_t * hicnb0;                                            \
+    /* Prefetch for next iteration. */                                 \
+    if (n_left_from > 1)                                               \
+      {                                                                        \
+       vlib_buffer_t *b1;                                              \
+       b1 = vlib_get_buffer (vm, from[1]);                             \
+       CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);               \
+       CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);         \
+      }                                                                        \
+    /* Dequeue a packet buffer */                                      \
+    bi0 = from[0];                                                     \
+    from += 1;                                                         \
+    n_left_from -= 1;                                                  \
+    to_next[0] = bi0;                                                  \
+    to_next += 1;                                                      \
+    n_left_to_next -= 1;                                               \
+                                                                       \
+    b0 = vlib_get_buffer (vm, bi0);                                    \
+    ip_hdr = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);          \
+    udp_hdr = (udp_header_t *) (ip_hdr + 1);                           \
+    hicnb0 = hicn_get_buffer(b0);                                      \
+                                                                       \
+    stats.pkts_interest_count += 1;                                    \
+                                                                       \
+    inner_ip_hdr = (u8 *)(udp_hdr + 1);                                        \
+    u8 is_v6 = ((inner_ip_hdr[0] & 2) >> 1);                           \
+    u8 is_icmp = is_v6*(inner_ip_hdr[7] == IPPROTO_ICMPV6) +           \
+      (1 - is_v6)*(inner_ip_hdr[10] == IPPROTO_ICMPV4);                        \
+                                                                       \
+    next0 = is_icmp*NEXT_MAPME_UDP##ipv +                              \
+      (1-is_icmp)*NEXT_INTEREST_UDP##ipv;                              \
+                                                                       \
+    HICN_IFACE_UDP_ADD_LOCK_IP##ipv                                    \
+      (&(hicnb0->face_dpo_id),                                         \
+       &(ip_hdr->dst_address),                                         \
+       &(ip_hdr->src_address),                                         \
+       udp_hdr->dst_port,                                              \
+       udp_hdr->src_port,                                              \
+       GET_FACE_UDP##ipv                                               \
+       (),                                                             \
+       &hicnb0->is_appface);                                           \
+                                                                       \
+    vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) +                  \
+                       sizeof(udp_header_t));                          \
+                                                                       \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&         \
+                      (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                        \
+       TRACE_INPUT_PKT_UDP##ipv *t =                                   \
+         vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+       t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+       t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+       t->next_index = next0;                                          \
+      }                                                                        \
+                                                                       \
+                                                                       \
+    /* 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);                       \
+  }while(0)
+
+
+#define iface_input_x2(ipv)                                         \
+  do {                                                              \
+    vlib_buffer_t *b0, *b1;                                        \
+    u32 bi0, bi1;                                                  \
+    u32 next0, next1 = ERROR_INPUT_UDP##ipv;                       \
+    IP_HEADER_##ipv * ip_hdr0 = NULL, *ip_hdr1 = NULL;             \
+    u8 * inner_ip_hdr0 = NULL, *inner_ip_hdr1 = NULL;              \
+    udp_header_t * udp_hdr0 = NULL, *udp_hdr1 = NULL;              \
+    hicn_buffer_t * hicnb0, *hicnb1;                               \
+                                                                   \
+    /* Prefetch for next iteration. */                             \
+      {                                                                    \
+       vlib_buffer_t *b2, *b3;                                     \
+       b2 = vlib_get_buffer (vm, from[2]);                         \
+       b3 = vlib_get_buffer (vm, from[3]);                         \
+       CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);           \
+       CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);           \
+       CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);     \
+       CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);     \
+      }                                                                    \
+                                                                   \
+  /* Dequeue a packet buffer */                                     \
+  bi0 = from[0];                                                    \
+  bi1 = from[1];                                                    \
+  from += 2;                                                        \
+  n_left_from -= 2;                                                 \
+  to_next[0] = bi0;                                                 \
+  to_next[1] = bi1;                                                 \
+  to_next += 2;                                                     \
+  n_left_to_next -= 2;                                              \
+                                                                    \
+  b0 = vlib_get_buffer (vm, bi0);                                   \
+  b1 = vlib_get_buffer (vm, bi1);                                   \
+  ip_hdr0 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b0);       \
+  ip_hdr1 = (IP_HEADER_##ipv *) vlib_buffer_get_current(b1);       \
+  udp_hdr0 = (udp_header_t *) (ip_hdr0 + 1);                       \
+  udp_hdr1 = (udp_header_t *) (ip_hdr1 + 1);                       \
+  hicnb0 = hicn_get_buffer(b0);                                     \
+  hicnb1 = hicn_get_buffer(b1);                                     \
+                                                                   \
+  stats.pkts_interest_count += 2;                                      \
+                                                                       \
+  inner_ip_hdr0 = (u8 *)(udp_hdr0 + 1);                                        \
+  inner_ip_hdr1 = (u8 *)(udp_hdr1 + 1);                                        \
+  u8 is_v6_0 = ((inner_ip_hdr0[0] & 2) >> 1);                          \
+  u8 is_v6_1 = ((inner_ip_hdr1[0] & 2) >> 1);                          \
+  u8 is_icmp0 = is_v6_0*(inner_ip_hdr0[7] == IPPROTO_ICMPV6) +         \
+    (1 - is_v6_0)*(inner_ip_hdr0[10] == IPPROTO_ICMPV4);               \
+  u8 is_icmp1 = is_v6_1*(inner_ip_hdr1[7] == IPPROTO_ICMPV6) +         \
+    (1 - is_v6_1)*(inner_ip_hdr1[10] == IPPROTO_ICMPV4);               \
+                                                                       \
+  next0 = is_icmp0*NEXT_MAPME_UDP##ipv +                               \
+    (1-is_icmp0)*NEXT_INTEREST_UDP##ipv;                               \
+  next1 = is_icmp1*NEXT_MAPME_UDP##ipv +                               \
+    (1-is_icmp1)*NEXT_INTEREST_UDP##ipv;                               \
+                                                                       \
+  HICN_IFACE_UDP_ADD_LOCK_IP##ipv                                      \
+    (&(hicnb0->face_dpo_id),                                           \
+     &(ip_hdr0->dst_address),                                          \
+     &(ip_hdr0->src_address),                                          \
+     udp_hdr0->dst_port,                                               \
+     udp_hdr0->src_port,                                               \
+     GET_FACE_UDP##ipv                                                 \
+     (),                                                               \
+     &hicnb0->is_appface);                                             \
+                                                                       \
+                                                                       \
+    HICN_IFACE_UDP_ADD_LOCK_IP##ipv                                    \
+    (&(hicnb1->face_dpo_id),                                           \
+     &(ip_hdr1->dst_address),                                          \
+     &(ip_hdr1->src_address),                                          \
+     udp_hdr1->dst_port,                                               \
+     udp_hdr1->src_port,                                               \
+     GET_FACE_UDP##ipv                                                 \
+     (),                                                               \
+     &hicnb1->is_appface);                                             \
+                                                                       \
+    vlib_buffer_advance(b0, sizeof(IP_HEADER_##ipv) +                  \
+                       sizeof(udp_header_t));                          \
+                                                                       \
+    vlib_buffer_advance(b1, sizeof(IP_HEADER_##ipv) +                  \
+                       sizeof(udp_header_t));                          \
+                                                                       \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&         \
+                      (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                        \
+       TRACE_INPUT_PKT_UDP##ipv *t =                                   \
+         vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+       t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+       t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+       t->next_index = next0;                                          \
+      }                                                                        \
+                                                                       \
+                                                                       \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&         \
+                      (b1->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                        \
+       TRACE_INPUT_PKT_UDP##ipv *t =                                   \
+         vlib_add_trace (vm, node, b1, sizeof (*t));                   \
+       t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+       t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];        \
+       t->next_index = next1;                                          \
+      }                                                                        \
+                                                                       \
+                                                                       \
+    /* Verify speculative enqueue, 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(0)
+
+
+static uword
+hicn_iface_udp4_input_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         iface_input_x2 (4);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_input_x1 (4);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_udp4_input_format_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 *);
+  hicn_iface_udp4_input_trace_t *t =
+    va_arg (*args, hicn_iface_udp4_input_trace_t *);
+
+  s = format (s, "IFACE_UDP4_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_udp4_input_node) =
+
+{
+  .function = hicn_iface_udp4_input_node_fn,
+  .name = "hicn-iface-udp4-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_udp4_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_udp4_input_error_strings),
+  .error_strings = hicn_iface_udp4_input_error_strings,
+  .n_next_nodes = HICN_IFACE_UDP4_INPUT_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_IFACE_UDP4_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup",
+    [HICN_IFACE_UDP4_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl",
+    [HICN_IFACE_UDP4_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+static uword
+hicn_iface_udp6_input_node_fn (vlib_main_t * vm,
+                              vlib_node_runtime_t * node,
+                              vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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);
+
+      /* Dual loop, X2 */
+      while (n_left_from >= 4 && n_left_to_next >= 2)
+       {
+         iface_input_x2 (6);
+       }
+
+      /* Dual loop, X1 */
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_input_x1 (6);
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_udp6_input_format_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 *);
+  hicn_iface_udp6_input_trace_t *t =
+    va_arg (*args, hicn_iface_udp6_input_trace_t *);
+
+  s = format (s, "IFACE_UDP6_INPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_udp6_input_node) =
+{
+  .function = hicn_iface_udp6_input_node_fn,
+  .name = "hicn-iface-udp6-input",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_udp6_input_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_udp6_input_error_strings),
+  .error_strings = hicn_iface_udp6_input_error_strings,
+  .n_next_nodes = HICN_IFACE_UDP6_INPUT_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_IFACE_UDP6_INPUT_NEXT_INTEREST] = "hicn-interest-pcslookup",
+    [HICN_IFACE_UDP6_INPUT_NEXT_MAPME] = "hicn-mapme-ctrl",
+    [HICN_IFACE_UDP6_INPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/******* Iface Output *******/
+
+always_inline void
+hicn_iface_udp4_encap (vlib_main_t * vm,
+                      vlib_buffer_t * b0, hicn_face_t * face)
+{
+  u16 new_l0 = 0;
+  ip4_header_t *ip0;
+  udp_header_t *udp0;
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+
+  /* Adjust vlib buffers */
+  /* Set the right length on the header buffer */
+  /* Move the next buffer current data pointer back to the ip+tcp header (hicn header) */
+  int offset = sizeof (ip4_header_t) + sizeof (udp_header_t);
+  b0->current_data -= offset;
+  b0->current_length += offset;
+
+  /* ip */
+  ip0 = vlib_buffer_get_current (b0);
+  clib_memcpy (ip0, &(face_udp->hdrs.ip4.ip), sizeof (ip4_header_t) +
+              sizeof (udp_header_t));
+
+  /* Fix UDP length */
+  udp0 = (udp_header_t *) (ip0 + 1);
+
+  new_l0 =
+    clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0) -
+                         sizeof (*ip0));
+  udp0->length = new_l0;
+
+  ip0->length = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+  ip0->checksum = ip4_header_checksum (ip0);
+}
+
+always_inline void
+hicn_iface_udp6_encap (vlib_main_t * vm,
+                      vlib_buffer_t * b0, hicn_face_t * face)
+{
+  int bogus0;
+  u16 new_l0;
+  ip6_header_t *ip0;
+  udp_header_t *udp0;
+  hicn_face_udp_t *face_udp = (hicn_face_udp_t *) face->data;
+
+  /* Adjust vlib buffer */
+  int offset = sizeof (ip6_header_t) + sizeof (udp_header_t);
+  b0->current_data -= offset;
+  b0->current_length += offset;
+
+  /* ip */
+  ip0 = vlib_buffer_get_current (b0);
+  clib_memcpy (ip0, &(face_udp->hdrs.ip6.ip), sizeof (ip6_header_t) +
+              sizeof (udp_header_t));
+
+  new_l0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0)
+                                - sizeof (*ip0));
+
+  ip0->payload_length = new_l0;
+
+  /* Fix UDP length */
+  udp0 = (udp_header_t *) (ip0 + 1);
+  udp0->length = new_l0;
+
+  udp0->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, &bogus0);
+
+  ASSERT (bogus0 == 0);
+
+  if (udp0->checksum == 0)
+    udp0->checksum = 0xffff;
+}
+
+static char *hicn_iface_udp4_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+static char *hicn_iface_udp6_output_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_udp4_output_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP,
+  HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_UDP4_OUTPUT_N_NEXT,
+} hicn_iface_udp4_output_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_iface_udp6_output_trace_t;
+
+typedef enum
+{
+  HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP,
+  HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP,
+  HICN_IFACE_UDP6_OUTPUT_N_NEXT,
+} hicn_iface_udp6_output_next_t;
+
+#define ERROR_OUTPUT_UDP4 HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP
+#define ERROR_OUTPUT_UDP6 HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP
+
+#define IP_HEADER_4 ip4_header_t
+#define IP_HEADER_6 ip6_header_t
+
+#define NEXT_LOOKUP_UDP4 HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP
+#define NEXT_LOOKUP_UDP6 HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP
+
+#define HICN_IFACE_UDP_ADD_LOCK_IP4 hicn_dpo_udp4_add_and_lock
+#define HICN_IFACE_UDP_ADD_LOCK_IP6 hicn_dpo_udp6_add_and_lock
+
+#define HICN_FACE_UDP_ENCAP_IP4 hicn_iface_udp4_encap
+#define HICN_FACE_UDP_ENCAP_IP6 hicn_iface_udp6_encap
+
+#define TRACE_OUTPUT_PKT_UDP4 hicn_iface_udp4_output_trace_t
+#define TRACE_OUTPUT_PKT_UDP6 hicn_iface_udp6_output_trace_t
+
+#define iface_output_x1(ipv)                                        \
+  do {                                                              \
+  vlib_buffer_t *b0;                                                \
+  u32 bi0;                                                          \
+  u32 next0 = ERROR_OUTPUT_UDP##ipv;                                \
+  hicn_face_t * face;                                               \
+                                                                    \
+  /* Prefetch for next iteration. */                                \
+  if (n_left_from > 1)                                              \
+    {                                                               \
+      vlib_buffer_t *b1;                                            \
+      b1 = vlib_get_buffer (vm, from[1]);                           \
+      CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);             \
+      CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES , LOAD);       \
+    }                                                               \
+  /* Dequeue a packet buffer */                                     \
+  bi0 = from[0];                                                    \
+  from += 1;                                                        \
+  n_left_from -= 1;                                                 \
+  to_next[0] = bi0;                                                 \
+  to_next += 1;                                                     \
+  n_left_to_next -= 1;                                              \
+                                                                   \
+  b0 = vlib_get_buffer (vm, bi0);                                       \
+                                                                       \
+  face =                                                                \
+    hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]);    \
+                                                                        \
+  if (PREDICT_TRUE(face != NULL))                                       \
+    {                                                                   \
+      HICN_FACE_UDP_ENCAP_IP##ipv                                       \
+        (vm, b0, face);                                                 \
+      next0 = NEXT_LOOKUP_UDP##ipv;                                     \
+      stats.pkts_data_count += 1;                                      \
+    }                                                                   \
+                                                                        \
+  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&            \
+                     (b0->flags & VLIB_BUFFER_IS_TRACED)))              \
+    {                                                                   \
+      TRACE_OUTPUT_PKT_UDP##ipv *t =                                    \
+        vlib_add_trace (vm, node, b0, sizeof (*t));                     \
+      t->pkt_type = HICN_PKT_TYPE_INTEREST;                             \
+      t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];          \
+      t->next_index = next0;                                            \
+    }                                                                   \
+                                                                        \
+                                                                        \
+  /* 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);                         \
+  } while(0)
+
+#define iface_output_x2(ipv)                                        \
+  do {                                                                 \
+    vlib_buffer_t *b0, *b1;                                            \
+    u32 bi0, bi1;                                                      \
+    u32 next0 = ERROR_OUTPUT_UDP##ipv, next1 = ERROR_OUTPUT_UDP##ipv;  \
+    hicn_face_t *face0, *face1;                                                \
+                                                                       \
+    /* Prefetch for next iteration. */                                 \
+    {                                                                  \
+      vlib_buffer_t *b2, *b3;                                          \
+      b2 = vlib_get_buffer (vm, from[2]);                              \
+      b3 = vlib_get_buffer (vm, from[3]);                              \
+      CLIB_PREFETCH (b2, CLIB_CACHE_LINE_BYTES, STORE);                        \
+      CLIB_PREFETCH (b3, CLIB_CACHE_LINE_BYTES, STORE);                        \
+      CLIB_PREFETCH (b2->data, CLIB_CACHE_LINE_BYTES , LOAD);          \
+      CLIB_PREFETCH (b3->data, CLIB_CACHE_LINE_BYTES , LOAD);          \
+    }                                                                  \
+                                                                       \
+    /* Dequeue packets buffers */                                      \
+    bi0 = from[0];                                                     \
+    bi1 = from[1];                                                     \
+    from += 2;                                                         \
+    n_left_from -= 2;                                                  \
+    to_next[0] = bi0;                                                  \
+    to_next[1] = bi1;                                                  \
+    to_next += 2;                                                      \
+    n_left_to_next -= 2;                                               \
+                                                                       \
+    b0 = vlib_get_buffer (vm, bi0);                                    \
+    b1 = vlib_get_buffer (vm, bi1);                                    \
+                                                                       \
+    face0 =                                                            \
+      hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+    face1 =                                                            \
+      hicn_dpoi_get_from_idx(vnet_buffer (b0)->ip.adj_index[VLIB_TX]); \
+                                                                        \
+    if (PREDICT_TRUE(face0 != NULL))                                   \
+      {                                                                        \
+       HICN_FACE_UDP_ENCAP_IP##ipv                                     \
+         (vm, b0, face0);                                              \
+       next0 = NEXT_LOOKUP_UDP##ipv;                                   \
+       stats.pkts_data_count += 1;                                     \
+      }                                                                        \
+                                                                       \
+    if (PREDICT_TRUE(face1 != NULL))                                   \
+      {                                                                        \
+       HICN_FACE_UDP_ENCAP_IP##ipv                                     \
+         (vm, b1, face1);                                              \
+       next0 = NEXT_LOOKUP_UDP##ipv;                                   \
+       stats.pkts_data_count += 1;                                     \
+      }                                                                        \
+                                                                       \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&         \
+                      (b0->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                        \
+       TRACE_OUTPUT_PKT_UDP##ipv *t =                                  \
+         vlib_add_trace (vm, node, b0, sizeof (*t));                   \
+       t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+       t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];        \
+       t->next_index = next0;                                          \
+      }                                                                        \
+                                                                        \
+    if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&         \
+                      (b1->flags & VLIB_BUFFER_IS_TRACED)))            \
+      {                                                                        \
+       TRACE_OUTPUT_PKT_UDP##ipv *t =                                  \
+         vlib_add_trace (vm, node, b1, sizeof (*t));                   \
+       t->pkt_type = HICN_PKT_TYPE_INTEREST;                           \
+       t->sw_if_index = vnet_buffer (b1)->sw_if_index[VLIB_RX];        \
+       t->next_index = next1;                                          \
+      }                                                                        \
+                                                                       \
+                                                                       \
+  /* Verify speculative enqueue, 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(0)
+
+
+static uword
+hicn_iface_udp4_output_node_fn (vlib_main_t * vm,
+                               vlib_node_runtime_t * node,
+                               vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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)
+       {
+         iface_output_x2 (4);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_output_x1 (4);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_udp4_output_format_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 *);
+  hicn_iface_udp4_output_trace_t *t =
+    va_arg (*args, hicn_iface_udp4_output_trace_t *);
+
+  s = format (s, "IFACE_UDP4_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_udp4_output_node) =
+{
+  .function = hicn_iface_udp4_output_node_fn,
+  .name = "hicn-iface-udp4-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_udp4_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_udp4_output_error_strings),
+  .error_strings = hicn_iface_udp4_output_error_strings,
+  .n_next_nodes = HICN_IFACE_UDP4_OUTPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_IFACE_UDP4_OUTPUT_NEXT_LOOKUP] = "ip4-lookup",
+    [HICN_IFACE_UDP4_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+
+static uword
+hicn_iface_udp6_output_node_fn (vlib_main_t * vm,
+                               vlib_node_runtime_t * node,
+                               vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next, next_index;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 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)
+       {
+         iface_output_x2 (6);
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         iface_output_x1 (6);
+       }
+
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, node->node_index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  return (frame->n_vectors);
+
+}
+
+/* packet trace format function */
+static u8 *
+hicn_iface_udp6_output_format_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 *);
+  hicn_iface_udp6_output_trace_t *t =
+    va_arg (*args, hicn_iface_udp6_output_trace_t *);
+
+  s = format (s, "IFACE_UDP6_OUTPUT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_iface_udp6_output_node) =
+{
+  .function = hicn_iface_udp6_output_node_fn,
+  .name = "hicn-iface-udp6-output",
+  .vector_size =  sizeof (u32),
+  .format_trace = hicn_iface_udp6_output_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_iface_udp6_output_error_strings),
+  .error_strings = hicn_iface_udp6_output_error_strings,
+  .n_next_nodes = HICN_IFACE_UDP6_OUTPUT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_IFACE_UDP6_OUTPUT_NEXT_LOOKUP] = "ip6-lookup",
+    [HICN_IFACE_UDP6_OUTPUT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/faces/udp/iface_udp_node.h b/hicn-plugin/src/faces/udp/iface_udp_node.h
new file mode 100755 (executable)
index 0000000..957d192
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_IFACE_UDP_H__
+#define __HICN_IFACE_UDP_H__
+
+#include <vlib/vlib.h>
+
+extern vlib_node_registration_t hicn_iface_udp4_input_node;
+extern vlib_node_registration_t hicn_iface_udp6_input_node;
+extern vlib_node_registration_t hicn_iface_udp4_output_node;
+extern vlib_node_registration_t hicn_iface_udp6_output_node;
+
+void hicn_iface_udp_init (vlib_main_t * vm);
+
+#endif // __HICN_FACE_UDP_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/hashtb.c b/hicn-plugin/src/hashtb.c
new file mode 100755 (executable)
index 0000000..332da35
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include <vlib/vlib.h>
+#include <vppinfra/pool.h>
+
+#include "pcs.h"
+#include "hashtb.h"
+#include "parser.h"
+#include "error.h"
+
+/* return dvd/dvr, rounded up (intended for integer values) */
+#define    CEIL(dvd, dvr)                       \
+  ({                                            \
+    __typeof__ (dvd) _dvd = (dvd);              \
+    __typeof__ (dvr) _dvr = (dvr);              \
+    (_dvd + _dvr - 1)/_dvr;                     \
+  })
+
+#ifndef ALIGN8
+#define ALIGN8(p) (((p) + 0x7) & ~(0x7))
+#endif
+
+#ifndef ALIGNPTR8
+#define ALIGNPTR8(p) ((void *)(((u8 * )(p) + 0x7) & ~(0x7)))
+#endif
+
+#ifndef ALIGN64
+#define ALIGN64(p) (((p) + 0x3f) & ~(0x3f))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/*
+ * Offset to aligned start of additional data (PIT/CS, FIB) embedded in each
+ * node.
+ */
+u32 ht_node_data_offset_aligned;
+
+/* Some support for posix vs vpp mem management */
+#define MEM_ALLOC(x) clib_mem_alloc_aligned((x), 8)
+#define MEM_FREE(p) clib_mem_free((p))
+
+/*
+ * Internal utilities
+ */
+
+/* Allocate an overflow bucket */
+static hicn_hash_bucket_t *
+alloc_overflow_bucket (hicn_hashtb_h h)
+{
+  hicn_hash_bucket_t *newbkt = NULL;
+
+  if (h->ht_overflow_buckets_used < h->ht_overflow_bucket_count)
+    {
+      pool_get_aligned (h->ht_overflow_buckets, newbkt, 8);
+
+      if (newbkt)
+       {
+         h->ht_overflow_buckets_used++;
+       }
+    }
+  return (newbkt);
+}
+
+/* Free an overflow bucket; clear caller's pointer */
+static void
+free_overflow_bucket (hicn_hashtb_h h, hicn_hash_bucket_t ** pb)
+{
+  hicn_hash_bucket_t *bkt = *pb;
+
+  ASSERT (h->ht_overflow_buckets_used > 0);
+
+  pool_put (h->ht_overflow_buckets, bkt);
+  h->ht_overflow_buckets_used--;
+  *pb = NULL;
+}
+
+/*
+ * Init, allocate a new hashtable
+ */
+int
+hicn_hashtb_alloc (hicn_hashtb_h * ph, u32 max_elems, size_t app_data_size)
+{
+  int ret = HICN_ERROR_NONE;
+  hicn_hashtb_h h = NULL;
+  u32 count;
+  u32 total_buckets;
+  size_t sz;
+  hicn_hash_node_t *nodep;
+  hicn_hash_bucket_t *bucket;
+
+  if (ph == NULL)
+    {
+      ret = HICN_ERROR_HASHTB_INVAL;
+      goto done;
+    }
+  if (max_elems < HICN_HASHTB_MIN_ENTRIES ||
+      max_elems > HICN_HASHTB_MAX_ENTRIES)
+    {
+      goto done;
+    }
+  /* Allocate and init main hashtable struct */
+  h = MEM_ALLOC (sizeof (hicn_hashtb_t));
+  if (h == NULL)
+    {
+      ret = HICN_ERROR_HASHTB_NOMEM;
+      goto done;
+    }
+  memset (h, 0, sizeof (hicn_hashtb_t));
+
+  /* Compute main table bucket (row) count and size, and allocate */
+
+  /* Consider the last entry as used for containing the overflow bucket */
+  total_buckets = CEIL (max_elems, HICN_HASHTB_BUCKET_ENTRIES - 1);
+  count = ALIGN8 (CEIL (total_buckets, HICN_HASHTB_FILL_FACTOR));
+
+  h->ht_bucket_count = count;
+
+  /* We _really_ expect to have buckets aligned on cache lines ... */
+  sz = sizeof (hicn_hash_bucket_t);
+  assert (sz == ALIGN64 (sz));
+
+  h->ht_buckets = MEM_ALLOC (count * sz);
+  if (h->ht_buckets == NULL)
+    {
+      ret = HICN_ERROR_HASHTB_NOMEM;
+      goto done;
+    }
+  memset (h->ht_buckets, 0, count * sz);
+
+  /*
+   * First time through, compute offset to aligned extra data start in
+   * each node struct it's crucial that both the node struct (that the
+   * base hashtable uses) and the extra data area (that's also probably
+   * a struct) are aligned.
+   */
+  if (ht_node_data_offset_aligned == 0)
+    {
+      count = STRUCT_OFFSET_OF (hicn_hash_node_t, hn_data);
+      ht_node_data_offset_aligned = ALIGN8 (count);
+    }
+  //check app struct fits into space provided(HICN_HASH_NODE_APP_DATA_SIZE)
+  u32 ht_node_data_size;
+  ht_node_data_size = sizeof (hicn_hash_node_t) - ht_node_data_offset_aligned;
+  if (app_data_size > ht_node_data_size)
+    {
+      clib_error
+       ("hicn hashtable: fatal error: requested app data size(%u) > hashtb node's configured bytes available(%u), sizeof(hicn_shared_t)=%u, sizeof(hicn_pit_entry_t)=%u, sizeof(hicn_cs_entry_t)=%u",
+        app_data_size, ht_node_data_size, sizeof (hicn_pcs_shared_t),
+        sizeof (hicn_pit_entry_t), sizeof (hicn_cs_entry_t));
+    }
+  /*
+   * Compute entry node count and size, allocate Allocate/'Hide' the
+   * zero-th node so can use zero as an 'empty' value
+   */
+  pool_alloc_aligned (h->ht_nodes, max_elems, 8);
+  if (h->ht_nodes == NULL)
+    {
+      ret = HICN_ERROR_HASHTB_NOMEM;
+      goto done;
+    }
+  pool_get_aligned (h->ht_nodes, nodep, 8);
+  //alloc node 0
+  nodep = nodep;               /* Silence 'not used' warning */
+
+  h->ht_node_count = max_elems;
+  h->ht_nodes_used = 1;
+
+  /*
+   * Compute overflow bucket count and size, allocate
+   */
+  //count = ALIGN8(CEIL(max_elems, HICN_HASHTB_OVERFLOW_FRACTION));
+  count = ALIGN8 (total_buckets - h->ht_bucket_count);
+
+  pool_alloc_aligned (h->ht_overflow_buckets, count, 8);
+  if (h->ht_overflow_buckets == NULL)
+    {
+      ret = HICN_ERROR_HASHTB_NOMEM;
+      goto done;
+    }
+  /* 'Hide' the zero-th node so we can use zero as an 'empty' value */
+  pool_get_aligned (h->ht_overflow_buckets, bucket, 8);
+  bucket = bucket;             /* Silence 'not used' warning */
+
+  h->ht_overflow_bucket_count = count;
+  h->ht_overflow_buckets_used = 1;
+
+done:
+
+  if (h)
+    {
+      if ((ret == HICN_ERROR_NONE) && ph)
+       {
+         *ph = h;
+       }
+      else
+       {
+         hicn_hashtb_free (&h);
+       }
+    }
+  return (ret);
+}
+
+/*
+ * Free, de-allocate a hashtable
+ */
+int
+hicn_hashtb_free (hicn_hashtb_h * ph)
+{
+  int ret = 0;
+
+  if (ph)
+    {
+      if ((*ph)->ht_nodes)
+       {
+         pool_free ((*ph)->ht_nodes);
+         (*ph)->ht_nodes = 0;
+       }
+      if ((*ph)->ht_overflow_buckets)
+       {
+         pool_free ((*ph)->ht_overflow_buckets);
+         (*ph)->ht_overflow_buckets = 0;
+       }
+      if ((*ph)->ht_buckets)
+       {
+         MEM_FREE ((*ph)->ht_buckets);
+         (*ph)->ht_buckets = 0;
+       }
+      MEM_FREE (*ph);
+
+      *ph = NULL;
+    }
+  return (ret);
+}
+
+
+
+/*
+ * Basic api to lookup a specific hash+key tuple. This does the entire lookup
+ * operation, retrieving node structs and comparing keys, so it's not
+ * optimized for prefetching or high performance.
+ *
+ * Returns zero and mails back a node on success, errno otherwise.
+ */
+int
+hicn_hashtb_lookup_node (hicn_hashtb_h h, const u8 * key,
+                        u32 keylen, u64 hashval, u8 is_data,
+                        u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                        u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                        u8 * bucket_is_overflow)
+{
+  return (hicn_hashtb_lookup_node_ex
+         (h, key, keylen, hashval, is_data, FALSE /* deleted nodes */ ,
+          node_id,
+          dpo_ctx_id, vft_id, is_cs, hash_entry_id, bucket_id,
+          bucket_is_overflow));
+}
+
+/*
+ * Extended api to lookup a specific hash+key tuple. The implementation
+ * allows the caller to locate nodes that are marked for deletion, which is
+ * part of some hashtable applications, such as the FIB.
+ *
+ * This does the entire lookup operation, retrieving node structs and comparing
+ * keys, so it's not optimized for prefetching or high performance.
+ *
+ * Returns zero and mails back a node on success, errno otherwise.
+ */
+int
+hicn_hashtb_lookup_node_ex (hicn_hashtb_h h, const u8 * key,
+                           u32 keylen, u64 hashval, u8 is_data,
+                           int include_deleted_p, u32 * node_id,
+                           u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                           u8 * hash_entry_id, u32 * bucket_id,
+                           u8 * bucket_is_overflow)
+{
+  int i, ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND;
+  int found_p = FALSE;
+  u32 bidx;
+  hicn_hash_bucket_t *bucket;
+  u32 current_bucket_id = ~0;
+
+  /*
+   * Use some bits of the low half of the hash to locate a row/bucket
+   * in the table
+   */
+  current_bucket_id = bidx = (hashval & (h->ht_bucket_count - 1));
+
+  bucket = h->ht_buckets + bidx;
+
+  *bucket_is_overflow = 0;
+  /* Check the entries in the bucket for matching hash value */
+
+loop_buckets:
+
+  for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES && !found_p; i++)
+    {
+      /*
+       * If an entry is marked for deletion, ignore it unless the
+       * caller explicitly wants these nodes.
+       */
+      if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED)
+       {
+         if (!include_deleted_p)
+           {
+             continue;
+           }
+       }
+      if (bucket->hb_entries[i].he_msb64 == hashval)
+       {
+         /*
+          * Found a candidate - must retrieve the actual node
+          * and check the key.
+          */
+         *node_id = bucket->hb_entries[i].he_node;
+         *dpo_ctx_id = bucket->hb_entries[i].dpo_ctx_id;
+         *vft_id = bucket->hb_entries[i].vft_id;
+         *is_cs =
+           bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY;
+         *hash_entry_id = i;
+         *bucket_id = current_bucket_id;
+         /*
+          * If we are doing lookup for a data, do not take a
+          * lock in case of a hit with a CS entry
+          */
+         if (!(is_data && *is_cs))
+           {
+             bucket->hb_entries[i].locks++;
+           }
+         found_p = TRUE;
+         ret = HICN_ERROR_NONE;
+         goto done;
+       }
+    }
+
+  /*
+   * Be prepared to continue to an overflow bucket if necessary. We
+   * only expect the last entry in a bucket to refer to an overflow
+   * bucket...
+   */
+  i = HICN_HASHTB_BUCKET_ENTRIES - 1;
+  if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW)
+    {
+      current_bucket_id = bucket->hb_entries[i].he_node;
+      bucket = pool_elt_at_index (h->ht_overflow_buckets,
+                                 bucket->hb_entries[i].he_node);
+      *bucket_is_overflow = 1;
+      goto loop_buckets;
+    }
+done:
+
+  return (ret);
+}
+
+/**
+ * This function allows to split the hash verification from the comparison of
+ * the entire key. Useful to exploit prefertching.
+ * return 1 if equals, 0 otherwise
+ */
+int
+hicn_node_compare (const u8 * key, u32 keylen, hicn_hash_node_t * node)
+{
+
+  int ret = 0;
+
+  if (key && keylen == node->hn_keysize)
+    {
+      ret = (memcmp (key, node->hn_key.ks.key, keylen) == 0);
+    }
+  return ret;
+}
+
+/*
+ * Utility to init a new entry in a hashtable bucket/row. We use this to add
+ * new a node+hash, and to clear out an entry during removal.
+ */
+void
+hicn_hashtb_init_entry (hicn_hash_entry_t * entry, u32 nodeidx,
+                       u64 hashval, u32 locks)
+{
+  entry->he_msb64 = hashval;
+  entry->he_node = nodeidx;
+
+  /* Clear out some other fields in the entry */
+  entry->he_flags = 0;
+  entry->locks = locks;
+}
+
+/*
+ * Insert a node into the hashtable. We expect the caller has a) computed the
+ * hash value to use, b) initialized the node with the hash and key info, and
+ * c) filled in its app-specific data portion of the node.
+ */
+
+int
+hicn_hashtb_insert (hicn_hashtb_h h, hicn_hash_node_t * node,
+                   hicn_hash_entry_t ** hash_entry, u64 hash,
+                   u32 * node_id,
+                   u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                   u8 * hash_entry_id, u32 * bucket_id,
+                   u8 * bucket_is_overflow)
+{
+  int i, ret = HICN_ERROR_HASHTB_INVAL;
+  u32 bidx;
+  hicn_hash_bucket_t *bucket, *newbkt;
+  int use_seven;
+  u32 current_bucket_id = ~0;
+  int is_overflow = 0;
+
+  *hash_entry = NULL;
+
+  if (h == NULL)
+    {
+      goto done;
+    }
+  /*
+   * Use some bits of the low half of the hash to locate a row/bucket
+   * in the table
+   */
+  current_bucket_id = bidx = (hash & (h->ht_bucket_count - 1));
+
+  bucket = h->ht_buckets + bidx;
+
+  use_seven = (h->ht_flags & HICN_HASHTB_FLAG_USE_SEVEN);
+
+  /* Locate a free entry slot in the bucket */
+
+loop_buckets:
+
+  for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++)
+    {
+
+      /*
+       * If an entry is marked for deletion, ignore it
+       */
+      if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED)
+       {
+         continue;
+       }
+      /*
+       * Be sure that we are not inserting the same entry twice
+       */
+      if (bucket->hb_entries[i].he_msb64 == hash)
+       {
+         /*
+          * We hit an existing pit entry. increase lock.
+          */
+
+         *node_id = bucket->hb_entries[i].he_node;
+         *dpo_ctx_id = bucket->hb_entries[i].dpo_ctx_id;
+         *vft_id = bucket->hb_entries[i].vft_id;
+         *is_cs =
+           bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY;
+         *hash_entry_id = i;
+         *bucket_id = current_bucket_id;
+         *hash_entry = &(bucket->hb_entries[i]);
+         /*
+          * If we are doing lookup for a data, do not take a
+          * lock in case of a hit with a CS entry
+          */
+         bucket->hb_entries[i].locks++;
+         *bucket_is_overflow = is_overflow;
+         ret = HICN_ERROR_HASHTB_EXIST;
+         goto done;
+       }
+      if ((bucket->hb_entries[i].he_msb64 == 0LL) &&
+         (bucket->hb_entries[i].he_node == 0))
+       {
+         /* Found a candidate -- fill it in */
+
+         /*
+          * Special case if the application asked not to use
+          * the last entry in each bucket.
+          */
+         if ((i != (HICN_HASHTB_BUCKET_ENTRIES - 1)) || use_seven)
+           {
+             hicn_hashtb_init_entry (&(bucket->hb_entries[i]),
+                                     NODE_IDX_FROM_NODE (node, h), hash, 0);
+
+             *hash_entry = &(bucket->hb_entries[i]);
+
+             node->bucket_id = current_bucket_id;
+             node->entry_idx = i;
+             if (is_overflow)
+               node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET;
+
+             ret = HICN_ERROR_NONE;
+             goto done;
+           }
+       }
+    }
+  /*
+   * Be prepared to continue to an overflow bucket if necessary, or to
+   * add a new overflow bucket. We only expect the last entry in a
+   * bucket to refer to an overflow bucket...
+   */
+  i = HICN_HASHTB_BUCKET_ENTRIES - 1;
+  if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW)
+    {
+      /* Existing overflow bucket - re-start the search loop */
+      current_bucket_id = bucket->hb_entries[i].he_node;
+      bucket = pool_elt_at_index (h->ht_overflow_buckets, current_bucket_id);
+      is_overflow = 1;
+      goto loop_buckets;
+
+    }
+  else
+    {
+      /*
+       * Overflow - reached the end of a bucket without finding a
+       * free entry slot. Need to allocate an overflow bucket, and
+       * connect it to this bucket.
+       */
+      newbkt = alloc_overflow_bucket (h);
+      if (newbkt == NULL)
+       {
+         ret = HICN_ERROR_HASHTB_NOMEM;
+         goto done;
+       }
+      /*
+       * We're touching some more bytes than we absolutely have to
+       * here, but ... that seems ok.
+       */
+      memset (newbkt, 0, sizeof (hicn_hash_bucket_t));
+
+      if (use_seven)
+       {
+         /*
+          * Copy existing entry into new bucket - we really
+          * expect these to be properly aligned so they can be
+          * treated as int.
+          */
+         memcpy (&(newbkt->hb_entries[0]),
+                 &(bucket->hb_entries[i]), sizeof (hicn_hash_entry_t));
+
+         /* Update bucket id and entry_idx on the hash node */
+         hicn_hash_node_t *node =
+           pool_elt_at_index (h->ht_nodes, newbkt->hb_entries[0].he_node);
+         node->bucket_id = (newbkt - h->ht_overflow_buckets);
+         node->entry_idx = 0;
+         node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET;
+
+       }
+      /*
+       * Connect original bucket to the index of the new overflow
+       * bucket
+       */
+      bucket->hb_entries[i].he_flags |= HICN_HASH_ENTRY_FLAG_OVERFLOW;
+      bucket->hb_entries[i].he_node = (newbkt - h->ht_overflow_buckets);
+
+      /* Add new entry to new overflow bucket */
+      bucket = newbkt;
+
+      /*
+       * Use entry [1] in the new bucket _if_ we just copied into
+       * entry [zero] above.
+       */
+      if (use_seven)
+       {
+
+         hicn_hashtb_init_entry (&(bucket->hb_entries[1]),
+                                 NODE_IDX_FROM_NODE (node, h), hash, 0);
+         *hash_entry = &(bucket->hb_entries[1]);
+
+         node->bucket_id = (newbkt - h->ht_overflow_buckets);
+         node->entry_idx = 1;
+         node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET;
+       }
+      else
+       {
+
+         hicn_hashtb_init_entry (&(bucket->hb_entries[0]),
+                                 NODE_IDX_FROM_NODE (node, h), hash, 0);
+         *hash_entry = &(bucket->hb_entries[0]);
+         node->bucket_id = (newbkt - h->ht_overflow_buckets);
+         node->entry_idx = 0;
+         node->hn_flags |= HICN_HASH_NODE_OVERFLOW_BUCKET;
+       }
+    }
+
+  /* And we're done with the overflow bucket */
+  ret = HICN_ERROR_NONE;
+
+done:
+
+  return (ret);
+}
+
+/*
+ * Delete a node from a hashtable using the node itself, and delete/free the
+ * node. Caller's pointer is cleared on success.
+ */
+void
+hicn_hashtb_delete (hicn_hashtb_h h, hicn_hash_node_t ** pnode, u64 hashval)
+{
+
+  hicn_hashtb_remove_node (h, *pnode, hashval);
+  hicn_hashtb_free_node (h, *pnode);
+  *pnode = NULL;
+
+}
+
+/*
+ * Delete an entry from a hashtable using the node itself. If the node was
+ * stored in an overflow bucket, and the bucket is empty after freeing the
+ * node, the bucket is freed as well.
+ */
+void
+hicn_hashtb_remove_node (hicn_hashtb_h h, hicn_hash_node_t * node,
+                        u64 hashval)
+{
+  int i, count;
+  u32 bidx, overflow_p;
+  hicn_hash_bucket_t *bucket, *parent;
+
+  if ((h == NULL) || (node == NULL))
+    {
+      goto done;
+    }
+  if (node->hn_flags & HICN_HASH_NODE_OVERFLOW_BUCKET)
+    bucket = pool_elt_at_index (h->ht_overflow_buckets, node->bucket_id);
+  else
+    {
+      /*
+       * Use some bits of the low half of the hash to locate a
+       * row/bucket in the table
+       */
+      bidx = (hashval & (h->ht_bucket_count - 1));
+      ASSERT (bidx == node->bucket_id);
+      bucket = h->ht_buckets + node->bucket_id;
+    }
+
+  overflow_p = node->hn_flags & HICN_HASH_NODE_OVERFLOW_BUCKET;
+
+  /* Clear out the entry. */
+  hicn_hashtb_init_entry (&(bucket->hb_entries[node->entry_idx]), 0, 0LL, 0);
+
+  if (!overflow_p)
+    {
+      /*
+       * And we're done, in the easy case where we didn't change an
+       * overflow bucket
+       */
+      goto done;
+    }
+  /*
+   * The special case: if this is the last remaining entry in an
+   * overflow bucket, liberate the bucket. That in turn has a special
+   * case if this bucket is in the middle of a chain of overflow
+   * buckets.
+   *
+   * Note that we're not trying aggressively (yet) to condense buckets at
+   * every possible opportunity.
+   */
+
+  /*
+   * Reset this flag; we'll set it again if this bucket links to
+   * another
+   */
+  overflow_p = FALSE;
+
+  for (i = 0, count = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++)
+    {
+      if (bucket->hb_entries[i].he_node != 0)
+       {
+         count++;
+       }
+      if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1) &&
+         (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW))
+       {
+         count--;              /* Doesn't count as a 'real' entry */
+         overflow_p = TRUE;
+       }
+    }
+
+  if (count > 0)
+    {
+      /* Still a (real) entry in the row */
+      goto done;
+    }
+  /*
+   * Need to locate the predecessor of 'bucket': start at the beginning
+   * of the chain of buckets and move forward
+   */
+  bidx = (hashval & (h->ht_bucket_count - 1));
+
+  for (parent = h->ht_buckets + bidx; parent != NULL;)
+    {
+
+      if ((parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_flags &
+          HICN_HASH_ENTRY_FLAG_OVERFLOW) == 0)
+       {
+         parent = NULL;
+         break;
+       }
+      bidx = parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node;
+
+      if (pool_elt_at_index (h->ht_overflow_buckets, bidx) == bucket)
+       {
+         /*
+          * Found the predecessor of 'bucket'. If 'bucket' has
+          * a successor, connect 'parent' to it, and take
+          * 'bucket out of the middle.
+          */
+         if (overflow_p)
+           {
+             parent->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node =
+               bucket->hb_entries[(HICN_HASHTB_BUCKET_ENTRIES - 1)].he_node;
+           }
+         else
+           {
+             /*
+              * Just clear the predecessor entry pointing
+              * at 'bucket'
+              */
+             hicn_hashtb_init_entry (&parent->hb_entries
+                                     [(HICN_HASHTB_BUCKET_ENTRIES - 1)], 0,
+                                     0LL, 0);
+           }
+
+         break;
+       }
+      /*
+       * After the first iteration, 'parent' will be an overflow
+       * bucket too
+       */
+      parent = pool_elt_at_index (h->ht_overflow_buckets, bidx);
+    }
+
+  /* We really expect to have found the predecessor */
+  ASSERT (parent != NULL);
+
+  /* And now, finally, we can put 'bucket' back on the free list */
+  free_overflow_bucket (h, &bucket);
+
+done:
+  return;
+}
+
+/*
+ * Prepare a hashtable node, supplying the key, and computed hash info.
+ */
+void
+hicn_hashtb_init_node (hicn_hashtb_h h, hicn_hash_node_t * node,
+                      const u8 * key, u32 keylen)
+{
+  assert (h != NULL);
+  assert (node != NULL);
+  assert (keylen <= HICN_PARAM_HICN_NAME_LEN_MAX);
+
+  /* Init the node struct */
+  node->hn_flags = HICN_HASH_NODE_FLAGS_DEFAULT;
+  node->hn_keysize = 0;
+  node->hn_keysize = keylen;
+  memcpy (node->hn_key.ks.key, key, keylen);
+  node->bucket_id = ~0;
+  node->entry_idx = ~0;
+}
+
+/*
+ * Release a hashtable node back to the free list when an entry is cleared
+ */
+void
+hicn_hashtb_free_node (hicn_hashtb_h h, hicn_hash_node_t * node)
+{
+  ASSERT (h->ht_nodes_used > 0);
+
+  /* Return 'node' to the free list */
+  pool_put (h->ht_nodes, node);
+  h->ht_nodes_used--;
+
+}
+
+/*
+ * Walk a hashtable, iterating through the nodes, keeping context in 'ctx'.
+ */
+int
+hicn_hashtb_next_node (hicn_hashtb_h h, hicn_hash_node_t ** pnode, u64 * ctx)
+{
+  int i, j, ret = HICN_ERROR_HASHTB_INVAL;
+  u32 bidx, entry;
+  hicn_hash_bucket_t *bucket;
+
+  if ((h == NULL) || (pnode == NULL) || (ctx == NULL))
+    {
+      goto done;
+    }
+  /* Special-case for new iteration */
+  if (*ctx == HICN_HASH_WALK_CTX_INITIAL)
+    {
+      bidx = 0;
+      bucket = &h->ht_buckets[0];
+      entry = 0;
+      j = 0;
+      i = 0;
+      goto search_table;
+    }
+  /* Convert context to bucket and entry indices */
+  bidx = *ctx & 0xffffffffLL;
+  entry = *ctx >> 32;
+
+  if (bidx >= h->ht_bucket_count)
+    {
+      ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND;
+      goto done;
+    }
+  bucket = h->ht_buckets + bidx;
+
+  /* Init total index into entries (includes fixed bucket and overflow) */
+  j = 0;
+
+skip_processed_bucket_chunks:
+  /*
+   * Figure out where to resume the search for the next entry in the
+   * table, by trying to find the last entry returned, from the cookie.
+   * Loop walks one (regular or overflow) bucket chunk, label is used
+   * for walking chain of chunks. Note that if there was a deletion or
+   * an addition that created an overflow, iterator can skip entries or
+   * return duplicate entries, for entries that are present from before
+   * the walk starts until after it ends.
+   */
+
+  for (i = 0; i < HICN_HASHTB_BUCKET_ENTRIES; i++, j++)
+    {
+      if (j > entry)
+       {
+         /*
+          * Start search for next here, use existing 'bucket'
+          * and 'i'
+          */
+         break;
+       }
+      /*
+       * If an entry is marked for deletion, ignore it
+       */
+      if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED)
+       {
+         continue;
+       }
+      /*
+       * Be prepared to continue to an overflow bucket if
+       * necessary. (We only expect the last entry in a bucket to
+       * refer to an overflow bucket...)
+       */
+      if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1))
+       {
+         if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW)
+           {
+             bucket = pool_elt_at_index (h->ht_overflow_buckets,
+                                         bucket->hb_entries[i].he_node);
+
+             /* Increment overall entry counter 'j' */
+             j++;
+
+             goto skip_processed_bucket_chunks;
+           }
+         /*
+          * end of row (end of fixed bucket plus any
+          * overflows)
+          */
+         i = 0;
+         j = 0;
+
+         bidx++;
+
+         /* Special case - we're at the end */
+         if (bidx >= h->ht_bucket_count)
+           {
+             ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND;
+             goto done;
+           }
+         bucket = h->ht_buckets + bidx;
+         break;
+       }
+    }
+
+search_table:
+
+  /*
+   * Now we're searching through the table for the next entry that's
+   * set
+   */
+
+  for (; i < HICN_HASHTB_BUCKET_ENTRIES; i++, j++)
+    {
+      /*
+       * If an entry is marked for deletion, ignore it
+       */
+      if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_DELETED)
+       {
+         continue;
+       }
+      /* Is this entry set? */
+      if (bucket->hb_entries[i].he_node != 0)
+       {
+
+         /* Retrieve the node struct */
+         *pnode = pool_elt_at_index (h->ht_nodes,
+                                     bucket->hb_entries[i].he_node);
+
+         /*
+          * Set 'entry' as we exit, so we can update the
+          * cookie
+          */
+         entry = j;
+         ret = HICN_ERROR_NONE;
+         break;
+       }
+      /*
+       * Be prepared to continue to an overflow bucket if
+       * necessary. (We only expect the last entry in a bucket to
+       * refer to an overflow bucket...)
+       */
+      if (i == (HICN_HASHTB_BUCKET_ENTRIES - 1))
+       {
+         if (bucket->hb_entries[i].he_flags & HICN_HASH_ENTRY_FLAG_OVERFLOW)
+           {
+             bucket = pool_elt_at_index (h->ht_overflow_buckets,
+                                         bucket->hb_entries[i].he_node);
+             /*
+              * Reset per-bucket index 'i', here (not done
+              * in iterator)
+              */
+             i = 0;
+             /* Increment overall entry counter 'j' */
+             j++;
+
+             goto search_table;
+           }
+         else
+           {
+             /*
+              * Move to next bucket, resetting per-bucket
+              * and overall entry indexes
+              */
+             i = 0;
+             j = 0;
+
+             bidx++;
+
+             /* Special case - we're at the end */
+             if (bidx >= h->ht_bucket_count)
+               {
+                 ret = HICN_ERROR_HASHTB_HASH_NOT_FOUND;
+                 goto done;
+               }
+             bucket = h->ht_buckets + bidx;
+             goto search_table;
+           }
+       }
+    }
+
+done:
+
+  if (ret == HICN_ERROR_NONE)
+    {
+      /* Update context */
+      *ctx = bidx;
+      *ctx |= ((u64) entry << 32);
+    }
+  return (ret);
+}
+
+int
+hicn_hashtb_key_to_buf (u8 ** vec_res, hicn_hashtb_h h,
+                       const hicn_hash_node_t * node)
+{
+  int ret = HICN_ERROR_NONE;
+  u8 *vec = *vec_res;
+
+  if (node->hn_keysize <= HICN_HASH_KEY_BYTES)
+    {
+      vec_add (vec, node->hn_key.ks.key, node->hn_keysize);
+    }
+  *vec_res = vec;
+  return (ret);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hashtb.h b/hicn-plugin/src/hashtb.h
new file mode 100755 (executable)
index 0000000..1690419
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_HASHTB_H__
+#define __HICN_HASHTB_H__
+
+#include <stdint.h>
+#include <vppinfra/bihash_8_8.h>
+#include <vppinfra/bihash_24_8.h>
+
+#include "params.h"
+#include "parser.h"
+#include "error.h"
+
+/* Handy abbreviations for success status, and for boolean values */
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/*
+ * Lookup is finding a hashtable record whose name matches the name being
+ * looked up.  Most of the lookup work is based on the hash value of the two
+ * names. Note that the intel cache line size is 64 bytes, and some platforms
+ * load in 2 cache lines together. - first step is to match a record at the
+ * bucket/slot level (htab has an array of htbucket_t/htbc_elmt, where each
+ * bucket has 7 slots to hold indices for entries.) Matching at this level
+ * implies - the hashes of the lookup name and the record map to the same
+ * bucket - the high 32 bits of the hashes (slot bce_hash_msb32s) match. Read
+ * cost (on the hash table size, i.e. ignoring reading the name being looked
+ * up): - First step normally requires 1 cache line load to pull in the
+ * 64-byte htbucket_t with the 7 element slot table holding the hash_msb32s.
+ * - In the event (hopefully rare for a hash table with appropriate number of
+ * buckets) that more than 7 elements hash to the same bucket, lookup may
+ * well need to look not only at the static htbc_elmt_t but at the chain of
+ * dynamically allocated htbc_elmt_t's linked to the static htbc_elmt_t,
+ * where each of these holds slot entries for additional elements. - Before
+ * reaching that point, it is initially required is to read in the hash table
+ * record fields (ht_bucket_buf, htnode buf, etc) holding pointers to the
+ * arrays, but these cache lines are common to all lookups so will likely
+ * already be in the cache. - second step is to match at the record level
+ * (htnode/htkb level) once a slot-level match happens. Matching at this
+ * level implies the following match - the hash values (the full 64 bits vs.
+ * bucket+32 msb, above) With siphash, two names hashing to the same 64-bit
+ * value is quite rare. - the name which, on the hash table side, is stored
+ * as a list of htkb_t (key buffers). [In some cases, the full name is not
+ * compared, and a match is assumed based on hash value match. Read cost: -
+ * htnode_t, in one cache line, holds hash value and index for the htkb at
+ * the head of the key buffer list - each key buffer (htkb_t) is cache line
+ * aligned/sized, and holds 60 bytes of the name and requires a cache line
+ * read. Simplification is that a fib lookup requires 3 cache lines: - bucket
+ * - htnode - single key buffer (for cases where a name comparision is done)
+ *
+ * Some hashtables (for which rare false positives are tolerable) store hash
+ * values but no keys. (In ISM NDN forwarder, this was used for dcm_dpf: data
+ * cache manager's dataplane filter, where speed was critical and very rare
+ * false positives would be detected in the full dcm check.) - No key buffers
+ * are used (or even allocated at hash table creation).
+ */
+
+#define HICN_HASH_INVALID_IDX  ~0
+/*
+ * for hicn_hashtb_next_node() iterator, this otherwise illegal context value
+ * indicates first call of iteration. Note: must not be 0, which is a legal
+ * context value.
+ */
+#define HICN_HASH_WALK_CTX_INITIAL (~((u64)0))
+
+/*
+ * Key memory allocation scheme.
+ *
+ * The key is the bytestring that a hashtable entry is storing, e.g. a fib
+ * prefix or packet name. The hash of the name is used not just to pick the
+ * bucket, but also as a surrogate for the actual key value.
+ *
+ * Client calls pass key/name as contiguous memory for lookup/add/delete but
+ * hashable stores its copy of the key/name as a list of one or more hash_key
+ * structs. - key memory is managed as a list of keys (cache line
+ * sized/aligned buffers). - If (keysize < 128) then use key struct's full
+ * 128 bytes - If not, first key struct is head of a linked list of elements
+ * where the first bytes are used for the key and the last 4 bytes are the
+ * index of the next entry (or an end marker). - key memory is generally the
+ * single largest use of memory in the hash table, especially for PIT, as
+ * names are bigger than node structs (which is also per name/entry).
+ *
+ */
+
+/* Compute hash node index from node pointer */
+#define NODE_IDX_FROM_NODE(p, h) \
+  (u32)((p) - ((h)->ht_nodes))
+
+#define HICN_HASH_KEY_BYTES   20
+
+typedef struct
+{
+  struct
+  {
+    u8 key[HICN_HASH_KEY_BYTES];
+  } ks;                                /* Entire key in one block */
+} hicn_hash_key_t;
+
+/*
+ * Ratio of extra key blocks to allocate, in case the embedded ones aren't
+ * sufficient. This is the fraction of the number of entries allocated.
+ */
+#define HICN_HASHTB_KEY_RATIO 8
+
+/*
+ * hash node, used to store a hash table entry; indexed by an entry in a
+ * bucket. the node contains an embedded key; long keys are stored as chains
+ * of keys.
+ *
+ * The memory block for a node includes space for client data, additional memory
+ * located off the end of the htnode data structure. Size of client-supplied
+ * data is fixed, so we can use vpp pools. The PIT and FIB need to ensure
+ * that they fit within the available data area, or change the size to
+ * accomodate their needs.
+ *
+ * NOTE: app_data_size currently applies to all apps, i.e. bigger FIB nodes
+ * means (leads to, requires) bigger PCS nodes
+ */
+
+/* Size this so that we can offer 64B aligned on 64-bits to the applications */
+/* New PIT entry syze 62B */
+#define HICN_HASH_NODE_APP_DATA_SIZE 4184      //to support 512 entry //96 //190 to support 50 faces
+
+/* How to align in the right way */
+typedef struct __attribute__ ((packed)) hicn_hash_node_s
+{
+  /* Bucket id containing the corresponding hash entry. */
+  u32 bucket_id;
+
+  /* Hash entry index in the bucket */
+  u32 entry_idx;
+
+  /* Total size of the key */
+  u16 hn_keysize;
+
+  /* 1 byte of flags for application use */
+  u8 hn_flags;
+
+  u8 _hn_reserved1;            /* TBD, to align what follows back to
+                                * 32 */
+
+  hicn_hash_key_t hn_key;      /* Key value embedded in the node, may chain
+                                * to more key buffers if necessary */
+
+  /* 32B + HICN_HASH_NODE_APP_DATA_SIZE */
+  /* Followed by app-specific data (fib or pit or cs entry, e.g.) */
+  u8 hn_data[HICN_HASH_NODE_APP_DATA_SIZE];
+
+} hicn_hash_node_t;
+
+#define HICN_HASH_NODE_FLAGS_DEFAULT     0x00
+#define HICN_HASH_NODE_CS_FLAGS          0x01
+#define HICN_HASH_NODE_OVERFLOW_BUCKET   0x02
+
+/*
+ * hicn_hash_entry_t Structure holding all or part of a hash value, a node
+ * index, and other key pieces of info.
+ *
+ * - 128 bytes/bucket with 19 bytes/entry gives 6 entries, or 5 entries plus
+ * next bucket ptr if overflow Changes in this structure will affect
+ * hicn_hash_bucket_t
+ */
+typedef struct __attribute__ ((packed)) hicn_hash_entry_s
+{
+
+  /* MSB of the hash value */
+  u64 he_msb64;
+
+  /* Index of node block */
+  u32 he_node;
+
+  /*
+   * Lock to prevent hash_node deletion while there are still interest
+   * or data referring to it
+   */
+  u32 locks;
+
+  /* A few flags, including 'this points to a chain of buckets' */
+  u8 he_flags;
+
+  /*
+   * Index of the virtual function table corresponding to the dpo_ctx
+   * strategy
+   */
+  u8 vft_id;
+
+  /* Index of dpo */
+  u8 dpo_ctx_id;
+
+} hicn_hash_entry_t;
+
+#define HICN_HASH_ENTRY_FLAGS_DEFAULT  0x00
+
+/* If entry is PIT this flag is 0 */
+#define HICN_HASH_ENTRY_FLAG_CS_ENTRY  0x01
+
+/*
+ * This entry heads a chain of overflow buckets (we expect to see this only
+ * in the last entry in a bucket.) In this case, the index is to an overflow
+ * bucket rather than to a single node block.
+ */
+#define HICN_HASH_ENTRY_FLAG_OVERFLOW  0x04
+
+/* This entry has been marked for deletion */
+#define HICN_HASH_ENTRY_FLAG_DELETED   0x08
+
+/* Use fast he_timeout units for expiration, slow if not */
+#define HICN_HASH_ENTRY_FLAG_FAST_TIMEOUT 0x10
+
+/*
+ * hash bucket: Contains an array of entries. Cache line sized/aligned, so no
+ * room for extra fields unless bucket size is increased to 2 cache lines or
+ * the entry struct shrinks.
+ */
+
+/*
+ * Overflow bucket ratio as a fraction of the fixed/configured count; a pool
+ * of hash buckets used if a row in the fixed table overflows.
+ */
+#define HICN_HASHTB_BUCKET_ENTRIES 6
+
+typedef struct __attribute__ ((packed))
+{
+  hicn_hash_entry_t hb_entries[HICN_HASHTB_BUCKET_ENTRIES];
+  u64 align1;
+  u32 align2;
+  u16 align3;
+} hicn_hash_bucket_t;
+
+/* Overall target fill-factor for the hashtable */
+#define HICN_HASHTB_FILL_FACTOR    4
+
+#define HICN_HASHTB_MIN_ENTRIES  (1 << 4)      // includes dummy node 0 entry
+#define HICN_HASHTB_MAX_ENTRIES  (1 << 24)
+
+#define HICN_HASHTB_MIN_BUCKETS (1 << 10)
+
+/*
+ * htab_t
+ *
+ * Hash table main structure.
+ *
+ * Contains - pointers to dynamically allocated arrays of cache-line
+ * sized/aligned structures (buckets, nodes, keys). Put frequently accessed
+ * fields in the first cache line.
+ */
+typedef struct hicn_hashtb_s
+{
+
+  /* 8B - main array of hash buckets */
+  hicn_hash_bucket_t *ht_buckets;
+
+  /* 8B - just-in-case block of overflow buckets */
+  hicn_hash_bucket_t *ht_overflow_buckets;
+
+  /* 8B - block of nodes associated with entries in buckets */
+  hicn_hash_node_t *ht_nodes;
+
+  /* Flags */
+  u32 ht_flags;
+
+  /* Count of buckets allocated in the main array */
+  u32 ht_bucket_count;
+
+  /* Count of overflow buckets allocated */
+  u32 ht_overflow_bucket_count;
+  u32 ht_overflow_buckets_used;
+
+  /* Count of nodes allocated */
+  u32 ht_node_count;
+  u32 ht_nodes_used;
+
+  /* Count of overflow key structs allocated */
+  u32 ht_key_count;
+  u32 ht_keys_used;
+
+} hicn_hashtb_t, *hicn_hashtb_h;
+
+/*
+ * Offset to aligned start of additional data (PIT/CS, FIB) embedded in each
+ * node.
+ */
+extern u32 ht_node_data_offset_aligned;
+
+/* Flags for hashtable */
+
+#define HICN_HASHTB_FLAGS_DEFAULT    0x00
+
+/*
+ * Don't use the last entry in each bucket - only use it for overflow. We use
+ * this for the FIB, currently, so that we can support in-place FIB changes
+ * that would be difficult if there were hash entry copies as part of
+ * overflow handling.
+ */
+#define HICN_HASHTB_FLAG_USE_SEVEN      0x04
+#define HICN_HASHTB_FLAG_KEY_FMT_PFX    0x08
+#define HICN_HASHTB_FLAG_KEY_FMT_NAME   0x10
+
+/*
+ * Max prefix name components we'll support in our incremental hashing;
+ * currently used only for LPM in the FIB.
+ */
+#define HICN_HASHTB_MAX_NAME_COMPS HICN_PARAM_FIB_ENTRY_PFX_COMPS_MAX
+
+/*
+ * APIs and inlines
+ */
+
+/* Compute hash node index from node pointer */
+static inline u32
+hicn_hashtb_node_idx_from_node (hicn_hashtb_h h, hicn_hash_node_t * p)
+{
+  return (p - h->ht_nodes);
+}
+
+/* Retrieve a hashtable node by node index */
+static inline hicn_hash_node_t *
+hicn_hashtb_node_from_idx (hicn_hashtb_h h, u32 idx)
+{
+  return (pool_elt_at_index (h->ht_nodes, idx));
+}
+
+/* Allocate a brand-new hashtable */
+int
+hicn_hashtb_alloc (hicn_hashtb_h * ph, u32 max_elems, size_t app_data_size);
+
+/* Free a hashtable, including its embedded arrays */
+int hicn_hashtb_free (hicn_hashtb_h * ph);
+
+/* Hash a bytestring, currently using bihash */
+u64 hicn_hashtb_hash_bytestring (const u8 * key, u32 keylen);
+
+always_inline hicn_hash_entry_t *
+hicn_hashtb_get_entry (hicn_hashtb_h h, u32 entry_idx, u32 bucket_id,
+                      u8 bucket_overflow)
+{
+  hicn_hash_bucket_t *bucket;
+  if (bucket_overflow)
+    bucket = pool_elt_at_index (h->ht_overflow_buckets, bucket_id);
+  else
+    bucket = (hicn_hash_bucket_t *) (h->ht_buckets + bucket_id);
+
+  return &(bucket->hb_entries[entry_idx]);
+}
+
+/* Hash a name, currently using bihash */
+always_inline u64
+hicn_hashtb_hash_name (const u8 * key, u16 keylen)
+{
+  if (key != NULL && keylen == HICN_V4_NAME_LEN)
+    {
+      clib_bihash_kv_8_8_t kv;
+      kv.key = ((u64 *) key)[0];
+      return clib_bihash_hash_8_8 (&kv);
+    }
+  else if (key != NULL && keylen == HICN_V6_NAME_LEN)
+    {
+      clib_bihash_kv_24_8_t kv;
+      kv.key[0] = ((u64 *) key)[0];
+      kv.key[1] = ((u64 *) key)[1];
+      kv.key[2] = ((u32 *) key)[4];
+      return clib_bihash_hash_24_8 (&kv);
+    }
+  else
+    {
+      return (-1LL);
+    }
+}
+
+
+/*
+ * Prepare a hashtable node for insertion, supplying the key and computed
+ * hash info. This sets up the node->key relationship, possibly allocating
+ * overflow key buffers.
+ */
+void
+hicn_hashtb_init_node (hicn_hashtb_h h, hicn_hash_node_t * node,
+                      const u8 * key, u32 keylen);
+
+/*
+ * Insert a node into the hashtable. We expect the caller has used the init
+ * api to set the node key and hash info, and populated the extra data area
+ * (if any) - or done the equivalent work itself.
+ */
+int
+hicn_hashtb_insert (hicn_hashtb_h h, hicn_hash_node_t * node,
+                   hicn_hash_entry_t ** hash_entry, u64 hash,
+                   u32 * node_id,
+                   u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                   u8 * hash_entry_id, u32 * bucket_id,
+                   u8 * bucket_is_overflow);
+
+/*
+ * Basic api to lookup a specific hash+key tuple. This does the entire lookup
+ * operation, retrieving node structs and comparing keys, so it's not
+ * optimized for prefetching or high performance.
+ *
+ * Returns zero and mails back a node on success, errno otherwise.
+ */
+int
+hicn_hashtb_lookup_node (hicn_hashtb_h h, const u8 * key,
+                        u32 keylen, u64 hashval, u8 is_data,
+                        u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                        u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                        u8 * bucket_is_overflow);
+
+/*
+ * Extended api to lookup a specific hash+key tuple. The implementation
+ * allows the caller to locate nodes that are marked for deletion; this is
+ * part of some hashtable applications, such as the FIB.
+ *
+ * This does the entire lookup operation, retrieving node structs and comparing
+ * keys, so it's not optimized for prefetching or high performance.
+ *
+ * Returns zero and mails back a node on success, errno otherwise.
+ */
+int
+hicn_hashtb_lookup_node_ex (hicn_hashtb_h h, const u8 * key,
+                           u32 keylen, u64 hashval, u8 is_data,
+                           int include_deleted_p, u32 * node_id,
+                           u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                           u8 * hash_entry_id, u32 * bucket_id,
+                           u8 * bucket_is_overflow);
+
+/**
+ * @brief Compares the key in the node with the given key
+ *
+ * This function allows to split the hash verification from the comparison of
+ * the entire key. Useful to exploit prefertching.
+ * @result 1 if equals, 0 otherwise
+ */
+int hicn_node_compare (const u8 * key, u32 keylen, hicn_hash_node_t * node);
+
+/*
+ * Remove a node from a hashtable using the node itself. The internal data
+ * structs are cleaned up, but the node struct itself is not: the caller must
+ * free the node itself.
+ */
+void hicn_hashtb_remove_node (hicn_hashtb_h h, hicn_hash_node_t * node,
+                             u64 hashval);
+
+/*
+ * Delete a node from a hashtable using the node itself, and delete/free the
+ * node.  Caller's pointer is cleared on success.
+ */
+void hicn_hashtb_delete (hicn_hashtb_h h, hicn_hash_node_t ** pnode,
+                        u64 hashval);
+
+/*
+ * Utility to init a new entry in a hashtable bucket/row. We use this to add
+ * new a node+hash, and to clear out an entry during removal.
+ */
+void
+hicn_hashtb_init_entry (hicn_hash_entry_t * entry,
+                       u32 nodeidx, u64 hashval, u32 locks);
+
+
+/*
+ * Return data area embedded in a hash node struct. We maintain an 'offset'
+ * value in case the common node body struct doesn't leave the data area
+ * aligned properly.
+ */
+static inline void *
+hicn_hashtb_node_data (hicn_hash_node_t * node)
+{
+  return ((u8 *) (node) + ht_node_data_offset_aligned);
+}
+
+/*
+ * Use some bits of the low half of the hash to locate a row/bucket in the
+ * table
+ */
+static inline u32
+hicn_hashtb_bucket_idx (hicn_hashtb_h h, u64 hashval)
+{
+  return ((u32) (hashval & (h->ht_bucket_count - 1)));
+}
+
+/*
+ * Return a hash node struct from the free list, or NULL. Note that the
+ * returned struct is _not_ cleared/zeroed - init is up to the caller.
+ */
+static inline hicn_hash_node_t *
+hicn_hashtb_alloc_node (hicn_hashtb_h h)
+{
+  hicn_hash_node_t *p = NULL;
+
+  if (h->ht_nodes_used < h->ht_node_count)
+    {
+      pool_get_aligned (h->ht_nodes, p, 8);
+      h->ht_nodes_used++;
+    }
+  return (p);
+}
+
+/*
+ * Release a hashtable node back to the free list when an entry is cleared
+ */
+void hicn_hashtb_free_node (hicn_hashtb_h h, hicn_hash_node_t * node);
+
+/*
+ * Walk a hashtable, iterating through the nodes, keeping context in 'ctx'
+ * between calls.
+ *
+ * Set the context value to HICN_HASH_WALK_CTX_INITIAL to start an iteration.
+ */
+int
+hicn_hashtb_next_node (hicn_hashtb_h h, hicn_hash_node_t ** pnode, u64 * ctx);
+
+
+int
+hicn_hashtb_key_to_str (hicn_hashtb_h h, const hicn_hash_node_t * node,
+                       char *buf, int bufsize, int must_fit);
+
+/*
+ * single hash full name can pass offset for two hashes calculation in case
+ * we use CS and PIT in a two steps hashes (prefix + seqno)
+ */
+always_inline int
+hicn_hashtb_fullhash (const u8 * name, u16 namelen, u64 * name_hash)
+{
+  *name_hash = hicn_hashtb_hash_name (name, namelen);
+  return (*name_hash != (-1LL) ? HICN_ERROR_NONE : HICN_ERROR_HASHTB_INVAL);
+}
+
+#endif /* // __HICN_HASHTB_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn.api b/hicn-plugin/src/hicn.api
new file mode 100755 (executable)
index 0000000..e7d7d33
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+define hicn_api_node_params_set
+{
+  /* 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 ICN forwarder in VPP */
+  u8 enable_disable;
+
+  /* PIT maximum size, otherwise -1 to assign default value */
+  i32 pit_max_size;
+
+  /* CS maximum size, otherwise -1 to assign default value */
+  i32 cs_max_size;
+
+  /* Portion of CS reserved to application, otherwise -1 to assign default value */
+  i32 cs_reserved_app;
+
+  /* Default PIT entry lifetime */
+  f64 pit_dflt_lifetime_sec;
+
+  /* Lower bound on PIT entry lifetime */
+  f64 pit_min_lifetime_sec;
+
+  /* Upper bound on PIT entry lifetime */
+  f64 pit_max_lifetime_sec;
+};
+
+define hicn_api_node_params_set_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_node_params_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+};
+
+define hicn_api_node_params_get_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+
+  /* Enabled / disabled flag */
+  u8 is_enabled;
+
+  /* compile-time plugin features */
+  u8 feature_cs;
+
+  /* Number of VPP workers */
+  u32 worker_count;
+
+  /* PIT maximum size, otherwise -1 to assign default value */
+  u32 pit_max_size;
+
+  /* CS maximum size, otherwise -1 to assign default value */
+  u32 cs_max_size;
+
+  /* Default PIT entry lifetime */
+  f64 pit_dflt_lifetime_sec;
+
+  /* Lower bound on PIT entry lifetime */
+  f64 pit_min_lifetime_sec;
+
+  /* Upper bound on PIT entry lifetime */
+  f64 pit_max_lifetime_sec;
+};
+
+define hicn_api_node_stats_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+};
+
+define hicn_api_node_stats_get_reply
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+
+  /* ICN packets processed */
+  u64 pkts_processed;
+
+  /* ICN interests forwarded */
+  u64 pkts_interest_count;
+
+  /* ICN data msgs forwarded */
+  u64 pkts_data_count;
+
+  /* ICN cached data msg replies */
+  u64 pkts_from_cache_count;
+
+  /* ICN no PIT entry drops */
+  u64 pkts_no_pit_count;
+
+  /* ICN expired PIT entries */
+  u64 pit_expired_count;
+
+  /* ICN expired CS entries */
+  u64 cs_expired_count;
+
+  /* ICN LRU CS entries freed */
+  u64 cs_lru_count;
+
+  /* ICN msgs dropped due to no packet buffers */
+  u64 pkts_drop_no_buf;
+
+  /* ICN Interest messages aggregated in PIT */
+  u64 interests_aggregated;
+
+  /* ICN Interest messages retransmitted */
+  u64 interests_retx;
+
+  /* ICN Interest messages colliding in hashtb */
+  u64 interests_hash_collision;
+
+  /* Number of entries in PIT at the present moment */
+  u64 pit_entries_count;
+
+  /* Number of entries in CS at the present moment */
+  u64 cs_entries_count;
+
+  /* Number of entries in CS at the present moment */
+  u64 cs_entries_ntw_count;
+};
+
+define hicn_api_face_ip_add
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* IP local address */
+  u64 nh_addr[2];
+
+  /* IPv4 local port number */
+  u32 swif;
+};
+
+define hicn_api_face_ip_add_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value: new Face ID, ~0 means no Face was created */
+  u32 faceid;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_face_ip_del
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* A Face ID to be deleted */
+  u16 faceid;
+};
+
+define hicn_api_face_ip_del_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_face_ip_params_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* A Face to be retrieved */
+  u16 faceid;
+};
+
+define hicn_api_face_ip_params_get_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+
+  /* IP local address */
+  u64 nh_addr[2];
+
+  /* VPP interface (index) associated with the face */
+  u32 swif;
+
+  /* Face flags */
+  u32 flags;
+};
+
+define hicn_api_route_nhops_add
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Prefix to be added to the FIB */
+  u64 prefix[2];
+
+  /* Length of the prefix */
+  u8 len;
+
+  /* A Face ID to the next hop forwarder for the specified prefix */
+  u32 face_ids[7];
+
+  /* Number of face to add */
+  u8 n_faces;
+};
+
+define hicn_api_route_nhops_add_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_route_del
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Prefix to be added to the FIB */
+  u64 prefix[2];
+
+  /* Length of the prefix */
+  u8 len;
+};
+
+define hicn_api_route_del_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_route_nhop_del
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Prefix to be added to the FIB */
+  u64 prefix[2];
+
+  /* Length of the prefix */
+  u8 len;
+
+  /* Specific next-hop to be removed */
+  u16 faceid;
+};
+
+define hicn_api_route_nhop_del_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_route_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Route prefix */
+  u64 prefix[2];
+
+  /* Prefix len */
+  u8 len;
+};
+
+define hicn_api_route_get_reply
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* List of faces pointing to the next hops */
+  u16 faceids[1000];
+
+  /* Strategy */
+  u32 strategy_id;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_strategies_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+};
+
+define hicn_api_strategies_get_reply
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Number of available strategies */
+  u8 n_strategies;
+
+  /* Strategies */
+  u32 strategy_id[256];
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_strategy_get
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Route prefix */
+  u32 strategy_id;
+};
+
+define hicn_api_strategy_get_reply
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Strategy description */
+  u8 description[200];
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_punting_add
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Prefix to match */
+  u64 prefix[2];
+
+  /* Subnet */
+  u8 len;
+
+  /* Interface id */
+  u32 swif;
+};
+
+define hicn_api_punting_add_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_punting_del
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u32 context;
+
+  /* Prefix to match */
+  u64 prefix[2];
+
+  /* Subnet */
+  u8 len;
+
+  /* Interface id */
+  u32 swif;
+};
+
+define hicn_api_punting_del_reply
+{
+  /* From the request */
+  u32 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+};
+
+define hicn_api_register_prod_app
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u64 context;
+
+  /* Prefix to match */
+  u64 prefix[2];
+
+  /* Subnet */
+  u8 len;
+
+  /* sw_if id */
+  u32 swif;
+
+  /* CS memory reserved -- in number of packets */
+  u32 cs_reserved;
+};
+
+define hicn_api_register_prod_app_reply
+{
+  /* From the request */
+  u64 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+
+  /* Actual CS memory reserved -- in number of packets */
+  u32 cs_reserved;
+
+  /* Prod address (ipv4 or ipv6) */
+  u64 prod_addr[2];
+
+  /* Return value: new Face ID, ~0 means no Face was created */
+  u32 faceid;
+};
+
+define hicn_api_register_cons_app
+{
+  /* Client identifier, set from api_main.my_client_index */
+  u32 client_index;
+
+  /* Arbitrary context, so client can match reply to request */
+  u64 context;
+
+  /* swif */
+  u32 swif;
+};
+
+define hicn_api_register_cons_app_reply
+{
+  /* From the request */
+  u64 context;
+
+  /* Return value, zero means all OK */
+  i32 retval;
+
+  /* Ip4 address */
+  u32 src_addr4;
+
+  /* Ip6 address */
+  u64 src_addr6[2];
+
+  /* Return value: new Face ID, ~0 means no Face was created */
+  u32 faceid;
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/hicn.c b/hicn-plugin/src/hicn.c
new file mode 100755 (executable)
index 0000000..a7b04de
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/vnet.h>
+#include <vnet/plugin/plugin.h>
+
+#include "hicn.h"
+#include "params.h"
+#include "infra.h"
+#include "strategy_dpo_manager.h"
+#include "mgmt.h"
+#include "punt.h"
+#include "error.h"
+#include "faces/app/address_mgr.h"
+#include "face_db.h"
+#include "faces/udp/face_udp.h"
+
+hicn_main_t hicn_main;
+/* Module vars */
+int hicn_infra_fwdr_initialized = 0;
+
+/*
+ * Global time counters we're trying out for opportunistic hashtable
+ * expiration.
+ */
+uint16_t hicn_infra_fast_timer;        /* Counts at 1 second intervals */
+uint16_t hicn_infra_slow_timer;        /* Counts at 1 minute intervals */
+
+hicn_face_bucket_t *hicn_face_bucket_pool;
+
+/*
+ * Init hicn forwarder with configurable PIT, CS sizes
+ */
+static int
+hicn_infra_fwdr_init (uint32_t shard_pit_size, uint32_t shard_cs_size,
+                     uint32_t cs_reserved)
+{
+  int ret = 0;
+
+  if (hicn_infra_fwdr_initialized)
+    {
+      ret = HICN_ERROR_FWD_ALREADY_ENABLED;
+      goto done;
+    }
+  /* Init per worker limits */
+  hicn_infra_pit_size = shard_pit_size;
+  hicn_infra_cs_size = shard_cs_size;
+
+  /* Init the global time-compression counters */
+  hicn_infra_fast_timer = 1;
+  hicn_infra_slow_timer = 1;
+
+  ret = hicn_pit_create (&hicn_main.pitcs, hicn_infra_pit_size);
+  hicn_pit_set_lru_max (&hicn_main.pitcs,
+                       hicn_infra_cs_size -
+                       (hicn_infra_cs_size * cs_reserved / 100));
+  hicn_pit_set_lru_app_max (&hicn_main.pitcs,
+                           hicn_infra_cs_size * cs_reserved / 100);
+
+done:
+  if ((ret == HICN_ERROR_NONE) && !hicn_infra_fwdr_initialized)
+    {
+      hicn_infra_fwdr_initialized = 1;
+    }
+  return (ret);
+}
+
+/*
+ * Action function shared between message handler and debug CLI NOTICE: we're
+ * only 'enabling' now
+ */
+int
+hicn_infra_plugin_enable_disable (int enable_disable,
+                                 int pit_size_req,
+                                 f64 pit_dflt_lifetime_sec_req,
+                                 f64 pit_min_lifetime_sec_req,
+                                 f64 pit_max_lifetime_sec_req,
+                                 int cs_size_req, int cs_reserved_app)
+{
+  int ret = 0;
+
+  hicn_main_t *sm = &hicn_main;
+  uint32_t pit_size, cs_size, cs_reserved;
+
+  /* Notice if we're already enabled... */
+  if (sm->is_enabled)
+    {
+      ret = HICN_ERROR_FWD_ALREADY_ENABLED;
+      goto done;
+    }
+  /* Set up params and call fwdr_init set up PIT/CS, forwarder nodes */
+
+  /* Check the range and assign some globals */
+  if (pit_min_lifetime_sec_req < 0)
+    {
+      sm->pit_lifetime_min_ms = HICN_PARAM_PIT_LIFETIME_DFLT_MIN_MS;
+    }
+  else
+    {
+      if (pit_min_lifetime_sec_req < HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC ||
+         pit_min_lifetime_sec_req > HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC)
+       {
+         ret = HICN_ERROR_PIT_CONFIG_MINLT_OOB;
+         goto done;
+       }
+      sm->pit_lifetime_min_ms = pit_min_lifetime_sec_req * SEC_MS;
+    }
+
+  if (pit_max_lifetime_sec_req < 0)
+    {
+      sm->pit_lifetime_max_ms = HICN_PARAM_PIT_LIFETIME_DFLT_MAX_MS;
+    }
+  else
+    {
+      if (pit_max_lifetime_sec_req < HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC ||
+         pit_max_lifetime_sec_req > HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC)
+       {
+         ret = HICN_ERROR_PIT_CONFIG_MAXLT_OOB;
+         goto done;
+       }
+      sm->pit_lifetime_max_ms = pit_max_lifetime_sec_req * SEC_MS;
+    }
+  if (sm->pit_lifetime_min_ms > sm->pit_lifetime_max_ms)
+    {
+      ret = HICN_ERROR_PIT_CONFIG_MINMAXLT;
+      goto done;
+    }
+  if (pit_dflt_lifetime_sec_req < 0)
+    {
+      sm->pit_lifetime_dflt_ms = HICN_PARAM_PIT_LIFETIME_DFLT_DFLT_MS;
+    }
+  else
+    {
+      sm->pit_lifetime_dflt_ms = pit_dflt_lifetime_sec_req * SEC_MS;
+    }
+  if (sm->pit_lifetime_dflt_ms < sm->pit_lifetime_min_ms ||
+      sm->pit_lifetime_dflt_ms > sm->pit_lifetime_max_ms)
+    {
+      ret = HICN_ERROR_PIT_CONFIG_DFTLT_OOB;
+      goto done;
+    }
+  if (pit_size_req < 0)
+    {
+      pit_size = HICN_PARAM_PIT_ENTRIES_DFLT;
+    }
+  else
+    {
+      if (pit_size_req < HICN_PARAM_PIT_ENTRIES_MIN ||
+         pit_size_req > HICN_PARAM_PIT_ENTRIES_MAX)
+       {
+         ret = HICN_ERROR_PIT_CONFIG_SIZE_OOB;
+         goto done;
+       }
+      pit_size = (uint32_t) pit_size_req;
+    }
+
+  if (cs_size_req < 0)
+    {
+      cs_size = HICN_PARAM_CS_ENTRIES_DFLT;
+    }
+  else
+    {
+      if (cs_size_req > HICN_PARAM_CS_ENTRIES_MAX)
+       {
+         ret = HICN_ERROR_CS_CONFIG_SIZE_OOB;
+         goto done;
+       }
+      cs_size = (uint32_t) cs_size_req;
+    }
+
+  if (cs_reserved_app < 0)
+    {
+      cs_reserved = HICN_PARAM_CS_RESERVED_APP;
+    }
+  else
+    {
+      if (cs_reserved_app >= 100)
+       ret = HICN_ERROR_CS_CONFIG_RESERVED_OOB;
+      cs_reserved = cs_reserved_app;
+    }
+
+  ret = hicn_infra_fwdr_init (pit_size, cs_size, cs_reserved);
+
+  hicn_face_db_init (pit_size);
+
+  if (ret != HICN_ERROR_NONE)
+    {
+      goto done;
+    }
+  sm->is_enabled = 1;
+
+  hicn_face_udp_init_internal ();
+
+done:
+
+  return (ret);
+}
+
+/*
+ * Init entry-point for the icn plugin
+ */
+static clib_error_t *
+hicn_init (vlib_main_t * vm)
+{
+  clib_error_t *error = 0;
+
+  hicn_main_t *sm = &hicn_main;
+
+  /* Init other elements in the 'main' struct */
+  sm->is_enabled = 0;
+
+  error = hicn_api_plugin_hookup (vm);
+
+  /* Init the hash table */
+  hicn_punt_init (vm);
+
+  /* Init the dpo module */
+  hicn_dpos_init ();
+
+  /* Init the app manager */
+  address_mgr_init ();
+
+  hicn_face_module_init (vm);
+
+  return error;
+}
+
+VLIB_INIT_FUNCTION (hicn_init);
+
+/* *INDENT-OFF* */
+VLIB_PLUGIN_REGISTER() =
+{
+       .description = "hICN forwarder"
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn.h b/hicn-plugin/src/hicn.h
new file mode 100755 (executable)
index 0000000..02a3dfa
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_H__
+#define __HICN_H__
+
+#include <hicn/hicn.h>
+
+#include <netinet/in.h>
+#include <vnet/ip/ip.h>
+#include <vnet/tcp/tcp_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/buffer.h>
+
+/* Helper for avoiding warnings about type-punning */
+#define UNION_CAST(x, destType) \
+   (((union {__typeof__(x) a; destType b;})x).b)
+
+/*
+ * Update CMakeLists.txt as we have to manually replace the type for
+ * vppapigen
+ */
+typedef u8 weight_t;
+
+#define ISV6(isv6, dov6, dov4) isv6 ? dov6 : dov4
+#define HICN_IS_NAMEHASH_CACHED(b) (((u64)(b->opaque2)[0] != 0) || ((u64)(b->opaque2)[1] != 0))
+
+#ifndef VLIB_BUFFER_MIN_CHAIN_SEG_SIZE
+#define VLIB_BUFFER_MIN_CHAIN_SEG_SIZE (128)
+#endif
+
+/* The following is stored in the opaque2 field in the vlib_buffer_t */
+typedef struct
+{
+  /* hash of the name */
+  u64 name_hash;
+
+  /* ids to prefetch a PIT/CS entry */
+  u32 node_id;
+  u32 bucket_id;
+  u8 hash_entry_id;
+  u8 hash_bucket_flags;
+
+  u8 is_appface;               /* 1 the incoming face is an
+                                * application face, 0 otherwise */
+  u8 dpo_ctx_id;               /* used for data path */
+  u8 vft_id;                   /* " */
+
+  dpo_id_t face_dpo_id;                /* ingress face ,sizeof(iface_dpo_id)
+                                * <= sizeof(u64) */
+
+  hicn_type_t type;
+} hicn_buffer_t;
+
+STATIC_ASSERT (sizeof (hicn_buffer_t) <=
+              STRUCT_SIZE_OF (vlib_buffer_t, opaque2),
+              "hICN buffer opaque2 meta-data too large for vlib_buffer");
+
+
+always_inline hicn_buffer_t *
+hicn_get_buffer (vlib_buffer_t * b0)
+{
+  return (hicn_buffer_t *) & (b0->opaque2[0]);
+}
+
+#endif /* __HICN_H__ */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn_all_api_h.h b/hicn-plugin/src/hicn_all_api_h.h
new file mode 100755 (executable)
index 0000000..1263ea4
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/hicn.api.h>
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn_api.c b/hicn-plugin/src/hicn_api.c
new file mode 100755 (executable)
index 0000000..8becde1
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/ip/format.h>
+#include <vnet/ip/ip4.h>
+#include <vnet/ip/ip6.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include "hicn.h"
+#include "faces/ip/face_ip.h"
+#include "infra.h"
+#include "parser.h"
+#include "mgmt.h"
+#include "strategy_dpo_manager.h"
+#include "strategy_dpo_ctx.h"
+#include "strategy.h"
+#include "pg.h"
+#include "error.h"
+#include "punt.h"
+#include "faces/app/face_prod.h"
+#include "faces/app/face_cons.h"
+#include "route.h"
+
+/* define message IDs */
+#include <hicn/hicn_msg_enum.h>
+
+/* define generated endian-swappers */
+#define vl_endianfun
+#include <hicn/hicn_all_api_h.h>
+#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 <hicn/hicn_all_api_h.h>
+#undef vl_printfun
+
+/* Get the API version number */
+#define vl_api_version(n, v) static u32 api_version=(v);
+#include <hicn/hicn_all_api_h.h>
+#undef vl_api_version
+
+#define REPLY_MSG_ID_BASE sm->msg_id_base
+#include <vlibapi/api_helper_macros.h>
+
+/****** List of message types that this plugin understands ******/
+
+#define foreach_hicn_plugin_api_msg                                 \
+  _(HICN_API_NODE_PARAMS_SET, hicn_api_node_params_set)             \
+  _(HICN_API_NODE_PARAMS_GET, hicn_api_node_params_get)             \
+  _(HICN_API_NODE_STATS_GET, hicn_api_node_stats_get)               \
+  _(HICN_API_FACE_IP_ADD, hicn_api_face_ip_add)                     \
+  _(HICN_API_FACE_IP_DEL, hicn_api_face_ip_del)                     \
+  _(HICN_API_FACE_IP_PARAMS_GET, hicn_api_face_ip_params_get)       \
+  _(HICN_API_ROUTE_GET, hicn_api_route_get)                         \
+  _(HICN_API_ROUTE_NHOPS_ADD, hicn_api_route_nhops_add)             \
+  _(HICN_API_ROUTE_DEL, hicn_api_route_del)                         \
+  _(HICN_API_ROUTE_NHOP_DEL, hicn_api_route_nhop_del)               \
+  _(HICN_API_STRATEGIES_GET, hicn_api_strategies_get)               \
+  _(HICN_API_STRATEGY_GET, hicn_api_strategy_get)                   \
+  _(HICN_API_PUNTING_ADD, hicn_api_punting_add)                     \
+  _(HICN_API_PUNTING_DEL, hicn_api_punting_del)                     \
+  _(HICN_API_REGISTER_PROD_APP, hicn_api_register_prod_app)         \
+  _(HICN_API_REGISTER_CONS_APP, hicn_api_register_cons_app)
+
+
+/****** SUPPORTING FUNCTION DECLARATIONS ******/
+
+/*
+ * Convert a unix return code to a vnet_api return code. Currently stubby:
+ * should have more cases.
+ */
+always_inline vnet_api_error_t
+hicn_face_api_entry_params_serialize (hicn_face_id_t faceid,
+                                     vl_api_hicn_api_face_ip_params_get_reply_t
+                                     * reply);
+
+
+/****************** API MESSAGE HANDLERS ******************/
+
+/****** NODE ******/
+
+static void
+vl_api_hicn_api_node_params_set_t_handler (vl_api_hicn_api_node_params_set_t *
+                                          mp)
+{
+  vl_api_hicn_api_node_params_set_reply_t *rmp;
+  int rv;
+
+  hicn_main_t *sm = &hicn_main;
+
+  int pit_max_size = clib_net_to_host_i32 (mp->pit_max_size);
+  f64 pit_dflt_lifetime_sec = mp->pit_dflt_lifetime_sec;
+  f64 pit_min_lifetime_sec = mp->pit_min_lifetime_sec;
+  f64 pit_max_lifetime_sec = mp->pit_max_lifetime_sec;
+  int cs_max_size = clib_net_to_host_i32 (mp->cs_max_size);
+  int cs_reserved_app = clib_net_to_host_i32 (mp->cs_reserved_app);
+
+  cs_reserved_app = cs_reserved_app >= 0
+    && cs_reserved_app < 100 ? cs_reserved_app : HICN_PARAM_CS_RESERVED_APP;
+
+  rv = hicn_infra_plugin_enable_disable ((int) (mp->enable_disable),
+                                        pit_max_size,
+                                        pit_dflt_lifetime_sec,
+                                        pit_min_lifetime_sec,
+                                        pit_max_lifetime_sec,
+                                        cs_max_size, cs_reserved_app);
+
+  REPLY_MACRO (VL_API_HICN_API_NODE_PARAMS_SET_REPLY /* , rmp, mp, rv */ );
+}
+
+static void
+vl_api_hicn_api_node_params_get_t_handler (vl_api_hicn_api_node_params_get_t *
+                                          mp)
+{
+  vl_api_hicn_api_node_params_get_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_NODE_PARAMS_GET_REPLY, (
+    {
+      rmp->is_enabled = sm->is_enabled;
+      rmp->feature_cs =        HICN_FEATURE_CS;
+      rmp->pit_max_size = clib_host_to_net_u32 (hicn_infra_pit_size);
+      rmp->pit_dflt_lifetime_sec = ((f64) sm->pit_lifetime_dflt_ms) / SEC_MS;
+      rmp->pit_min_lifetime_sec        = ((f64) sm->pit_lifetime_min_ms) / SEC_MS;
+      rmp->pit_max_lifetime_sec        = ((f64) sm->pit_lifetime_max_ms) / SEC_MS;
+      rmp->cs_max_size = clib_host_to_net_u32 (hicn_infra_cs_size);
+      rmp->retval = clib_host_to_net_i32 (rv);
+    }));
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_hicn_api_node_stats_get_t_handler (vl_api_hicn_api_node_stats_get_t *
+                                         mp)
+{
+  vl_api_hicn_api_node_stats_get_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_NODE_STATS_GET_REPLY, (
+    {
+      rv = hicn_mgmt_node_stats_get (rmp);
+      rmp->retval =clib_host_to_net_i32 (rv);
+    }));
+  /* *INDENT-ON* */
+}
+
+
+/****** FACE *******/
+
+static void
+vl_api_hicn_api_face_ip_add_t_handler (vl_api_hicn_api_face_ip_add_t * mp)
+{
+  vl_api_hicn_api_face_ip_add_reply_t *rmp;
+  int rv;
+
+  hicn_main_t *sm = &hicn_main;
+
+  hicn_face_id_t faceid = HICN_FACE_NULL;
+  ip46_address_t nh_addr;
+  nh_addr.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->nh_addr))[0]);
+  nh_addr.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->nh_addr))[1]);
+
+  u32 swif = clib_net_to_host_u32 (mp->swif);
+  rv = hicn_face_ip_add (&nh_addr, NULL, swif, &faceid);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_FACE_IP_ADD_REPLY /* , rmp, mp, rv */ ,(
+    {
+      rmp->faceid = clib_host_to_net_u16 ((u16) faceid);
+    }));
+  /* *INDENT-ON* */
+}
+
+static void
+vl_api_hicn_api_face_ip_del_t_handler (vl_api_hicn_api_face_ip_del_t * mp)
+{
+  vl_api_hicn_api_face_ip_del_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  hicn_face_id_t faceid = clib_net_to_host_u16 (mp->faceid);
+  rv = hicn_face_del (faceid);
+
+  REPLY_MACRO (VL_API_HICN_API_FACE_IP_DEL_REPLY /* , rmp, mp, rv */ );
+
+}
+
+static void
+  vl_api_hicn_api_face_ip_params_get_t_handler
+  (vl_api_hicn_api_face_ip_params_get_t * mp)
+{
+  vl_api_hicn_api_face_ip_params_get_reply_t *rmp;
+  int rv = 0;
+
+  hicn_main_t *sm = &hicn_main;
+
+  hicn_face_id_t faceid = clib_net_to_host_u16 (mp->faceid);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_FACE_IP_PARAMS_GET_REPLY, (
+    {
+      rv = hicn_face_api_entry_params_serialize(faceid, rmp);
+      rmp->retval = clib_host_to_net_u32(rv);
+    }));
+  /* *INDENT-ON* */
+}
+
+/****** ROUTE *******/
+
+static void
+vl_api_hicn_api_route_nhops_add_t_handler (vl_api_hicn_api_route_nhops_add_t
+                                          * mp)
+{
+  vl_api_hicn_api_route_nhops_add_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+  hicn_face_id_t face_ids[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+
+  hicn_main_t *sm = &hicn_main;
+
+  ip46_address_t prefix;
+  prefix.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+
+  u8 len = mp->len;
+  u8 n_faces = mp->n_faces;
+
+  for (int i = 0; i < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; i++)
+    {
+      face_ids[i] = clib_net_to_host_u16 (mp->face_ids[i]);
+    }
+
+  if ((face_ids == NULL) || (n_faces > HICN_PARAM_FIB_ENTRY_NHOPS_MAX))
+    {
+      rv = VNET_API_ERROR_INVALID_ARGUMENT;
+    }
+  if (rv == HICN_ERROR_NONE)
+    {
+      rv = hicn_route_add (face_ids, n_faces, &prefix, len);
+
+      if (rv == HICN_ERROR_ROUTE_ALREADY_EXISTS)
+       {
+         rv = hicn_route_add_nhops (face_ids, n_faces, &prefix, len);
+       }
+    }
+  REPLY_MACRO (VL_API_HICN_API_ROUTE_NHOPS_ADD_REPLY /* , rmp, mp, rv */ );
+}
+
+
+static void vl_api_hicn_api_route_del_t_handler
+  (vl_api_hicn_api_route_del_t * mp)
+{
+  vl_api_hicn_api_route_del_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  ip46_address_t prefix;
+  prefix.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+  u8 len = mp->len;
+
+  rv = hicn_route_del (&prefix, len);
+
+  REPLY_MACRO (VL_API_HICN_API_ROUTE_DEL_REPLY /* , rmp, mp, rv */ );
+}
+
+static void vl_api_hicn_api_route_nhop_del_t_handler
+  (vl_api_hicn_api_route_nhop_del_t * mp)
+{
+  vl_api_hicn_api_route_nhop_del_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  ip46_address_t prefix;
+  prefix.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+  u8 len = mp->len;
+  hicn_face_id_t faceid = clib_net_to_host_u32 (mp->faceid);
+
+
+  rv = hicn_route_del_nhop (&prefix, len, faceid);
+
+  REPLY_MACRO (VL_API_HICN_API_ROUTE_NHOP_DEL_REPLY /* , rmp, mp, rv */ );
+}
+
+static void vl_api_hicn_api_route_get_t_handler
+  (vl_api_hicn_api_route_get_t * mp)
+{
+  vl_api_hicn_api_route_get_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  ip46_address_t prefix;
+  prefix.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+  u8 len = mp->len;
+  const dpo_id_t *hicn_dpo_id;
+  const hicn_dpo_vft_t *hicn_dpo_vft;
+  hicn_dpo_ctx_t *hicn_dpo_ctx;
+  u32 fib_index;
+
+  rv = hicn_route_get_dpo (&prefix, len, &hicn_dpo_id, &fib_index);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_ROUTE_GET_REPLY, (
+    {
+      if (rv == HICN_ERROR_NONE)
+       {
+         hicn_dpo_vft = hicn_dpo_get_vft(hicn_dpo_id->dpoi_index);
+         hicn_dpo_ctx = hicn_dpo_vft->hicn_dpo_get_ctx(hicn_dpo_id->dpoi_index);
+         for (int i = 0; i < hicn_dpo_ctx->entry_count; i++)
+           {
+             if (dpo_id_is_valid(&hicn_dpo_ctx->next_hops[i]))
+               {
+                 rmp->faceids[i] =((dpo_id_t *) &hicn_dpo_ctx->next_hops[i])->dpoi_index;}
+           }
+         rmp->strategy_id = clib_host_to_net_u32(hicn_dpo_get_vft_id(hicn_dpo_id));}
+    }));
+  /* *INDENT-ON* */
+}
+
+static void vl_api_hicn_api_strategies_get_t_handler
+  (vl_api_hicn_api_strategies_get_t * mp)
+{
+  vl_api_hicn_api_strategies_get_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  int n_strategies = hicn_strategy_get_all_available ();
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_STRATEGIES_GET_REPLY/* , rmp, mp, rv */ ,(
+    {
+      int j = 0;
+      for (u32 i = 0; i < (u32) n_strategies; i++)
+       {
+         if (hicn_dpo_strategy_id_is_valid (i) == HICN_ERROR_NONE)
+           {
+             rmp->strategy_id[j] = clib_host_to_net_u32 (i); j++;}
+       }
+      rmp->n_strategies = n_strategies;
+    }));
+  /* *INDENT-ON* */
+}
+
+static void vl_api_hicn_api_strategy_get_t_handler
+  (vl_api_hicn_api_strategy_get_t * mp)
+{
+  vl_api_hicn_api_strategy_get_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  u32 strategy_id = clib_net_to_host_u32 (mp->strategy_id);
+  rv = hicn_dpo_strategy_id_is_valid (strategy_id);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_STRATEGY_GET_REPLY /* , rmp, mp, rv */ ,(
+    {
+      if (rv == HICN_ERROR_NONE)
+       {
+         const hicn_dpo_vft_t * hicn_dpo_vft =
+           hicn_dpo_get_vft (strategy_id);
+         hicn_dpo_vft->format_hicn_dpo (rmp->description, 0);}
+    }));
+  /* *INDENT-ON* */
+}
+
+/****** PUNTING *******/
+
+static void vl_api_hicn_api_punting_add_t_handler
+  (vl_api_hicn_api_punting_add_t * mp)
+{
+  vl_api_hicn_api_punting_add_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+  vlib_main_t *vm = vlib_get_main ();
+
+  hicn_main_t *sm = &hicn_main;
+
+  ip46_address_t prefix;
+  prefix.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+  u8 subnet_mask = mp->len;
+  u32 swif = clib_net_to_host_u32 (mp->swif);
+
+  rv =
+    hicn_punt_interest_data_for_ethernet (vm, &prefix, subnet_mask, swif, 0);
+
+  REPLY_MACRO (VL_API_HICN_API_PUNTING_ADD_REPLY /* , rmp, mp, rv */ );
+}
+
+static void vl_api_hicn_api_punting_del_t_handler
+  (vl_api_hicn_api_punting_del_t * mp)
+{
+  vl_api_hicn_api_punting_del_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  rv = HICN_ERROR_NONE;
+
+  REPLY_MACRO (VL_API_HICN_API_ROUTE_DEL_REPLY /* , rmp, mp, rv */ );
+}
+
+/************* APP FACE ****************/
+
+static void vl_api_hicn_api_register_prod_app_t_handler
+  (vl_api_hicn_api_register_prod_app_t * mp)
+{
+  vl_api_hicn_api_register_prod_app_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+
+  hicn_prefix_t prefix;
+  prefix.name.as_u64[0] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[0]);
+  prefix.name.as_u64[1] = clib_net_to_host_u64 (((u64 *) (&mp->prefix))[1]);
+  prefix.len = mp->len;
+  u32 swif = clib_net_to_host_u32 (mp->swif);
+  u32 cs_reserved = clib_net_to_host_u32 (mp->cs_reserved);
+  u32 faceid;
+
+  ip46_address_t prod_addr;
+  ip46_address_reset (&prod_addr);
+  rv = hicn_face_prod_add (&prefix, swif, &cs_reserved, &prod_addr, &faceid);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_REGISTER_PROD_APP_REPLY, (
+    {
+      rmp->prod_addr[0] = prod_addr.as_u64[0];
+      rmp->prod_addr[1] = prod_addr.as_u64[1];
+      rmp->cs_reserved = clib_net_to_host_u32(cs_reserved);
+      rmp->faceid = clib_net_to_host_u32(faceid);
+    }));
+  /* *INDENT-ON* */
+}
+
+static void vl_api_hicn_api_register_cons_app_t_handler
+  (vl_api_hicn_api_register_cons_app_t * mp)
+{
+  vl_api_hicn_api_register_cons_app_reply_t *rmp;
+  int rv = HICN_ERROR_NONE;
+
+  hicn_main_t *sm = &hicn_main;
+  ip4_address_t src_addr4;
+  ip6_address_t src_addr6;
+  src_addr4.as_u32 = (u32) 0;
+  src_addr6.as_u64[0] = (u64) 0;
+  src_addr6.as_u64[1] = (u64) 1;
+
+  u32 swif = clib_net_to_host_u32 (mp->swif);
+  u32 faceid;
+
+  rv = hicn_face_cons_add (&src_addr4, &src_addr6, swif, &faceid);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO2 (VL_API_HICN_API_REGISTER_CONS_APP_REPLY, (
+    {
+      rmp->src_addr4 = clib_net_to_host_u32(src_addr4.as_u32);
+      rmp->src_addr6[0] = clib_net_to_host_u64(src_addr6.as_u64[0]);
+      rmp->src_addr6[1] = clib_net_to_host_u64(src_addr6.as_u64[1]);
+      rmp->faceid = clib_net_to_host_u32(faceid);
+    }));
+  /* *INDENT-ON* */
+}
+
+/************************************************************************************/
+
+/* Set up the API message handling tables */
+clib_error_t *
+hicn_api_plugin_hookup (vlib_main_t * vm)
+{
+  hicn_main_t *sm = &hicn_main;
+
+  /* Get a correctly-sized block of API message decode slots */
+  u8 *name = format (0, "hicn_%08x%c", api_version, 0);
+  sm->msg_id_base = vl_msg_api_get_msg_ids ((char *) name,
+                                           VL_MSG_FIRST_AVAILABLE);
+  vec_free (name);
+
+#define _(N, n)                                                  \
+    vl_msg_api_set_handlers(sm->msg_id_base + VL_API_##N,       \
+                            #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_hicn_plugin_api_msg;
+#undef _
+
+  return 0;
+}
+
+
+
+
+
+
+
+/******************* SUPPORTING FUNCTIONS  *******************/
+
+/*
+ * Binary serialization for get face configuration API. for the moment
+ * assuming only ip faces here. To be completed with othet types of faces
+ */
+vnet_api_error_t
+hicn_face_api_entry_params_serialize (hicn_face_id_t faceid,
+                                     vl_api_hicn_api_face_ip_params_get_reply_t
+                                     * reply)
+{
+  int rv = HICN_ERROR_NONE;
+
+  if (!reply)
+    {
+      rv = VNET_API_ERROR_INVALID_ARGUMENT;
+      goto done;
+    }
+  hicn_face_t *face = hicn_dpoi_get_from_idx (faceid);
+
+  ip_adjacency_t *ip_adj = adj_get (face->shared.adj);
+
+  if (ip_adj != NULL)
+    {
+      reply->nh_addr[0] =
+       clib_host_to_net_u64 (ip_adj->sub_type.nbr.next_hop.as_u64[0]);
+      reply->nh_addr[1] =
+       clib_host_to_net_u64 (ip_adj->sub_type.nbr.next_hop.as_u64[1]);
+      reply->swif = clib_host_to_net_u32 (face->shared.sw_if);
+      reply->flags = clib_host_to_net_u32 (face->shared.flags);
+    }
+  else
+    rv = HICN_ERROR_FACE_IP_ADJ_NOT_FOUND;
+
+done:
+  return (rv);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn_api.h b/hicn-plugin/src/hicn_api.h
new file mode 100755 (executable)
index 0000000..79b561b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_API_H__
+#define __HICN_API_H__
+
+#define HICN_STRATEGY_NULL ~0
+
+/* define message structures */
+#define vl_typedefs
+#include <hicn/hicn_all_api_h.h>
+#undef vl_typedefs
+
+#endif /* // __HICN_API_H___ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/hicn_api_test.c b/hicn-plugin/src/hicn_api_test.c
new file mode 100755 (executable)
index 0000000..9d4519b
--- /dev/null
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2017-2019 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 <inttypes.h>
+
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/format.h>
+
+#define __plugin_msg_base hicn_test_main.msg_id_base
+#include <vlibapi/vat_helper_macros.h>
+
+
+#include <hicn/hicn_api.h>
+#include "error.h"
+
+// uword unformat_sw_if_index(unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include "hicn_msg_enum.h"
+
+/* declare message handlers for each api */
+
+#define vl_endianfun           /* define message structures */
+#include "hicn_all_api_h.h"
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...)
+#define vl_printfun
+#include "hicn_all_api_h.h"
+#undef vl_printfun
+
+/* Get the API version number. */
+#define vl_api_version(n, v) static u32 api_version=(v);
+#include "hicn_all_api_h.h"
+#undef vl_api_version
+
+/* SUPPORTING FUNCTIONS NOT LOADED BY VPP_API_TEST */
+uword
+unformat_ip46_address (unformat_input_t * input, va_list * args)
+{
+  ip46_address_t *ip46 = va_arg (*args, ip46_address_t *);
+  ip46_type_t type = va_arg (*args, ip46_type_t);
+  if ((type != IP46_TYPE_IP6) &&
+      unformat (input, "%U", unformat_ip4_address, &ip46->ip4))
+    {
+      ip46_address_mask_ip4 (ip46);
+      return 1;
+    }
+  else if ((type != IP46_TYPE_IP4) &&
+          unformat (input, "%U", unformat_ip6_address, &ip46->ip6))
+    {
+      return 1;
+    }
+  return 0;
+}
+
+/////////////////////////////////////////////////////
+
+#define HICN_FACE_NULL ~0
+
+typedef struct
+{
+  /* API message ID base */
+  u16 msg_id_base;
+  vat_main_t *vat_main;
+} hicn_test_main_t;
+
+hicn_test_main_t hicn_test_main;
+
+#define foreach_standard_reply_retval_handler            \
+_(hicn_api_node_params_set_reply)                        \
+_(hicn_api_face_ip_del_reply)                            \
+_(hicn_api_route_nhops_add_reply)                        \
+_(hicn_api_route_del_reply)                              \
+_(hicn_api_route_nhop_del_reply)
+
+#define _(n)                                            \
+    static void vl_api_##n##_t_handler                  \
+    (vl_api_##n##_t * mp)                               \
+    {                                                   \
+        vat_main_t * vam = hicn_test_main.vat_main;     \
+        i32 retval = ntohl(mp->retval);                 \
+        if (vam->async_mode) {                          \
+            vam->async_errors += (retval < 0);          \
+        } else {                                       \
+           fformat (vam->ofp,"%s\n", get_error_string(retval));\
+            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                                       \
+_(HICN_API_NODE_PARAMS_SET_REPLY, hicn_api_node_params_set_reply)       \
+_(HICN_API_NODE_PARAMS_GET_REPLY, hicn_api_node_params_get_reply)       \
+_(HICN_API_NODE_STATS_GET_REPLY, hicn_api_node_stats_get_reply)         \
+_(HICN_API_FACE_IP_DEL_REPLY, hicn_api_face_ip_del_reply)               \
+_(HICN_API_FACE_IP_ADD_REPLY, hicn_api_face_ip_add_reply)               \
+_(HICN_API_ROUTE_NHOPS_ADD_REPLY, hicn_api_route_nhops_add_reply)       \
+_(HICN_API_FACE_IP_PARAMS_GET_REPLY, hicn_api_face_ip_params_get_reply) \
+_(HICN_API_ROUTE_GET_REPLY, hicn_api_route_get_reply)                   \
+_(HICN_API_ROUTE_DEL_REPLY, hicn_api_route_del_reply)                   \
+_(HICN_API_ROUTE_NHOP_DEL_REPLY, hicn_api_route_nhop_del_reply)                    \
+_(HICN_API_STRATEGIES_GET_REPLY, hicn_api_strategies_get_reply)                    \
+_(HICN_API_STRATEGY_GET_REPLY, hicn_api_strategy_get_reply)             \
+_(HICN_API_REGISTER_PROD_APP_REPLY, hicn_api_register_prod_app_reply)   \
+_(HICN_API_REGISTER_CONS_APP_REPLY, hicn_api_register_cons_app_reply)
+
+
+static int
+api_hicn_api_node_params_set (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  int enable_disable = 1;
+  int pit_size = -1, cs_size = -1;
+  f64 pit_dflt_lifetime_sec = -1.0f;
+  f64 pit_min_lifetime_sec = -1.0f, pit_max_lifetime_sec = -1.0f;
+  int ret;
+
+  vl_api_hicn_api_node_params_set_t *mp;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "disable"))
+       {
+         enable_disable = 0;
+       }
+      else if (unformat (input, "PIT size %d", &pit_size))
+       {;
+       }
+      else if (unformat (input, "CS size %d", &cs_size))
+       {;
+       }
+      else if (unformat (input, "PIT dfltlife %f", &pit_dflt_lifetime_sec))
+       {;
+       }
+      else if (unformat (input, "PIT minlife %f", &pit_min_lifetime_sec))
+       {;
+       }
+      else if (unformat (input, "PIT maxlife %f", &pit_max_lifetime_sec))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Construct the API message */
+  M (HICN_API_NODE_PARAMS_SET, mp);
+  mp->enable_disable = enable_disable;
+  mp->pit_max_size = clib_host_to_net_i32 (pit_size);
+  mp->cs_max_size = clib_host_to_net_i32 (cs_size);
+  mp->pit_dflt_lifetime_sec = pit_dflt_lifetime_sec;
+  mp->pit_min_lifetime_sec = pit_min_lifetime_sec;
+  mp->pit_max_lifetime_sec = pit_max_lifetime_sec;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static int
+api_hicn_api_node_params_get (vat_main_t * vam)
+{
+  vl_api_hicn_api_node_params_get_t *mp;
+  int ret;
+
+  //Construct the API message
+  M (HICN_API_NODE_PARAMS_GET, mp);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_node_params_get_reply_t_handler
+  (vl_api_hicn_api_node_params_get_reply_t * mp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (mp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  fformat (vam->ofp,
+          "Enabled %d\n"
+          "  Features: cs:%d\n"
+          "  PIT size %d\n"
+          "  PIT lifetime dflt %.3f, min %.3f, max %.3f\n"
+          "  CS size %d\n",
+          mp->is_enabled,
+          mp->feature_cs,
+          clib_net_to_host_u32 (mp->pit_max_size),
+          mp->pit_dflt_lifetime_sec,
+          mp->pit_min_lifetime_sec,
+          mp->pit_max_lifetime_sec, clib_net_to_host_u32 (mp->cs_max_size));
+}
+
+static int
+api_hicn_api_node_stats_get (vat_main_t * vam)
+{
+  vl_api_hicn_api_node_stats_get_t *mp;
+  int ret;
+
+  /* Construct the API message */
+  M (HICN_API_NODE_STATS_GET, mp);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_node_stats_get_reply_t_handler
+  (vl_api_hicn_api_node_stats_get_reply_t * rmp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (rmp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  else
+    {
+      fformat (vam->ofp,       //compare hicn_cli_show_command_fn block:should match
+              "  PIT entries (now): %d\n"
+              "  CS entries (now): %d\n"
+              "  Forwarding statistics:"
+              "    pkts_processed: %d\n"
+              "    pkts_interest_count: %d\n"
+              "    pkts_data_count: %d\n"
+              "    pkts_nak_count: %d\n"
+              "    pkts_from_cache_count: %d\n"
+              "    pkts_nacked_interests_count: %d\n"
+              "    pkts_nak_hoplimit_count: %d\n"
+              "    pkts_nak_no_route_count: %d\n"
+              "    pkts_no_pit_count: %d\n"
+              "    pit_expired_count: %d\n"
+              "    cs_expired_count: %d\n"
+              "    cs_lru_count: %d\n"
+              "    pkts_drop_no_buf: %d\n"
+              "    interests_aggregated: %d\n"
+              "    interests_retransmitted: %d\n",
+              clib_net_to_host_u64 (rmp->pit_entries_count),
+              clib_net_to_host_u64 (rmp->cs_entries_count),
+              clib_net_to_host_u64 (rmp->pkts_processed),
+              clib_net_to_host_u64 (rmp->pkts_interest_count),
+              clib_net_to_host_u64 (rmp->pkts_data_count),
+              clib_net_to_host_u64 (rmp->pkts_from_cache_count),
+              clib_net_to_host_u64 (rmp->pkts_no_pit_count),
+              clib_net_to_host_u64 (rmp->pit_expired_count),
+              clib_net_to_host_u64 (rmp->cs_expired_count),
+              clib_net_to_host_u64 (rmp->cs_lru_count),
+              clib_net_to_host_u64 (rmp->pkts_drop_no_buf),
+              clib_net_to_host_u64 (rmp->interests_aggregated),
+              clib_net_to_host_u64 (rmp->interests_retx));
+    }
+}
+
+static int
+api_hicn_api_face_ip_add (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  ip46_address_t nh_addr;
+  vl_api_hicn_api_face_ip_add_t *mp;
+  int swif, ret;
+
+  /* Parse args required to build the message */
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "add %d %U",
+                   &swif, unformat_ip46_address, &nh_addr))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check for presence of both addresses */
+  if ((nh_addr.as_u64[0] == (u64) 0) && (nh_addr.as_u64[1] == (u64) 0))
+    {
+      clib_warning ("Next hop address not specified");
+      return (1);
+    }
+  /* Construct the API message */
+  M (HICN_API_FACE_IP_ADD, mp);
+  mp->nh_addr[0] = clib_host_to_net_u64 (nh_addr.as_u64[0]);
+  mp->nh_addr[1] = clib_host_to_net_u64 (nh_addr.as_u64[0]);
+  mp->swif = clib_host_to_net_u32 (swif);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_face_ip_add_reply_t_handler
+  (vl_api_hicn_api_face_ip_add_reply_t * rmp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (rmp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  fformat (vam->ofp, "New Face ID: %d\n", ntohl (rmp->faceid));
+}
+
+static int
+api_hicn_api_face_ip_del (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_face_ip_del_t *mp;
+  int faceid = 0, ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "face %d", &faceid))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  //Check for presence of face ID
+  if (faceid == 0)
+    {
+      clib_warning ("Please specify face ID");
+      return 1;
+    }
+  //Construct the API message
+  M (HICN_API_FACE_IP_DEL, mp);
+  mp->faceid = clib_host_to_net_i32 (faceid);
+
+  //send it...
+  S (mp);
+
+  //Wait for a reply...
+  W (ret);
+
+  return ret;
+}
+
+static int
+api_hicn_api_face_ip_params_get (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_face_ip_params_get_t *mp;
+  int faceid = 0, ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "face %d", &faceid))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  //Check for presence of face ID
+  if (faceid == 0)
+    {
+      clib_warning ("Please specify face ID");
+      return 1;
+    }
+  //Construct the API message
+  M (HICN_API_FACE_IP_PARAMS_GET, mp);
+  mp->faceid = clib_host_to_net_i32 (faceid);
+
+  //send it...
+  S (mp);
+
+  //Wait for a reply...
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_face_ip_params_get_reply_t_handler
+  (vl_api_hicn_api_face_ip_params_get_reply_t * rmp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (rmp->retval);
+  u8 *sbuf = 0;
+  u64 nh_addr[2];
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  vec_reset_length (sbuf);
+  nh_addr[0] = clib_net_to_host_u64 (rmp->nh_addr[0]);
+  nh_addr[1] = clib_net_to_host_u64 (rmp->nh_addr[1]);
+  sbuf =
+    format (sbuf, "%U", format_ip46_address, &nh_addr,
+           0 /* IP46_ANY_TYPE */ );
+
+  fformat (vam->ofp, "nh_addr %s swif %d flags %d\n",
+          sbuf,
+          clib_net_to_host_u16 (rmp->swif),
+          clib_net_to_host_i32 (rmp->flags));
+}
+
+static int
+api_hicn_api_route_get (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+
+  vl_api_hicn_api_route_get_t *mp;
+  ip46_address_t prefix;
+  u8 plen;
+  int ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "prefix %U/%d", unformat_ip46_address,
+                   &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check parse */
+  if (((prefix.as_u64[0] == 0) && (prefix.as_u64[1] == 0)) || (plen == 0))
+    {
+      clib_warning ("Please specify a valid prefix...");
+      return 1;
+    }
+  //Construct the API message
+  M (HICN_API_ROUTE_GET, mp);
+  mp->prefix[0] = clib_host_to_net_u64 (((u64 *) & prefix)[0]);
+  mp->prefix[1] = clib_host_to_net_u64 (((u64 *) & prefix)[1]);
+  mp->len = plen;
+
+  //send it...
+  S (mp);
+
+  //Wait for a reply...
+  W (ret);
+
+  return ret;
+}
+
+static void
+vl_api_hicn_api_route_get_reply_t_handler (vl_api_hicn_api_route_get_reply_t *
+                                          rmp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (rmp->retval);
+  u8 *sbuf = 0;
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  int i = 0;
+  u8 null_face = 0;
+  u32 faceid;
+
+  vec_reset_length (sbuf);
+  sbuf = format (sbuf, "Faces: \n");
+  while (i < 1000 && !null_face)
+    {
+      faceid = clib_net_to_host_u32 (rmp->faceids[i]);
+      if (faceid != HICN_FACE_NULL)
+       {
+         sbuf =
+           format (sbuf, "faceid %d",
+                   clib_net_to_host_u32 (rmp->faceids[i]));
+         i++;
+       }
+      else
+       {
+         null_face = 1;
+       }
+    }
+
+  fformat (vam->ofp, "%s\n Strategy: %d",
+          sbuf, clib_net_to_host_u32 (rmp->strategy_id));
+}
+
+static int
+api_hicn_api_route_nhops_add (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_route_nhops_add_t *mp;
+
+  ip46_address_t prefix;
+  u8 plen;
+  u32 faceid = 0;
+  int ret;
+
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "add prefix %U/%d", unformat_ip46_address,
+                   &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else if (unformat (input, "face %d", &faceid))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check parse */
+  if (((prefix.as_u64[0] == 0) && (prefix.as_u64[1] == 0)) || (plen == 0)
+      || (faceid == 0))
+    {
+      clib_warning ("Please specify prefix and faceid...");
+      return 1;
+    }
+  /* Construct the API message */
+  M (HICN_API_ROUTE_NHOPS_ADD, mp);
+  mp->prefix[0] = clib_host_to_net_u64 (((u64 *) & prefix)[0]);
+  mp->prefix[1] = clib_host_to_net_u64 (((u64 *) & prefix)[1]);
+  mp->len = plen;
+
+  mp->face_ids[0] = clib_host_to_net_u32 (faceid);
+  mp->n_faces = 1;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static int
+api_hicn_api_route_del (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_route_del_t *mp;
+
+  ip46_address_t prefix;
+  u8 plen;
+  int ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "prefix %U/%d", unformat_ip46_address,
+                   &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check parse */
+  if (((prefix.as_u64[0] == 0) && (prefix.as_u64[1] == 0)) || (plen == 0))
+    {
+      clib_warning ("Please specify prefix...");
+      return 1;
+    }
+  /* Construct the API message */
+  M (HICN_API_ROUTE_DEL, mp);
+  mp->prefix[0] = clib_host_to_net_u64 (((u64 *) & prefix)[0]);
+  mp->prefix[1] = clib_host_to_net_u64 (((u64 *) & prefix)[1]);
+  mp->len = plen;
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+
+}
+
+static int
+api_hicn_api_route_nhop_del (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_route_nhop_del_t *mp;
+
+  ip46_address_t prefix;
+  u8 plen;
+  int faceid = 0, ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "del prefix %U/%d", unformat_ip46_address,
+                   &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else if (unformat (input, "face %d", &faceid))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check parse */
+  if (((prefix.as_u64[0] == 0) && (prefix.as_u64[1] == 0)) || (plen == 0)
+      || (faceid == HICN_FACE_NULL))
+    {
+      clib_warning ("Please specify prefix and faceid...");
+      return 1;
+    }
+  /* Construct the API message */
+  M (HICN_API_ROUTE_NHOP_DEL, mp);
+  mp->prefix[0] = clib_host_to_net_u64 (((u64 *) & prefix)[0]);
+  mp->prefix[1] = clib_host_to_net_u64 (((u64 *) & prefix)[1]);
+  mp->len = plen;
+
+  mp->faceid = clib_host_to_net_u32 (faceid);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static int
+api_hicn_api_strategies_get (vat_main_t * vam)
+{
+  vl_api_hicn_api_strategies_get_t *mp;
+  int ret;
+
+  //TODO
+  /* Construct the API message */
+  M (HICN_API_STRATEGIES_GET, mp);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_strategies_get_reply_t_handler
+  (vl_api_hicn_api_strategies_get_reply_t * mp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (mp->retval);
+  u8 *sbuf = 0;
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  int n_strategies = clib_net_to_host_i32 (mp->n_strategies);
+
+  vec_reset_length (sbuf);
+  sbuf = format (sbuf, "Available strategies:\n");
+
+  int i;
+  for (i = 0; i < n_strategies; i++)
+    {
+      u32 strategy_id = clib_net_to_host_u32 (mp->strategy_id[i]);
+      sbuf = format (sbuf, "%d ", strategy_id);
+    }
+  fformat (vam->ofp, "%s", sbuf);
+}
+
+static int
+api_hicn_api_strategy_get (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_strategy_get_t *mp;
+  int ret;
+
+  u32 strategy_id = HICN_STRATEGY_NULL;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "strategy %d", strategy_id))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  if (strategy_id == HICN_STRATEGY_NULL)
+    {
+      clib_warning ("Please specify strategy id...");
+      return 1;
+    }
+
+  /* Construct the API message */
+  M (HICN_API_STRATEGY_GET, mp);
+  mp->strategy_id = clib_host_to_net_u32 (strategy_id);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_strategy_get_reply_t_handler
+  (vl_api_hicn_api_strategy_get_reply_t * mp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (mp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  fformat (vam->ofp, "%s", mp->description);
+}
+
+static int
+api_hicn_api_register_prod_app (vat_main_t * vam)
+{
+  unformat_input_t *input = vam->input;
+  vl_api_hicn_api_register_prod_app_t *mp;
+  ip46_address_t prefix;
+  int plen;
+  u32 swif = ~0;
+  int ret;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "prefix %U/%d", unformat_ip46_address,
+                   &prefix, IP46_TYPE_ANY, &plen))
+       {;
+       }
+      else if (unformat (input, "id %d", &swif))
+       {;
+       }
+      else
+       {
+         break;
+       }
+    }
+
+  /* Check parse */
+  if (((prefix.as_u64[0] == 0) && (prefix.as_u64[1] == 0)) || (plen == 0))
+    {
+      clib_warning ("Please specify prefix...");
+      return 1;
+    }
+  /* Construct the API message */
+  M (HICN_API_REGISTER_PROD_APP, mp);
+  mp->prefix[0] = clib_host_to_net_u64 (prefix.as_u64[0]);
+  mp->prefix[1] = clib_host_to_net_u64 (prefix.as_u64[1]);
+  mp->len = (u8) plen;
+
+  mp->swif = clib_host_to_net_u32 (swif);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_register_prod_app_reply_t_handler
+  (vl_api_hicn_api_register_prod_app_reply_t * mp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (mp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+}
+
+static int
+api_hicn_api_register_cons_app (vat_main_t * vam)
+{
+  vl_api_hicn_api_register_cons_app_t *mp;
+  int ret;
+
+  /* Construct the API message */
+  M (HICN_API_REGISTER_CONS_APP, mp);
+
+  /* send it... */
+  S (mp);
+
+  /* Wait for a reply... */
+  W (ret);
+
+  return ret;
+}
+
+static void
+  vl_api_hicn_api_register_cons_app_reply_t_handler
+  (vl_api_hicn_api_register_cons_app_reply_t * mp)
+{
+  vat_main_t *vam = hicn_test_main.vat_main;
+  i32 retval = ntohl (mp->retval);
+
+  if (vam->async_mode)
+    {
+      vam->async_errors += (retval < 0);
+      return;
+    }
+  vam->retval = retval;
+  vam->result_ready = 1;
+
+  if (vam->retval < 0)
+    {
+      //vpp_api_test infra will also print out string form of error
+      fformat (vam->ofp, "   (API call error: %d)\n", vam->retval);
+      return;
+    }
+  ip4_address_t src_addr4;
+  src_addr4.as_u32 = clib_net_to_host_u32 (mp->src_addr4);
+  ip6_address_t src_addr6;
+  src_addr6.as_u64[0] = clib_net_to_host_u64 (mp->src_addr6[0]);
+  src_addr6.as_u64[1] = clib_net_to_host_u64 (mp->src_addr6[1]);
+
+  fformat (vam->ofp,
+          "ip4 address %U\n"
+          "ip6 address :%U\n"
+          "appif id :%d\n",
+          format_ip4_address, &src_addr4, format_ip6_address, &src_addr6);
+}
+
+/*
+ * List of messages that the api test plugin sends, and that the data plane
+ * plugin processes
+ */
+#define foreach_vpe_api_msg                                             \
+_(hicn_api_node_params_set, "PIT size <sz> CS size <sz>"                \
+  "PIT minlimit <f> PIT maxlimit <f> [disable] ")                       \
+_(hicn_api_node_params_get, "")                                         \
+_(hicn_api_node_stats_get, "")                                          \
+_(hicn_api_face_ip_del, "face <faceID>")                                \
+_(hicn_api_face_ip_add, "add <swif> <address>")                         \
+_(hicn_api_route_nhops_add, "add prefix <IP4/IP6>/<subnet> face <faceID> weight <weight>") \
+_(hicn_api_face_ip_params_get, "face <faceID>")                         \
+_(hicn_api_route_get, "prefix <IP4/IP6>/<subnet>")                      \
+_(hicn_api_route_del, "prefix <IP4/IP6>/<subnet>")                      \
+_(hicn_api_route_nhop_del, "del prefix <IP4/IP6>/<subnet> face <faceID>") \
+_(hicn_api_strategies_get, "")                                          \
+_(hicn_api_strategy_get, "strategy <id>")                               \
+_(hicn_api_register_prod_app, "prefix <IP4/IP6>/<subnet> id <appif_id>") \
+_(hicn_api_register_cons_app, "")
+
+void
+hicn_vat_api_hookup (vat_main_t * vam)
+{
+  hicn_test_main_t *sm = &hicn_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)
+{
+  hicn_test_main_t *sm = &hicn_test_main;
+  u8 *name;
+
+  sm->vat_main = vam;
+
+  /* Ask the vpp engine for the first assigned message-id */
+  name = format (0, "hicn_%08x%c", api_version, 0);
+  sm->msg_id_base = vl_client_get_first_plugin_msg_id ((char *) name);
+
+  if (sm->msg_id_base != (u16) ~ 0)
+    hicn_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/hicn-plugin/src/hicn_msg_enum.h b/hicn-plugin/src/hicn_msg_enum.h
new file mode 100755 (executable)
index 0000000..291e622
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_MSG_ENUM_H__
+#define __HICN_MSG_ENUM_H__
+
+#include <vppinfra/byte_order.h>
+
+#define vl_msg_id(n, h) n,
+typedef enum
+{
+#include <hicn/hicn_all_api_h.h>
+  /* We'll want to know how many messages IDs we need... */
+  VL_MSG_FIRST_AVAILABLE,
+} vl_msg_id_t;
+#undef vl_msg_id
+
+#endif /* __HICN_MSG_ENUM_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/infra.h b/hicn-plugin/src/infra.h
new file mode 100755 (executable)
index 0000000..a9744fe
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_INFRA_H__
+#define __HICN_INFRA_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "pcs.h"
+
+/**
+ * hICN plugin global state: see also
+ * - fib and pits
+ */
+typedef struct hicn_main_s
+{
+  /* Binary API message ID base */
+  u16 msg_id_base;
+
+  /* Have we been enabled */
+  u16 is_enabled;
+
+  /* Forwarder PIT/CS */
+  hicn_pit_cs_t pitcs;
+
+  /* Global PIT lifetime info */
+  /*
+   * Default PIT entry timeout to use in case an interest does not
+   * contain a valid interest lifetime
+   */
+  u64 pit_lifetime_dflt_ms;
+  /*
+   * Boundarier for the interest lifetime. If outside,
+   * pit_lifetime_dflt_ms is used in the PIT
+   */
+  u64 pit_lifetime_min_ms;
+  u64 pit_lifetime_max_ms;
+
+} hicn_main_t;
+
+extern hicn_main_t hicn_main;
+
+extern int hicn_infra_fwdr_initialized;
+
+/* PIT and CS size */
+u32 hicn_infra_pit_size;
+u32 hicn_infra_cs_size;
+
+/**
+ * @brief Enable and disable the hicn plugin
+ *
+ * Enable the time the hICN plugin and set the forwarder parameters.
+ * @param enable_disable 1 if to enable, 0 otherwisw (currently only enable is supported)
+ * @param pit_max_size Max size of the PIT
+ * @param pit_dflt_lifetime_sec_req Default PIT entry timeout to use in case an interest does not contain a valid interest lifetime
+ * @param pit_min_lifetime_sec_req Minimum timeout allowed for a PIT entry lifetime
+ * @param pit_max_lifetime_sec_req Maximum timeout allowed for a PIT entry lifetime
+ * @param cs_max_size CS size. Must be <= than pit_max_size
+ * @param cs_reserved_app Amount of CS reserved for application faces
+ */
+int
+hicn_infra_plugin_enable_disable (int enable_disable,
+                                 int pit_max_size,
+                                 f64 pit_dflt_lifetime_sec_req,
+                                 f64 pit_min_lifetime_sec_req,
+                                 f64 pit_max_lifetime_sec_req,
+                                 int cs_max_size, int cs_reserved_app);
+
+
+/* vlib nodes that compose the hICN forwarder */
+extern vlib_node_registration_t hicn_interest_pcslookup_node;
+extern vlib_node_registration_t hicn_data_pcslookup_node;
+extern vlib_node_registration_t hicn_data_fwd_node;
+extern vlib_node_registration_t hicn_data_store_node;
+extern vlib_node_registration_t hicn_interest_hitpit_node;
+extern vlib_node_registration_t hicn_interest_hitcs_node;
+extern vlib_node_registration_t hicn_pg_interest_node;
+extern vlib_node_registration_t hicn_pg_data_node;
+extern vlib_node_registration_t hicn_pg_server_node;
+
+
+#endif /* // __HICN_INFRA_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_hitcs.h b/hicn-plugin/src/interest_hitcs.h
new file mode 100755 (executable)
index 0000000..82b0ace
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_INTEREST_HITCS_H__
+#define __HICN_INTEREST_HITCS_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "pcs.h"
+
+/*
+ * Node context data; we think this is per-thread/instance
+ */
+typedef struct hicn_interest_hitcs_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_interest_hitcs_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_interest_hitcs_trace_t;
+
+typedef enum
+{
+  HICN_INTEREST_HITCS_NEXT_V4_LOOKUP,
+  HICN_INTEREST_HITCS_NEXT_V6_LOOKUP,
+  HICN_INTEREST_HITCS_NEXT_ERROR_DROP,
+  HICN_INTEREST_HITCS_N_NEXT,
+} hicn_interest_hitcs_next_t;
+
+#endif /* // __HICN_INTEREST_HITCS_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_hitcs_node.c b/hicn-plugin/src/interest_hitcs_node.c
new file mode 100755 (executable)
index 0000000..f9c8c48
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+#include <vppinfra/string.h>
+
+#include "interest_hitcs.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "data_fwd.h"
+#include "infra.h"
+#include "state.h"
+#include "error.h"
+
+/* packet trace format function */
+static u8 *hicn_interest_hitcs_format_trace (u8 * s, va_list * args);
+
+
+/* Stats string values */
+static char *hicn_interest_hitcs_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+vlib_node_registration_t hicn_interest_hitcs_node;
+
+always_inline void drop_packet (u32 * next0);
+
+always_inline void
+clone_from_cs (vlib_main_t * vm, u32 * bi0_cs, vlib_buffer_t * dest)
+{
+  /* Retrieve the buffer to clone */
+  vlib_buffer_t *cs_buf = vlib_get_buffer (vm, *bi0_cs);
+
+  if (cs_buf->current_data >= VLIB_BUFFER_MIN_CHAIN_SEG_SIZE
+      && ((i16) cs_buf->current_length) < (i16) 0)
+    {
+      vlib_buffer_advance (cs_buf,
+                          -(((i16) cs_buf->current_length) +
+                            VLIB_BUFFER_MIN_CHAIN_SEG_SIZE));
+
+      clib_memcpy (vlib_buffer_get_current (dest),
+                  vlib_buffer_get_current (cs_buf), cs_buf->current_length);
+      clib_memcpy (dest->opaque2, cs_buf->opaque2, sizeof (cs_buf->opaque2));
+      dest->current_data = cs_buf->current_data;
+      dest->current_length = cs_buf->current_length;
+      dest->total_length_not_including_first_buffer = 0;
+      cs_buf->current_data += VLIB_BUFFER_MIN_CHAIN_SEG_SIZE;
+      cs_buf->current_length -= VLIB_BUFFER_MIN_CHAIN_SEG_SIZE;
+    }
+  else
+    {
+      vlib_buffer_advance (cs_buf, -VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+
+      if (PREDICT_FALSE (cs_buf->n_add_refs == 255))
+       {
+         vlib_buffer_t *cs_buf2 = vlib_buffer_copy (vm, cs_buf);
+         vlib_buffer_advance (cs_buf, VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+         cs_buf = cs_buf2;
+       }
+
+      clib_memcpy (vlib_buffer_get_current (dest),
+                  vlib_buffer_get_current (cs_buf),
+                  VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+      dest->current_length = VLIB_BUFFER_MIN_CHAIN_SEG_SIZE;
+      vlib_buffer_advance (cs_buf, VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
+      vlib_buffer_attach_clone (vm, dest, cs_buf);
+    }
+}
+
+/*
+ * ICN forwarder node for interests: handling of Interests delivered based on
+ * ACL. - 1 packet at a time - ipv4/tcp ipv6/tcp
+ */
+static uword
+hicn_interest_hitcs_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                            vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicn_interest_hitcs_next_t next_index;
+  hicn_interest_hitcs_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  f64 tnow;
+  int ret;
+
+  rt = vlib_node_get_runtime_data (vm, hicn_interest_hitcs_node.index);
+
+  if (PREDICT_FALSE (rt->pitcs == NULL))
+    {
+      rt->pitcs = &hicn_main.pitcs;
+    }
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  /* Capture time in vpp terms */
+  tnow = vlib_time_now (vm);
+  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 > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         u32 bi0;
+         u32 next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         hicn_buffer_t *hicnb0;
+         hicn_hash_node_t *node0;
+         hicn_pcs_entry_t *pitp;
+         hicn_hash_entry_t *hash_entry0;
+         const hicn_strategy_vft_t *strategy_vft0;
+         const hicn_dpo_vft_t *dpo_vft0;
+         u8 dpo_ctx_id0;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE);
+           }
+
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         /* Get hicn buffer and state */
+         hicnb0 = hicn_get_buffer (b0);
+         hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0,
+                                  &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
+
+         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         nameptr = (u8 *) (&name);
+         pitp = hicn_pit_get_data (node0);
+
+         dpo_id_t hicn_dpo_id0 =
+           { dpo_vft0->hicn_dpo_get_type (), 0, 0, dpo_ctx_id0 };
+
+         if (PREDICT_FALSE
+             (ret != HICN_ERROR_NONE ||
+              !hicn_node_compare (nameptr, namelen, node0)))
+           {
+             /* Remove lock from the entry */
+             hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0,
+                                   dpo_vft0, &hicn_dpo_id0);
+             drop_packet (&next0);
+             goto end_processing;
+           }
+         if ((tnow > pitp->shared.expire_time))
+           {
+             /* Delete and clean up expired CS entry */
+             hicn_pcs_delete (rt->pitcs, &pitp, &node0, vm, hash_entry0,
+                              dpo_vft0, &hicn_dpo_id0);
+             stats.cs_expired_count++;
+             /* Forward interest to the strategy node */
+             next0 =
+               isv6 ? HICN_INTEREST_HITCS_NEXT_V6_LOOKUP :
+               HICN_INTEREST_HITCS_NEXT_V4_LOOKUP;
+           }
+         else
+           {
+             if (PREDICT_TRUE
+                 (!(hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_DELETED)))
+               hicn_pcs_cs_update (vm, rt->pitcs, pitp, node0);
+
+             /*
+              * Retrieve the incoming iface and forward
+              * the data through it
+              */
+             ASSERT (hicnb0->face_dpo_id.dpoi_index <
+                     HICN_PARAM_PIT_ENTRY_PHOPS_MAX);
+             next0 = hicnb0->face_dpo_id.dpoi_next_node;
+             vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
+               hicnb0->face_dpo_id.dpoi_index;
+
+             clone_from_cs (vm, &pitp->u.cs.cs_pkt_buf, b0);
+
+             stats.pkts_from_cache_count++;
+             stats.pkts_data_count++;
+             /* Remove lock from the entry */
+             hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0,
+                                   dpo_vft0, &hicn_dpo_id0);
+           }
+
+       end_processing:
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_interest_hitcs_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+           }
+         /* Incr packet counter */
+         stats.pkts_processed += 1;
+
+         /*
+          * 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);
+    }
+
+  u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs);
+
+  vlib_node_increment_counter (vm, hicn_interest_hitcs_node.index,
+                              HICNFWD_ERROR_CACHED,
+                              stats.pkts_from_cache_count);
+
+  vlib_node_increment_counter (vm, hicn_interest_hitcs_node.index,
+                              HICNFWD_ERROR_DATAS, stats.pkts_data_count);
+
+  update_node_counter (vm, hicn_interest_hitcs_node.index,
+                      HICNFWD_ERROR_INT_COUNT, pit_int_count);
+
+  return (frame->n_vectors);
+}
+
+always_inline void
+drop_packet (u32 * next0)
+{
+  *next0 = HICN_INTEREST_HITCS_NEXT_ERROR_DROP;
+}
+
+/* packet trace format function */
+static u8 *
+hicn_interest_hitcs_format_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 *);
+  hicn_interest_hitcs_trace_t *t =
+    va_arg (*args, hicn_interest_hitcs_trace_t *);
+
+  s = format (s, "INTEREST-HITCS: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_interest_hitcs_node) =
+{
+  .function = hicn_interest_hitcs_node_fn,
+  .name = "hicn-interest-hitcs",
+  .vector_size = sizeof(u32),
+  .runtime_data_bytes = sizeof(hicn_interest_hitcs_runtime_t),
+  .format_trace = hicn_interest_hitcs_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_interest_hitcs_error_strings),
+  .error_strings = hicn_interest_hitcs_error_strings,
+  .n_next_nodes = HICN_INTEREST_HITCS_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_INTEREST_HITCS_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICN_INTEREST_HITCS_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICN_INTEREST_HITCS_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_hitpit.h b/hicn-plugin/src/interest_hitpit.h
new file mode 100755 (executable)
index 0000000..28427d3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_INTEREST_HITPIT_H__
+#define __HICN_INTEREST_HITPIT_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "pcs.h"
+
+/*
+ * Node context data; we think this is per-thread/instance
+ */
+typedef struct hicn_interest_hitpit_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_interest_hitpit_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_interest_hitpit_trace_t;
+
+typedef enum
+{
+  HICN_INTEREST_HITPIT_NEXT_INTEREST_HITCS,
+  HICN_INTEREST_HITPIT_NEXT_IP4_LOOKUP,
+  HICN_INTEREST_HITPIT_NEXT_IP6_LOOKUP,
+  HICN_INTEREST_HITPIT_NEXT_ERROR_DROP,
+  HICN_INTEREST_HITPIT_N_NEXT,
+} hicn_interest_hitpit_next_t;
+
+#endif /* // __HICN_INTEREST_HITPIT_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_hitpit_node.c b/hicn-plugin/src/interest_hitpit_node.c
new file mode 100755 (executable)
index 0000000..21ba97d
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+
+#include "interest_hitpit.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "data_fwd.h"
+#include "infra.h"
+#include "strategy.h"
+#include "strategy_dpo_ctx.h"
+#include "strategy_dpo_manager.h"
+#include "state.h"
+#include "error.h"
+#include "face_db.h"
+
+/* packet trace format function */
+static u8 *hicn_interest_hitpit_format_trace (u8 * s, va_list * args);
+
+/* Stats string values */
+static char *hicn_interest_hitpit_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+vlib_node_registration_t hicn_interest_hitpit_node;
+
+always_inline void drop_packet (u32 * next0);
+
+/*
+ * hICN forwarder node for interests hitting the PIT
+ */
+static uword
+hicn_interest_hitpit_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                             vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicn_interest_hitpit_next_t next_index;
+  hicn_interest_hitpit_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  f64 tnow;
+
+  rt = vlib_node_get_runtime_data (vm, hicn_interest_hitpit_node.index);
+
+  if (PREDICT_FALSE (rt->pitcs == NULL))
+    {
+      rt->pitcs = &hicn_main.pitcs;
+    }
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  /* Capture time in vpp terms */
+  tnow = vlib_time_now (vm);
+
+  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 > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         u32 bi0;
+         u32 next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         hicn_hash_node_t *node0;
+         const hicn_strategy_vft_t *strategy_vft0;
+         const hicn_dpo_vft_t *dpo_vft0;
+         hicn_pcs_entry_t *pitp;
+         u8 dpo_ctx_id0;
+         u8 found = 0;
+         int nh_idx;
+         dpo_id_t *outface;
+         hicn_hash_entry_t *hash_entry0;
+         hicn_buffer_t *hicnb0;
+         int ret;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, STORE);
+           }
+
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+
+         /* Get hicn buffer and state */
+         hicnb0 = hicn_get_buffer (b0);
+         hicn_get_internal_state (hicnb0, rt->pitcs, &node0, &strategy_vft0,
+                                  &dpo_vft0, &dpo_ctx_id0, &hash_entry0);
+
+
+         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+         nameptr = (u8 *) (&name);
+         pitp = hicn_pit_get_data (node0);
+         dpo_id_t hicn_dpo_id0 =
+           { dpo_vft0->hicn_dpo_get_type (), 0, 0, dpo_ctx_id0 };
+
+         /*
+          * Check if the hit is instead a collision in the
+          * hash table. Unlikely to happen.
+          */
+         if (PREDICT_FALSE
+             (ret != HICN_ERROR_NONE
+              || !hicn_node_compare (nameptr, namelen, node0)))
+           {
+             stats.interests_hash_collision++;
+             /* Remove lock from the entry */
+             hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm, hash_entry0,
+                                   dpo_vft0, &hicn_dpo_id0);
+             drop_packet (&next0);
+
+             goto end_processing;
+           }
+         /*
+          * If the entry is expired, remove it no matter of
+          * the possible cases.
+          */
+         if (tnow > pitp->shared.expire_time)
+           {
+             strategy_vft0->hicn_on_interest_timeout (dpo_ctx_id0);
+             hicn_pcs_delete (rt->pitcs, &pitp, &node0, vm, hash_entry0,
+                              dpo_vft0, &hicn_dpo_id0);
+             stats.pit_expired_count++;
+             next0 =
+               isv6 ? HICN_INTEREST_HITPIT_NEXT_IP6_LOOKUP :
+               HICN_INTEREST_HITPIT_NEXT_IP4_LOOKUP;
+           }
+         else
+           {
+             if ((hash_entry0->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY))
+               {
+                 next0 = HICN_INTEREST_HITPIT_NEXT_INTEREST_HITCS;
+               }
+             else
+               {
+                 /*
+                  * Distinguish between aggregation or
+                  * retransmission
+                  */
+
+                 found =
+                   hicn_face_search (&(hicnb0->face_dpo_id),
+                                     &(pitp->u.pit.faces));
+
+                 if (found)
+                   {
+                     /*
+                      * Remove lock on the dpo
+                      * stored in the vlib_buffer
+                      */
+                     dpo_unlock (&hicnb0->face_dpo_id);
+                     strategy_vft0->hicn_select_next_hop (dpo_ctx_id0,
+                                                          &nh_idx, &outface);
+                     /* Retransmission */
+                     /*
+                      * Prepare the packet for the
+                      * forwarding
+                      */
+                     next0 = outface->dpoi_next_node;
+                     vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
+                       outface->dpoi_index;
+
+                     /*
+                      * Update the egress face in
+                      * the PIT
+                      */
+                     pitp->u.pit.pe_txnh = nh_idx;
+                     stats.interests_retx++;
+                   }
+                 else
+                   {
+                     hicn_face_db_add_face_dpo (&hicnb0->face_dpo_id,
+                                                &pitp->u.pit.faces);
+
+                     /* Aggregation */
+                     drop_packet (&next0);
+                     stats.interests_aggregated++;
+                   }
+                 /* Remove lock from the entry */
+                 hicn_pcs_remove_lock (rt->pitcs, &pitp, &node0, vm,
+                                       hash_entry0, dpo_vft0, &hicn_dpo_id0);
+
+               }
+           }
+       end_processing:
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_interest_hitpit_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+           }
+         /* Incr packet counter */
+         stats.pkts_processed += 1;
+
+         /*
+          * 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);
+    }
+  u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs);
+
+
+  vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+  vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index,
+                              HICNFWD_ERROR_INTEREST_AGG,
+                              stats.interests_aggregated);
+  vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index,
+                              HICNFWD_ERROR_INT_RETRANS,
+                              stats.interests_retx);
+  vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index,
+                              HICNFWD_ERROR_PIT_EXPIRED,
+                              stats.pit_expired_count);
+  vlib_node_increment_counter (vm, hicn_interest_hitpit_node.index,
+                              HICNFWD_ERROR_HASH_COLL_HASHTB_COUNT,
+                              stats.interests_hash_collision);
+
+  update_node_counter (vm, hicn_interest_hitpit_node.index,
+                      HICNFWD_ERROR_INT_COUNT, pit_int_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_interest_hitpit_format_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 *);
+  hicn_interest_hitpit_trace_t *t =
+    va_arg (*args, hicn_interest_hitpit_trace_t *);
+
+  s = format (s, "INTEREST-HITPIT: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+void
+drop_packet (u32 * next0)
+{
+  *next0 = HICN_INTEREST_HITPIT_NEXT_ERROR_DROP;
+}
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_interest_hitpit_node) =
+{
+  .function = hicn_interest_hitpit_node_fn,
+  .name = "hicn-interest-hitpit",
+  .vector_size = sizeof(u32),
+  .runtime_data_bytes = sizeof(hicn_interest_hitpit_runtime_t),
+  .format_trace = hicn_interest_hitpit_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_interest_hitpit_error_strings),
+  .error_strings = hicn_interest_hitpit_error_strings,
+  .n_next_nodes = HICN_INTEREST_HITPIT_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {
+    [HICN_INTEREST_HITPIT_NEXT_INTEREST_HITCS] = "hicn-interest-hitcs",
+    [HICN_INTEREST_HITPIT_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [HICN_INTEREST_HITPIT_NEXT_IP6_LOOKUP] = "ip6-lookup",
+    [HICN_INTEREST_HITPIT_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_pcslookup.h b/hicn-plugin/src/interest_pcslookup.h
new file mode 100755 (executable)
index 0000000..e27673a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_INTEREST_PCSLOOKUP_H__
+#define __HICN_INTEREST_PCSLOOKUP_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "pcs.h"
+
+/*
+ * Node context data; we think this is per-thread/instance
+ */
+typedef struct hicn_interest_pcslookup_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_interest_pcslookup_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_interest_pcslookup_trace_t;
+
+typedef enum
+{
+  HICN_INTEREST_PCSLOOKUP_NEXT_V4_LOOKUP,
+  HICN_INTEREST_PCSLOOKUP_NEXT_V6_LOOKUP,
+  HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITPIT,
+  HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITCS,
+  HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP,
+  HICN_INTEREST_PCSLOOKUP_N_NEXT,
+} hicn_interest_pcslookup_next_t;
+
+#endif /* // __HICN_INTEREST_PCSLOOKUP_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/interest_pcslookup_node.c b/hicn-plugin/src/interest_pcslookup_node.c
new file mode 100755 (executable)
index 0000000..40d6251
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+
+#include "interest_pcslookup.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "infra.h"
+#include "strategy_dpo_manager.h"
+#include "error.h"
+#include "state.h"
+
+/**
+ * @FILE This node performs a lookup in the PIT and CS for a received interest packet.
+ *
+ * This node passes the packet to the interest-hitpit and interest-hitcs nodes
+ * when there is a hit in the pit or content store, respectively.
+ */
+
+/* Functions declarations */
+
+/* packet trace format function */
+static u8 *hicn_interest_pcslookup_format_trace (u8 * s, va_list * args);
+
+
+/* Stats string values */
+static char *hicn_interest_pcslookup_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+vlib_node_registration_t hicn_interest_pcslookup_node;
+
+/*
+ * ICN forwarder node for interests: handling of Interests delivered based on
+ * ACL. - 1 packet at a time - ipv4/tcp ipv6/tcp
+ */
+static uword
+hicn_interest_pcslookup_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                                vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicn_interest_pcslookup_next_t next_index;
+  hicn_interest_pcslookup_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  int ret;
+
+  rt = vlib_node_get_runtime_data (vm, hicn_interest_pcslookup_node.index);
+
+  if (PREDICT_FALSE (rt->pitcs == NULL))
+    {
+      rt->pitcs = &hicn_main.pitcs;
+    }
+  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 > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t *b0;
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         u32 bi0;
+         u32 next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP;
+         u64 name_hash = 0;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         u32 node_id0 = 0;
+         u8 dpo_ctx_id0 = 0;
+         u8 vft_id0 = 0;
+         u8 is_cs0 = 0;
+         u8 hash_entry_id = 0;
+         u8 bucket_is_overflown = 0;
+         u32 bucket_id = ~0;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, STORE);
+             CLIB_PREFETCH (b1->data, CLIB_CACHE_LINE_BYTES, LOAD);
+           }
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+
+         if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
+           {
+             next0 =
+               isv6 ? HICN_INTEREST_PCSLOOKUP_NEXT_V6_LOOKUP :
+               HICN_INTEREST_PCSLOOKUP_NEXT_V4_LOOKUP;
+           }
+         nameptr = (u8 *) (&name);
+         stats.pkts_processed++;
+
+         if (PREDICT_FALSE (ret != HICN_ERROR_NONE ||
+                            hicn_hashtb_fullhash (nameptr, namelen,
+                                                  &name_hash) !=
+                            HICN_ERROR_NONE))
+           {
+             next0 = HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP;
+           }
+         else
+           {
+             if (hicn_hashtb_lookup_node (rt->pitcs->pcs_table, nameptr,
+                                          namelen, name_hash,
+                                          0 /* is_data */ , &node_id0,
+                                          &dpo_ctx_id0, &vft_id0, &is_cs0,
+                                          &hash_entry_id, &bucket_id,
+                                          &bucket_is_overflown) ==
+                 HICN_ERROR_NONE)
+               {
+                 next0 =
+                   HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITPIT + is_cs0;
+               }
+             stats.pkts_interest_count++;
+           }
+
+         hicn_store_internal_state (b0, name_hash, node_id0, dpo_ctx_id0,
+                                    vft_id0, hash_entry_id, bucket_id,
+                                    bucket_is_overflown);
+
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_interest_pcslookup_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_INTEREST;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+           }
+         /*
+          * 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);
+    }
+  u32 pit_int_count = hicn_pit_get_int_count (rt->pitcs);
+  u32 pit_cs_count = hicn_pit_get_cs_count (rt->pitcs);
+  u32 pcs_ntw_count = hicn_pcs_get_ntw_count (rt->pitcs);
+
+
+  vlib_node_increment_counter (vm, hicn_interest_pcslookup_node.index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+
+  vlib_node_increment_counter (vm, hicn_interest_pcslookup_node.index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  update_node_counter (vm, hicn_interest_pcslookup_node.index,
+                      HICNFWD_ERROR_INT_COUNT, pit_int_count);
+
+  update_node_counter (vm, hicn_interest_pcslookup_node.index,
+                      HICNFWD_ERROR_CS_COUNT, pit_cs_count);
+
+  update_node_counter (vm, hicn_interest_pcslookup_node.index,
+                      HICNFWD_ERROR_CS_NTW_COUNT, pcs_ntw_count);
+
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_interest_pcslookup_format_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 *);
+  hicn_interest_pcslookup_trace_t *t =
+    va_arg (*args, hicn_interest_pcslookup_trace_t *);
+
+  s = format (s, "INTEREST_PCSLOOKUP: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the interest forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_interest_pcslookup_node) =
+{
+  .function = hicn_interest_pcslookup_node_fn,
+  .name = "hicn-interest-pcslookup",
+  .vector_size = sizeof(u32),
+  .runtime_data_bytes = sizeof(hicn_interest_pcslookup_runtime_t),
+  .format_trace = hicn_interest_pcslookup_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicn_interest_pcslookup_error_strings),
+  .error_strings = hicn_interest_pcslookup_error_strings,
+  .n_next_nodes = HICN_INTEREST_PCSLOOKUP_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_INTEREST_PCSLOOKUP_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICN_INTEREST_PCSLOOKUP_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITPIT] = "hicn-interest-hitpit",
+    [HICN_INTEREST_PCSLOOKUP_NEXT_INTEREST_HITCS] = "hicn-interest-hitcs",
+    [HICN_INTEREST_PCSLOOKUP_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/mapme.h b/hicn-plugin/src/mapme.h
new file mode 100755 (executable)
index 0000000..e0786ef
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_MAPME__
+#define __HICN_MAPME__
+
+#include <vnet/dpo/load_balance.h>
+#include <vnet/buffer.h>
+#include <hicn/hicn.h>
+#include <hicn/mapme.h>
+
+#include "hicn.h"
+#include "strategy_dpo_ctx.h"
+#include "strategy_dpo_manager.h"      // dpo_is_hicn
+
+#define HICN_MAPME_ALLOW_LOCATORS 1
+
+//#define HICN_MAPME_NOTIFICATIONS 1
+
+#define NOT_A_NOTIFICATION false
+#define TIMER_NO_REPEAT false
+
+#define INVALID_SEQ 0
+#define INIT_SEQ 1
+
+typedef struct hicn_mapme_conf_s
+{
+  hicn_mapme_conf_t conf;
+  bool remove_dpo;             // FIXME used ?
+
+  vlib_main_t *vm;
+  vlib_log_class_t log_class;
+} hicn_mapme_main_t;
+
+#define foreach_hicn_mapme_event  \
+  _(FACE_ADD)                     \
+  _(FACE_DEL)                     \
+  _(FACE_APP_ADD)                 \
+  _(FACE_APP_DEL)                 \
+  _(FACE_NH_SET)                  \
+  _(FACE_NH_ADD)                  \
+  _(FACE_PH_ADD)                  \
+  _(FACE_PH_DEL)
+
+typedef enum
+{
+#define _(a) HICN_MAPME_EVENT_##a,
+  foreach_hicn_mapme_event
+#undef _
+} hicn_mapme_event_t;
+
+typedef hicn_dpo_ctx_t hicn_mapme_tfib_t;
+
+/*
+ * Ideally we might need to care about alignment, but this struct is only
+ * used for casting hicn_dpo_ctx_t.
+ *
+ * See otherwise vnet/dpo/dpo.h
+ */
+
+STATIC_ASSERT (sizeof (hicn_mapme_tfib_t) <= sizeof (hicn_dpo_ctx_t),
+              "hicn_mapme_tfib_t is greater than hicn_dpo_ctx_t");
+
+#define TFIB(dpo) ((hicn_mapme_tfib_t*)(dpo))
+
+static_always_inline int
+hicn_mapme_nh_set (hicn_mapme_tfib_t * tfib, dpo_id_t * face_id)
+{
+  tfib->next_hops[0] = *face_id;
+  tfib->entry_count = 1;
+  return 0;
+}
+
+/**
+ * @brief Add a next hop iif it is not already a next hops
+ */
+static_always_inline int
+hicn_mapme_nh_add (hicn_mapme_tfib_t * tfib, dpo_id_t * face_id)
+{
+  for (u8 pos = 0; pos < tfib->entry_count; pos++)
+    if (dpo_cmp (&tfib->next_hops[pos], face_id) == 0)
+      return 0;
+  tfib->next_hops[tfib->entry_count++] = *face_id;
+  return 0;
+}
+
+/**
+ * Add a 'previous' hop to the TFIB
+ *
+ * XXX we should have the for look in the reverse order for simpler code.
+ */
+static_always_inline int
+hicn_mapme_tfib_add (hicn_mapme_tfib_t * tfib, dpo_id_t * face_id)
+{
+  u8 pos = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
+
+  //XXX don 't add if it already exist
+  // eg.an old IU received on a face on which we are retransmitting
+  for (u8 pos2 = pos; pos2 < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; pos2++)
+    if (dpo_cmp (&tfib->next_hops[pos2], face_id) == 0)
+      return 0;
+
+  //Make sure we have enough room
+  if (pos <= tfib->entry_count)
+    return -1;
+
+  tfib->next_hops[pos - 1] = *face_id;
+  tfib->tfib_entry_count++;
+
+  return 0;
+}
+
+static_always_inline int
+hicn_mapme_tfib_del (hicn_mapme_tfib_t * tfib, dpo_id_t * face_id)
+{
+  /*
+   * We need to do a linear scan of TFIB entries to find the one to
+   * remove
+   */
+  u8 start_pos = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
+  u8 pos = ~0;
+  for (pos = start_pos; pos < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; pos++)
+    if (dpo_cmp (&tfib->next_hops[pos], face_id) == 0)
+      break;
+  if (pos == HICN_PARAM_FIB_ENTRY_NHOPS_MAX)
+    /* Not found */
+    return -1;
+
+  tfib->tfib_entry_count--;
+
+  /* Likely we won't receive a new IU twice from the same face */
+  if (PREDICT_TRUE (pos > start_pos))
+    memmove (tfib->next_hops + start_pos, tfib->next_hops + start_pos + 1,
+            (pos - start_pos) * sizeof (dpo_id_t));
+
+  return 0;
+}
+
+/**
+ * @brief Performs an Exact Prefix Match lookup on the FIB
+ * @returns the corresponding DPO (hICN or IP LB), or NULL
+ */
+static_always_inline
+  dpo_id_t * fib_epm_lookup (ip46_address_t * addr, u8 plen)
+{
+  fib_prefix_t fib_pfx;
+  fib_node_index_t fib_entry_index;
+  u32 fib_index;
+  dpo_id_t *dpo_id;
+  load_balance_t *lb;
+
+  const dpo_id_t *load_balance_dpo_id;
+
+  /* At this point the face exists in the face table */
+  fib_prefix_from_ip46_addr (addr, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+  /* Check if the route already exist in the fib : EPM */
+  fib_index = fib_table_find (fib_pfx.fp_proto, HICN_FIB_TABLE);
+
+  fib_entry_index = fib_table_lookup_exact_match (fib_index, &fib_pfx);
+  if (fib_entry_index == FIB_NODE_INDEX_INVALID)
+    return NULL;
+
+  load_balance_dpo_id = fib_entry_contribute_ip_forwarding (fib_entry_index);
+
+  /* The dpo is not a load balance dpo as expected */
+  if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE)
+    return NULL;
+
+  /* former_dpo_id is a load_balance dpo */
+  lb = load_balance_get (load_balance_dpo_id->dpoi_index);
+
+  /* Check if there is only one bucket */
+
+  /*
+   * We now distinguish the case where we have an hICN route (the
+   * regular case), and the case where we have an IP route, to be able
+   * to apply MAP-Me mechanisms even to a locator IP address.
+   */
+
+  for (int i = 0; i < lb->lb_n_buckets; i++)
+    {
+      /* un-const */
+      dpo_id = (dpo_id_t *) load_balance_get_bucket_i (lb, i);
+
+      if (dpo_is_hicn (dpo_id))
+       return dpo_id;
+    }
+
+  /* un-const */
+  return (dpo_id_t *) load_balance_dpo_id;
+}
+
+/* DPO types */
+
+extern dpo_type_t hicn_face_udp_type;
+extern dpo_type_t hicn_face_ip_type;
+
+/* VLIB EDGE IDs */
+
+/* in faces/ip/face_ip.c */
+extern u32 strategy_face_ip4_vlib_edge;
+extern u32 strategy_face_ip6_vlib_edge;
+/* in faces/udp/face_udp.c */
+extern u32 strategy_face_udp6_vlib_edge;
+extern u32 strategy_face_udp6_vlib_edge;
+
+
+/**
+ * @brief Returns the next hop vlib edge on which we can send an Interest packet.
+ *
+ * This is both used to preprocess a dpo that will be stored as a next hop in the FIB, and to determine on which node to send an Interest Update.
+ */
+always_inline u32
+hicn_mapme_get_dpo_vlib_edge (dpo_id_t * dpo)
+{
+  if (dpo->dpoi_type == hicn_face_ip_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return strategy_face_ip4_vlib_edge;
+       case DPO_PROTO_IP6:
+         return strategy_face_ip6_vlib_edge;
+       default:
+         return ~0;
+       }
+    }
+  else if (dpo->dpoi_type == hicn_face_udp_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return strategy_face_udp6_vlib_edge;
+       case DPO_PROTO_IP6:
+         return strategy_face_udp6_vlib_edge;
+       default:
+         return ~0;
+       }
+    }
+  else
+    {
+      return ~0;
+    }
+}
+
+/**
+ * @brief Returns the next hop node on which we can send an Update packet
+ */
+always_inline char *
+hicn_mapme_get_dpo_face_node (dpo_id_t * dpo)
+{
+  if (dpo->dpoi_type == hicn_face_ip_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return "hicn-face-ip4-output";
+       case DPO_PROTO_IP6:
+         return "hicn-face-ip6-output";
+       default:
+         return NULL;
+       }
+    }
+  else if (dpo->dpoi_type == hicn_face_udp_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return "hicn-face-udp4-output";
+       case DPO_PROTO_IP6:
+         return "hicn-face-udp6-output";
+       default:
+         return NULL;
+       }
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+
+#define DEBUG(...) vlib_log_debug(mapme_main.log_class, __VA_ARGS__)
+#define WARN(...) vlib_log_warn(mapme_main.log_class, __VA_ARGS__)
+#define ERROR(...) vlib_log_err(mapme_main.log_class, __VA_ARGS__)
+
+#endif /* __HICN_MAPME__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/mapme_ack.h b/hicn-plugin/src/mapme_ack.h
new file mode 100755 (executable)
index 0000000..98a2199
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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) 2017-2019 by Cisco Systems Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef HICN_MAPME_ACK_H
+#define HICN_MAPME_ACK_H
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+/* Node context data */
+typedef struct hicn_mapme_ack_runtime_s
+{
+  int id;
+} hicn_mapme_ack_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_mapme_ack_trace_t;
+
+typedef enum
+{
+  HICN_MAPME_ACK_NEXT_ERROR_DROP,
+  HICN_MAPME_ACK_N_NEXT,
+} hicn_mapme_ack_next_t;
+
+#endif /* HICN_MAPME_ACK_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/mapme_ack_node.c b/hicn-plugin/src/mapme_ack_node.c
new file mode 100755 (executable)
index 0000000..21e177b
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/ip/ip6_packet.h>
+#include <hicn/hicn.h>
+
+#include "mapme.h"
+#include "mapme_ack.h"
+#include "mapme_eventmgr.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "data_fwd.h"
+#include "infra.h"
+#include "strategy_dpo_manager.h"
+#include "error.h"
+#include "state.h"
+
+extern hicn_mapme_main_t mapme_main;
+
+/* packet trace format function */
+static u8 *hicn_mapme_ack_format_trace (u8 * s, va_list * args);
+
+
+/* Stats string values */
+static char *hicn_mapme_ack_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/*
+ * @brief Process incoming ack messages (Interest Update Ack)
+ * @param vm vlib main data structure
+ * @param b Control packet (IU)
+ * @param face_id Ingress face id
+ */
+bool
+hicn_mapme_process_ack (vlib_main_t * vm, vlib_buffer_t * b,
+                       dpo_id_t * in_face)
+{
+  seq_t fib_seq;
+  const dpo_id_t *dpo;
+  hicn_prefix_t prefix;
+  mapme_params_t params;
+  int rc;
+
+  /* Parse incoming message */
+  rc =
+    hicn_mapme_parse_packet (vlib_buffer_get_current (b), &prefix, &params);
+  if (rc < 0)
+    goto ERR_PARSE;
+
+  if (params.seq == INVALID_SEQ)
+    {
+      DEBUG ("Invalid sequence number found in IU");
+      return true;
+    }
+
+  dpo = fib_epm_lookup (&(prefix.name), prefix.len);
+  if (!dpo)
+    {
+      DEBUG ("Ignored ACK for non-existing FIB entry. Ignored.");
+      return true;
+
+    }
+
+  /* We are only expecting ACKs for hICN DPOs */
+  ASSERT (dpo_is_hicn (dpo));
+
+  const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (dpo->dpoi_type);
+  hicn_mapme_tfib_t *tfib =
+    TFIB (dpo_vft->hicn_dpo_get_ctx (dpo->dpoi_index));
+  fib_seq = tfib->seq;
+
+  /*
+   * As we always retransmit IU with the latest seq, we are not interested in
+   * ACKs with inferior seq
+   */
+  if (params.seq < fib_seq)
+    {
+      DEBUG ("Ignored ACK for low seq");
+      return true;
+    }
+
+  hicn_mapme_tfib_del (tfib, in_face);
+
+  /*
+   * Is the ingress face in TFIB ? if so, remove it, otherwise it might be a
+   * duplicate
+   */
+  retx_t *retx =
+    vlib_process_signal_event_data (vm,
+                                   hicn_mapme_eventmgr_process_node.index,
+                                   HICN_MAPME_EVENT_FACE_PH_DEL, 1,
+                                   sizeof (retx_t));
+  *retx = (retx_t)
+  {
+  .prefix = prefix,.dpo = *dpo};
+  return true;
+
+ERR_PARSE:
+  return false;
+}
+
+vlib_node_registration_t hicn_mapme_ack_node;
+
+static uword
+hicn_mapme_ack_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                       vlib_frame_t * frame)
+{
+  hicn_buffer_t *hb;
+  hicn_mapme_ack_next_t next_index;
+  u32 n_left_from, *from, *to_next;
+  n_left_from = frame->n_vectors;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)      // buffers in the current frame
+    {
+      u32 n_left_to_next;
+      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 bi0;
+         vlib_buffer_t *b0;
+         u32 next0 = HICN_MAPME_ACK_NEXT_ERROR_DROP;
+         u32 sw_if_index0;
+         /* 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);
+
+         vlib_cli_output (vm, "Received IUAck");
+         hb = hicn_get_buffer (b0);
+         hicn_mapme_process_ack (vm, b0, &hb->face_dpo_id);
+
+         /* Single loop: process 1 packet here */
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_mapme_ack_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         /* $$$$$ Done processing 1 packet here $$$$$ */
+
+         /* 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);
+    }
+//  vlib_node_increment_counter (vm, hicn_mapme_ack_node.index,
+//                               HICN_MAPME_ACK_ERROR_SWAPPED, pkts_swapped);
+  return (frame->n_vectors);
+}
+
+/* packet trace format function */
+static u8 *
+hicn_mapme_ack_format_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 *);
+  hicn_mapme_ack_trace_t *t = va_arg (*args, hicn_mapme_ack_trace_t *);
+
+  s = format (s, "MAPME_ACK: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the MAP-Me node processing special interests
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_mapme_ack_node) =
+{
+  .function = hicn_mapme_ack_node_fn,
+  .name = "hicn-mapme-ack",
+  .vector_size =  sizeof (u32),
+  .runtime_data_bytes = sizeof (hicn_mapme_ack_runtime_t),
+  .format_trace = hicn_mapme_ack_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_mapme_ack_error_strings),
+  .error_strings = hicn_mapme_ack_error_strings,
+  .n_next_nodes = HICN_MAPME_ACK_N_NEXT,
+  .next_nodes =
+  {
+    [HICN_MAPME_ACK_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/mapme_ctrl.h b/hicn-plugin/src/mapme_ctrl.h
new file mode 100755 (executable)
index 0000000..e7c1cdf
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017-2019 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) 2017-2019 by Cisco Systems Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef HICN_MAPME_CTRL_H
+#define HICN_MAPME_CTRL_H
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+/* Node context data */
+typedef struct hicn_mapme_ctrl_runtime_s
+{
+  int id;
+} hicn_mapme_ctrl_runtime_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_mapme_ctrl_trace_t;
+
+typedef enum
+{
+  HICN_MAPME_CTRL_NEXT_IP4_OUTPUT,
+  HICN_MAPME_CTRL_NEXT_IP6_OUTPUT,
+  HICN_MAPME_CTRL_NEXT_UDP46_OUTPUT,
+  HICN_MAPME_CTRL_NEXT_UDP66_OUTPUT,
+  HICN_MAPME_CTRL_NEXT_ERROR_DROP,
+  HICN_MAPME_CTRL_N_NEXT,
+} hicn_mapme_ctrl_next_t;
+/**
+ * @brief Returns the next hop node on which we can send an ACK packet
+ */
+always_inline hicn_mapme_ctrl_next_t
+hicn_mapme_get_dpo_iface_node (dpo_id_t * dpo)
+{
+  if (dpo->dpoi_type == hicn_face_ip_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return HICN_MAPME_CTRL_NEXT_IP4_OUTPUT;
+       case DPO_PROTO_IP6:
+         return HICN_MAPME_CTRL_NEXT_IP6_OUTPUT;
+       default:
+         return HICN_MAPME_CTRL_NEXT_ERROR_DROP;
+       }
+    }
+  else if (dpo->dpoi_type == hicn_face_udp_type)
+    {
+      switch (dpo->dpoi_proto)
+       {
+       case DPO_PROTO_IP4:
+         return HICN_MAPME_CTRL_NEXT_UDP46_OUTPUT;
+       case DPO_PROTO_IP6:
+         return HICN_MAPME_CTRL_NEXT_UDP66_OUTPUT;
+       default:
+         return HICN_MAPME_CTRL_NEXT_ERROR_DROP;
+       }
+    }
+  else
+    {
+      return HICN_MAPME_CTRL_NEXT_ERROR_DROP;
+    }
+}
+
+#endif /* HICN_MAPME_CTRL_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/mapme_ctrl_node.c b/hicn-plugin/src/mapme_ctrl_node.c
new file mode 100755 (executable)
index 0000000..9fc0c90
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * This node processses MAP-Me control messages.
+ */
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/dpo/load_balance.h>
+#include <hicn/hicn.h>
+
+#include "mapme.h"
+#include "mapme_ctrl.h"
+#include "mapme_eventmgr.h"
+#include "mgmt.h"
+#include "parser.h"
+#include "infra.h"
+#include "strategy_dpo_manager.h"
+#include "error.h"
+#include "state.h"
+
+extern hicn_mapme_main_t mapme_main;
+
+#define MS2NS(x) x * 1000000
+
+/* Functions declarations */
+
+/* packet trace format function */
+static u8 *hicn_mapme_ctrl_format_trace (u8 * s, va_list * args);
+
+
+/* Stats string values */
+static char *hicn_mapme_ctrl_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/**
+ * Preprocess the ingress face so as to make it a candidate next hop, which is
+ * what MAP-Me will handle
+ */
+static_always_inline void
+preprocess_in_face (hicn_type_t type, dpo_id_t * in, dpo_id_t * out)
+{
+  u32 vlib_edge = hicn_mapme_get_dpo_vlib_edge (in);
+  *out = *in;
+  out->dpoi_next_node = vlib_edge;
+}
+
+/*
+ * @brief Process incoming control messages (Interest Update)
+ * @param vm vlib main data structure
+ * @param b Control packet (IU)
+ * @param face_id Ingress face id
+ *
+ * NOTE:
+ *  - this function answers locally to the IU interest by replying with a Ack
+ *  (Data) packet, unless in case of outdated information, in which we can
+ *  consider the interest is dropped, and another IU (aka ICMP error) is sent so
+ *  that retransmissions stop.
+ */
+static_always_inline bool
+hicn_mapme_process_ctrl (vlib_main_t * vm, vlib_buffer_t * b,
+                        dpo_id_t * in_face)
+{
+  seq_t fib_seq;
+  const dpo_id_t *dpo;
+  hicn_prefix_t prefix;
+  mapme_params_t params;
+  int rc;
+
+  /* Parse incoming message */
+  rc =
+    hicn_mapme_parse_packet (vlib_buffer_get_current (b), &prefix, &params);
+  if (rc < 0)
+    goto ERR_PARSE;
+
+  vlib_cli_output (vm, "IU - type:%d seq:%d len:%d", params.type, params.seq,
+                  prefix.len);
+
+  if (params.seq == INVALID_SEQ)
+    {
+      vlib_log_warn (mapme_main.log_class,
+                    "Invalid sequence number found in IU");
+
+      return true;
+    }
+
+  /* We forge the ACK which we be the packet forwarded by the node */
+  hicn_mapme_create_ack (vlib_buffer_get_current (b), &params);
+
+  dpo = fib_epm_lookup (&prefix.name, prefix.len);
+  if (!dpo)
+    {
+#ifdef HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY
+      /*
+       * This might happen for a node hosting a producer which has moved.
+       * Destroying the face has led to removing all corresponding FIB
+       * entries. In that case, we need to correctly restore the FIB entries.
+       */
+      DEBUG ("Re-creating FIB entry with next hop on connection")
+#error "not implemented"
+#else
+      //ERROR("Received IU for non-existing FIB entry");
+      return false;
+#endif /* HICN_MAPME_ALLOW_NONEXISTING_FIB_ENTRY */
+
+    }
+
+#ifdef HICN_MAPME_ALLOW_LOCATORS
+  if (!dpo_is_hicn ((dpo)))
+    {
+      /* We have an IP DPO */
+      WARN ("Not implemented yet.");
+      return false;
+    }
+#endif
+
+  /* Process the hICN DPO */
+  const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (dpo->dpoi_type);
+  hicn_mapme_tfib_t *tfib =
+    TFIB (dpo_vft->hicn_dpo_get_ctx (dpo->dpoi_index));
+  fib_seq = tfib->seq;
+
+  if (params.seq > fib_seq)
+    {
+      DEBUG
+       ("Higher sequence number than FIB %d > %d, updating seq and next hops",
+        params.seq, fib_seq);
+
+      /* This has to be done first to allow processing ack */
+      tfib->seq = params.seq;
+
+      // in_face and next_hops are face_id_t
+
+      /* Remove ingress face from TFIB in case it was present */
+      hicn_mapme_tfib_del (tfib, in_face);
+
+      /* Move next hops to TFIB... but in_face... */
+      for (u8 pos = 0; pos < tfib->entry_count; pos++)
+       {
+         if (dpo_cmp (&tfib->next_hops[pos], in_face) == 0)
+           continue;
+         hicn_mapme_tfib_add (tfib, &tfib->next_hops[pos]);
+       }
+
+      /* ... and set ingress face as next_hop */
+      hicn_mapme_nh_set (tfib, in_face);
+
+      /* We transmit both the prefix and the full dpo (type will be needed to pick the right transmit node */
+      retx_t *retx =
+       vlib_process_signal_event_data (vm,
+                                       hicn_mapme_eventmgr_process_node.
+                                       index,
+                                       HICN_MAPME_EVENT_FACE_NH_SET, 1,
+                                       sizeof (retx_t));
+      *retx = (retx_t)
+      {
+      .prefix = prefix,.dpo = *dpo};
+
+    }
+  else if (params.seq == fib_seq)
+    {
+      DEBUG ("Same sequence number than FIB %d > %d, adding next hop",
+            params.seq, fib_seq);
+
+      /* Remove ingress face from TFIB in case it was present */
+      hicn_mapme_tfib_del (tfib, in_face);
+
+      /* Add ingress face to next hops */
+      hicn_mapme_nh_add (tfib, in_face);
+
+      /* Multipath, multihoming, multiple producers or duplicate interest */
+      retx_t *retx =
+       vlib_process_signal_event_data (vm,
+                                       hicn_mapme_eventmgr_process_node.
+                                       index,
+                                       HICN_MAPME_EVENT_FACE_NH_ADD, 1,
+                                       sizeof (retx_t));
+      *retx = (retx_t)
+      {
+      .prefix = prefix,.dpo = *dpo};
+    }
+  else                         // params.seq < fib_seq
+    {
+      /*
+       * face is propagating outdated information, we can just consider it as a
+       * prevHops
+       */
+      hicn_mapme_tfib_add (tfib, in_face);
+
+      retx_t *retx =
+       vlib_process_signal_event_data (vm,
+                                       hicn_mapme_eventmgr_process_node.
+                                       index,
+                                       HICN_MAPME_EVENT_FACE_PH_ADD, 1,
+                                       sizeof (retx_t));
+      *retx = (retx_t)
+      {
+      .prefix = prefix,.dpo = *dpo};
+    }
+
+  /* We just raise events, the event_mgr is in charge of forging packet. */
+
+  return true;
+
+//ERR_ACK_CREATE:
+ERR_PARSE:
+  return false;
+}
+
+vlib_node_registration_t hicn_mapme_ctrl_node;
+
+static uword
+hicn_mapme_ctrl_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                        vlib_frame_t * frame)
+{
+  hicn_buffer_t *hb;
+  hicn_mapme_ctrl_next_t next_index;
+  u32 n_left_from, *from, *to_next;
+  n_left_from = frame->n_vectors;
+  dpo_id_t in_face;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)      // buffers in the current frame
+    {
+      u32 n_left_to_next;
+      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 bi0;
+         vlib_buffer_t *b0;
+
+         /* 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);
+         hb = hicn_get_buffer (b0);
+
+         /* This determines the next node on which the ack will be sent back */
+         u32 next0 = hicn_mapme_get_dpo_iface_node (&hb->face_dpo_id);
+
+         /* Preprocessing is needed to precompute in the dpo the next node
+          * that will have to be followed by regular interests when being
+          * forwarder on a given next hop
+          */
+         preprocess_in_face (hb->type, &hb->face_dpo_id, &in_face);
+         hicn_mapme_process_ctrl (vm, b0, &in_face);
+
+         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);
+    }
+  //  vlib_node_increment_counter (vm, hicn_mapme_ctrl_node.index,
+  //                               HICN_MAPME_CTRL_ERROR_SWAPPED, pkts_swapped);
+  return frame->n_vectors;
+}
+
+/* packet trace format function */
+static u8 *
+hicn_mapme_ctrl_format_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 *);
+  hicn_mapme_ctrl_trace_t *t = va_arg (*args, hicn_mapme_ctrl_trace_t *);
+
+  s = format (s, "MAPME_CTRL: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node registration for the MAP-Me node processing special interests
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_mapme_ctrl_node) =
+{
+  .function = hicn_mapme_ctrl_node_fn,
+  .name = "hicn-mapme-ctrl",
+  .vector_size =  sizeof (u32),
+  .runtime_data_bytes = sizeof (hicn_mapme_ctrl_runtime_t),
+  .format_trace = hicn_mapme_ctrl_format_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_mapme_ctrl_error_strings),
+  .error_strings = hicn_mapme_ctrl_error_strings,
+  .n_next_nodes = HICN_MAPME_CTRL_N_NEXT,
+  .next_nodes =
+  {
+    /* 
+     * Control packets are not forwarded by this node, but sent by the Event
+     * Manager. This node is only responsible for sending ACK back, 
+     * Acks are like data packets are output on iface's
+     */
+    [HICN_MAPME_CTRL_NEXT_IP4_OUTPUT]   = "hicn-iface-ip4-output",
+    [HICN_MAPME_CTRL_NEXT_IP6_OUTPUT]   = "hicn-iface-ip6-output",
+    [HICN_MAPME_CTRL_NEXT_UDP46_OUTPUT] = "hicn-iface-udp4-output",
+    [HICN_MAPME_CTRL_NEXT_UDP66_OUTPUT] = "hicn-iface-udp6-output",
+    [HICN_MAPME_CTRL_NEXT_ERROR_DROP]   = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/mapme_eventmgr.c b/hicn-plugin/src/mapme_eventmgr.c
new file mode 100755 (executable)
index 0000000..5d59164
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2017-2019 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 "hicn.h"
+#include "strategy_dpo_ctx.h"
+#include "mapme.h"
+#include "mapme_eventmgr.h"
+#include "strategies/dpo_mw.h"
+
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
+
+#define DEFAULT_TIMEOUT 1.0    /* s */
+
+hicn_mapme_main_t mapme_main;
+
+hicn_prefix_t *retx_pool;
+uword *retx_hash;
+
+void
+hicn_mapme_init (vlib_main_t * vm)
+{
+  mapme_main.vm = vm;
+  mapme_main.log_class = vlib_log_register_class ("hicn_mapme", 0);
+}
+
+/* borrowed from vnet/fib/ip4_fib.c */
+
+typedef struct ip4_fib_show_walk_ctx_t_
+{
+  fib_node_index_t *ifsw_indicies;
+} ip4_fib_show_walk_ctx_t;
+
+static fib_table_walk_rc_t
+ip4_fib_show_walk_cb (fib_node_index_t fib_entry_index, void *arg)
+{
+  ip4_fib_show_walk_ctx_t *ctx = arg;
+
+  vec_add1 (ctx->ifsw_indicies, fib_entry_index);
+
+  return (FIB_TABLE_WALK_CONTINUE);
+}
+
+/* borrowed from vnet/fib/ip6_fib.c */
+
+typedef struct ip6_fib_show_ctx_t_
+{
+  fib_node_index_t *entries;
+} ip6_fib_show_ctx_t;
+
+static fib_table_walk_rc_t
+ip6_fib_table_show_walk (fib_node_index_t fib_entry_index, void *arg)
+{
+  ip6_fib_show_ctx_t *ctx = arg;
+
+  vec_add1 (ctx->entries, fib_entry_index);
+
+  return (FIB_TABLE_WALK_CONTINUE);
+}
+
+void
+hicn_mapme_process_fib_entry (vlib_main_t * vm, dpo_id_t face,
+                             const fib_node_index_t * fib_entry_index)
+{
+  const dpo_id_t *load_balance_dpo_id;
+  load_balance_t *lb;
+  dpo_id_t *dpo_id;
+  fib_entry_t *fib_entry;
+
+  load_balance_dpo_id = fib_entry_contribute_ip_forwarding (*fib_entry_index);
+
+  /* The dpo is not a load balance dpo as expected */
+  if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE)
+    return;
+
+  /* former_dpo_id is a load_balance dpo */
+  lb = load_balance_get (load_balance_dpo_id->dpoi_index);
+
+  for (int i = 0; i < lb->lb_n_buckets; i++)
+    {
+      /* un-const */
+      dpo_id = (dpo_id_t *) load_balance_get_bucket_i (lb, i);
+
+      if (dpo_is_hicn (dpo_id))
+       {
+         fib_entry = fib_entry_get (*fib_entry_index);
+         vlib_cli_output (vm, "set face pending %U", format_fib_prefix,
+                          &fib_entry->fe_prefix);
+       }
+    }
+}
+
+void
+hicn_mapme_process_ip4_fib (vlib_main_t * vm, dpo_id_t face)
+{
+  ip4_main_t *im4 = &ip4_main;
+  fib_table_t *fib_table;
+  int table_id = -1, fib_index = ~0;
+
+    /* *INDENT-OFF* */
+    pool_foreach (fib_table, im4->fibs,
+    ({
+        ip4_fib_t *fib = pool_elt_at_index(im4->v4_fibs, fib_table->ft_index);
+
+        if (table_id >= 0 && table_id != (int)fib->table_id)
+            continue;
+        if (fib_index != ~0 && fib_index != (int)fib->index)
+            continue;
+
+        fib_node_index_t *fib_entry_index;
+        ip4_fib_show_walk_ctx_t ctx = {
+            .ifsw_indicies = NULL,
+        };
+
+        ip4_fib_table_walk(fib, ip4_fib_show_walk_cb, &ctx);
+        //vec_sort_with_function(ctx.ifsw_indicies, fib_entry_cmp_for_sort);
+
+        vec_foreach(fib_entry_index, ctx.ifsw_indicies)
+        {
+            hicn_mapme_process_fib_entry(vm, face, fib_entry_index);
+        }
+
+        vec_free(ctx.ifsw_indicies);
+    }));
+    /* *INDENT-ON* */
+}
+
+void
+hicn_mapme_process_ip6_fib (vlib_main_t * vm, dpo_id_t face)
+{
+  /* Walk IPv6 FIB */
+  ip6_main_t *im6 = &ip6_main;
+  fib_table_t *fib_table;
+  ip6_fib_t *fib;
+  int table_id = -1, fib_index = ~0;
+
+    /* *INDENT-OFF* */
+    pool_foreach (fib_table, im6->fibs,
+    ({
+        fib = pool_elt_at_index(im6->v6_fibs, fib_table->ft_index);
+
+        if (table_id >= 0 && table_id != (int)fib->table_id)
+            continue;
+        if (fib_index != ~0 && fib_index != (int)fib->index)
+            continue;
+        if (fib_table->ft_flags & FIB_TABLE_FLAG_IP6_LL)
+            continue;
+
+        fib_node_index_t *fib_entry_index;
+        ip6_fib_show_ctx_t ctx = {
+            .entries = NULL,
+        };
+
+        ip6_fib_table_walk(fib->index, ip6_fib_table_show_walk, &ctx);
+        //vec_sort_with_function(ctx.entries, fib_entry_cmp_for_sort);
+
+        vec_foreach(fib_entry_index, ctx.entries)
+        {
+            hicn_mapme_process_fib_entry(vm, face, fib_entry_index);
+        }
+
+        vec_free(ctx.entries);
+
+    }));
+    /* *INDENT-ON* */
+}
+
+
+/**
+ * Callback called everytime a new face is created (not including app faces)
+ */
+void
+hicn_mapme_on_face_added (vlib_main_t * vm, dpo_id_t face)
+{
+  hicn_mapme_process_ip4_fib (vm, face);
+  hicn_mapme_process_ip6_fib (vm, face);
+}
+
+/*
+ * We need a retransmission pool holding all necessary information for crafting
+ * special interests, thus including both the DPO and the prefix associated to
+ * it.
+ */
+#define NUM_RETX_ENTRIES 100
+#define NUM_RETX_SLOT 2
+#define NEXT_SLOT(cur) (1-cur)
+#define CUR retx_array[cur]
+#define NXT retx_array[NEXT_SLOT(cur)]
+#define CURLEN retx_len[cur]
+#define NXTLEN retx_len[NEXT_SLOT(cur)]
+
+static_always_inline void *
+get_packet_buffer (vlib_main_t * vm, u32 node_index, u32 dpoi_index,
+                  ip46_address_t * addr, hicn_type_t type)
+{
+  vlib_frame_t *f;
+  vlib_buffer_t *b;            // for newly created packet
+  u32 *to_next;
+  u32 bi;
+  u8 *buffer;
+
+  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
+    {
+      clib_warning ("buffer allocation failure");
+      return NULL;
+    }
+
+  /* Create a new packet from scratch */
+  b = vlib_get_buffer (vm, bi);
+  ASSERT (b->current_data == 0);
+
+  /* Face information for next hop node index */
+  vnet_buffer (b)->ip.adj_index[VLIB_TX] = dpoi_index;
+  hicn_get_buffer (b)->type = type;
+
+  /* Enqueue the packet right now */
+  f = vlib_get_frame_to_node (vm, node_index);
+  to_next = vlib_frame_vector_args (f);
+  to_next[0] = bi;
+  f->n_vectors = 1;
+  vlib_put_frame_to_node (vm, node_index, f);
+
+  // pointer to IP layer ? do we need to prepare for ethernet ???
+  buffer = vlib_buffer_get_current (b);
+  b->current_length =
+    (type.l1 == IPPROTO_IPV6) ? HICN_MAPME_V6_HDRLEN : HICN_MAPME_V4_HDRLEN;
+
+  return buffer;
+}
+
+static_always_inline bool
+hicn_mapme_send_message (vlib_main_t * vm, const hicn_prefix_t * prefix,
+                        mapme_params_t * params, dpo_id_t * face)
+{
+  size_t n;
+
+  /* This should be retrieved from face information */
+  DEBUG ("Retransmission for prefix %U seq=%d", format_ip46_address,
+        &prefix->name, IP46_TYPE_ANY, params->seq);
+
+  char *node_name = hicn_mapme_get_dpo_face_node (face);
+  if (!node_name)
+    {
+      clib_warning
+       ("Could not determine next node for sending MAP-Me packet");
+      return false;
+    }
+
+  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) node_name);
+  u32 node_index = node->index;
+
+  u8 *buffer =
+    get_packet_buffer (vm, node_index, face->dpoi_index,
+                      (ip46_address_t *) prefix,
+                      (params->protocol ==
+                       IPPROTO_IPV6) ? HICN_TYPE_IPV6_ICMP :
+                      HICN_TYPE_IPV4_ICMP);
+  n = hicn_mapme_create_packet (buffer, prefix, params);
+  if (n <= 0)
+    {
+      clib_warning ("Could not create MAP-Me packet");
+      return false;
+    }
+
+  return true;
+}
+
+static_always_inline void
+hicn_mapme_send_updates (vlib_main_t * vm, hicn_prefix_t * prefix,
+                        dpo_id_t dpo, bool send_all)
+{
+  const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (dpo.dpoi_type);
+  hicn_mapme_tfib_t *tfib = TFIB (dpo_vft->hicn_dpo_get_ctx (dpo.dpoi_index));
+  u8 tfib_last_idx = HICN_PARAM_FIB_ENTRY_NHOPS_MAX - tfib->tfib_entry_count;
+  if (!tfib)
+    {
+      DEBUG ("NULL TFIB entry id=%d", dpo.dpoi_index);
+      return;
+    }
+
+  mapme_params_t params = {
+    .protocol = ip46_address_is_ip4 (&prefix->name)
+      ? IPPROTO_IP : IPPROTO_IPV6,
+    .type = UPDATE,
+    .seq = tfib->seq,
+  };
+
+  if (send_all)
+    {
+      for (u8 pos = tfib_last_idx; pos < HICN_PARAM_FIB_ENTRY_NHOPS_MAX;
+          pos++)
+       {
+         hicn_mapme_send_message (vm, prefix, &params,
+                                  &tfib->next_hops[pos]);
+       }
+    }
+  else
+    {
+      hicn_mapme_send_message (vm, prefix, &params,
+                              &tfib->next_hops[tfib_last_idx]);
+    }
+}
+
+static uword
+hicn_mapme_eventmgr_process (vlib_main_t * vm,
+                            vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+  f64 timeout = 0;             /* By default, no timer is run */
+  f64 current_time, due_time;
+  u8 idle = 0;
+
+  retx_t retx_array[NUM_RETX_SLOT][NUM_RETX_ENTRIES];
+  u8 retx_len[NUM_RETX_SLOT] = { 0 };
+  u8 cur = 0;                  /* current slot */
+
+  hicn_mapme_init (vm);
+
+  for (;;)
+    {
+      /* NOTE: returned timeout seems to always be 0 with get_event_data
+       * instead of get_event, and we thus need to reimplement timeout
+       * management on top, as done elsewhere in VPP code.
+       *
+       * The most probable event. For simplicity, for new faces, we pass the same retx_t with no
+       * prefix
+       */
+      if (timeout != 0)
+       {
+         /* timeout = */ vlib_process_wait_for_event_or_clock (vm, timeout);
+         current_time = vlib_time_now (vm);
+
+         /*
+          * As we don't accummulate errors, we allow for simple timer
+          * management with no error correction accounting for elapsed time.
+          * Also, we only run a timer when there are pending retransmissions.
+          */
+         timeout =
+           (due_time >
+            current_time) ? due_time - current_time : DEFAULT_TIMEOUT;
+         due_time = current_time + timeout;
+       }
+      else
+       {
+         vlib_process_wait_for_event (vm);
+       }
+
+      uword event_type = ~0;
+      void *event_data = vlib_process_get_event_data (vm, &event_type);
+
+      switch (event_type)
+       {
+       case HICN_MAPME_EVENT_FACE_ADD:
+         {
+           /*
+            * A face has been added:
+            *  - In case of a local app face, we need to advertise a new prefix
+            *  - For another local face type, we need to advertise local
+            *  prefixes and schedule retransmissions
+            */
+           retx_t *retx_events = event_data;
+           for (u8 i = 0; i < vec_len (retx_events); i++)
+             {
+               hicn_mapme_on_face_added (vm, retx_events[i].dpo);
+             }
+           idle = 0;
+         }
+         break;
+
+       case HICN_MAPME_EVENT_FACE_DEL:
+         idle = 0;
+         break;
+
+       case HICN_MAPME_EVENT_FACE_NH_SET:
+         {
+           /*
+            * An hICN FIB entry has been modified. All operations so far
+            * have been procedded in the nodes. Here we need to track
+            * retransmissions upon timeout: we mark the FIB entry as pending in
+            * the second-to-next slot
+            */
+
+           /* Mark FIB entry as pending for second-to-next slot */
+           retx_t *retx_events = event_data;
+           for (u8 i = 0; i < vec_len (retx_events); i++)
+             {
+               /*
+                * retx_events[i] corresponds to the dpoi_index of the (T)FIB
+                * structure that has been modified. Multiple successive
+                * events might correspond to the same entry.
+                *
+                * The FIB entry has a new next hop, and its TFIB section has:
+                *  - eventually previous prev hops for which a IU with a
+                *  lower seqno has been sent
+                *  - the prev hops that have just been added.
+                *
+                * We don't distinguish any and just send an updated IU to all
+                * of them. The retransmission of the latest IU to all
+                * facilitates the matching of ACKs to a single seqno which is
+                * the one stored in the FIB.
+                *
+                * Since we retransmit to all prev hops, we can remove this
+                * (T)FIB entry for the check at the end of the current slot.
+                */
+               retx_t *retx = (retx_t *) & retx_events[i];
+
+               /*
+                * Transmit IU for all TFIB entries with latest seqno (we have
+                * at least one for sure!)
+                */
+               hicn_mapme_send_updates (vm, &retx->prefix, retx->dpo, true);
+
+               /* Delete entry_id from retransmissions in the current slot (if present) ... */
+               for (u8 j = 0; j < CURLEN; j++)
+                 if (dpo_cmp (&(CUR[j].dpo), &retx->dpo))
+                   {
+                     CUR[j].dpo.dpoi_index = ~0;       /* sufficient */
+                   }
+
+               /* ... and schedule it for next slot (if not already) */
+               u8 j;
+               for (j = 0; j < NXTLEN; j++)
+                 if (dpo_cmp (&NXT[j].dpo, &retx->dpo))
+                   break;
+               if (j == NXTLEN)        /* not found */
+                 NXT[NXTLEN++] = *retx;
+             }
+           idle = 0;
+         }
+         break;
+
+       case HICN_MAPME_EVENT_FACE_NH_ADD:
+         /*
+          * As per the description of states, this event should add the face
+          * to the list of next hops, and eventually remove it from TFIB.
+          * This corresponds to the multipath case.
+          *
+          * In all cases, we assume the propagation was already done when the first
+          * interest with the same sequence number was received, so we stop here
+          * No change in TFIB = no IU to send
+          *
+          * No change in timers.
+          */
+         vlib_cli_output (vm, "[hicn_event_mgr] ADD NEXT HOP IN FIB");
+
+         /* Add ingress face as next hop */
+         idle = 0;
+
+         break;
+
+       case HICN_MAPME_EVENT_FACE_PH_ADD:
+         /* Back-propagation, interesting even for IN (desync) */
+         {
+           retx_t *retx_events = event_data;
+           for (u8 i = 0; i < vec_len (retx_events); i++)
+             {
+               hicn_mapme_send_updates (vm, &retx_events[i].prefix,
+                                        retx_events[i].dpo, false);
+             }
+           idle = 0;
+         }
+         break;
+
+       case HICN_MAPME_EVENT_FACE_PH_DEL:
+         /* Ack : remove an element from TFIB */
+         break;
+
+       case ~0:
+         /* Timeout occurred, we have to retransmit IUs for all pending
+          * prefixes having entries in TFIB
+          *
+          * timeouts are slotted
+          *    |     |     |     |
+          *
+          *      ^
+          *      +- event occurred
+          *            new face, wait for the second next
+          *            (having two arrays and swapping cur and next)
+          *         retx : put in next
+          */
+         idle += 1;
+         for (u8 pos = 0; pos < CURLEN; pos++)
+           {
+             retx_t *retx = &CUR[pos];
+
+             if (retx->dpo.dpoi_index == ~0)   /* deleted entry */
+               continue;
+
+             const hicn_dpo_vft_t *dpo_vft =
+               hicn_dpo_get_vft (retx->dpo.dpoi_type);
+             hicn_mapme_tfib_t *tfib =
+               TFIB (dpo_vft->hicn_dpo_get_ctx (retx->dpo.dpoi_index));
+             if (!tfib)
+               {
+                 DEBUG ("NULL TFIB entry for dpoi_index=%d",
+                        retx->dpo.dpoi_index);
+                 continue;
+               }
+
+             hicn_mapme_send_updates (vm, &retx->prefix, retx->dpo, true);
+
+             /*
+              * We did some retransmissions, so let's reschedule a check in the
+              * next slot
+              */
+             NXT[NXTLEN++] = CUR[pos];
+             idle = 0;
+           }
+
+         /* Reset events in this slot and prepare for next one */
+         CURLEN = 0;
+         cur = NEXT_SLOT (cur);
+
+         /* After two empty slots, we disable the timer */
+
+         break;
+       }
+
+      if (event_data)
+       vlib_process_put_event_data (vm, event_data);
+
+      timeout = (idle > 1) ? 0 : DEFAULT_TIMEOUT;
+
+      // if (vlib_process_suspend_time_is_zero (timeout)) { ... }
+
+    }
+
+  /* NOTREACHED */
+  return 0;
+}
+
+/* Not static as we need to access it from hicn_face */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_mapme_eventmgr_process_node) = { //,static) = {
+    .function = hicn_mapme_eventmgr_process,
+    .type = VLIB_NODE_TYPE_PROCESS,
+    .name = "mapme-eventmgr-process",
+    .process_log2_n_stack_bytes = 16,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/mapme_eventmgr.h b/hicn-plugin/src/mapme_eventmgr.h
new file mode 100755 (executable)
index 0000000..2f8106d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>         // vlib_node_registration_t (vlib/node.h)
+
+/* 
+ * Structure carrying all necessary information for managing Special Interest
+ * (re)transmissions.
+ */
+typedef struct
+{
+  hicn_prefix_t prefix;
+  dpo_id_t dpo;
+} retx_t;
+
+#define HASH32(x) ((u16)x ^ (x << 16))
+
+/**
+ * @brief This is a process node reacting to face events.
+ */
+// not static !
+vlib_node_registration_t hicn_mapme_eventmgr_process_node;
+
+/**
+ * @brief Initialize MAP-Me on forwarder
+ * @params vm - vlib_main_t pointer
+ */
+void hicn_mapme_init (vlib_main_t * vm);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/mgmt.c b/hicn-plugin/src/mgmt.c
new file mode 100755 (executable)
index 0000000..b992ba1
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vppinfra/error.h>
+
+#include "hicn.h"
+#include "infra.h"
+#include "mgmt.h"
+
+/* define message IDs */
+#include "hicn_msg_enum.h"
+
+/* shared routine betweeen API and CLI, leveraging API message structure */
+int
+hicn_mgmt_node_stats_get (vl_api_hicn_api_node_stats_get_reply_t * rmp)
+{
+  rmp->pkts_processed = 0;
+  rmp->pkts_interest_count = 0;
+  rmp->pkts_data_count = 0;
+  rmp->pkts_from_cache_count = 0;
+  rmp->pkts_no_pit_count = 0;
+  rmp->pit_expired_count = 0;
+  rmp->cs_expired_count = 0;
+  rmp->cs_lru_count = 0;
+  rmp->pkts_drop_no_buf = 0;
+  rmp->interests_aggregated = 0;
+  rmp->interests_retx = 0;
+  rmp->pit_entries_count =
+    clib_host_to_net_u64 (hicn_main.pitcs.pcs_pit_count);
+  rmp->cs_entries_count = clib_host_to_net_u64 (hicn_main.pitcs.pcs_cs_count);
+  rmp->cs_entries_ntw_count =
+    clib_host_to_net_u64 (hicn_main.pitcs.policy_state.count);
+
+  vlib_error_main_t *em;
+  vlib_node_t *n;
+  foreach_vlib_main ((
+                      {
+                      em = &this_vlib_main->error_main;
+                      n =
+                      vlib_get_node (this_vlib_main,
+                                     hicn_interest_pcslookup_node.index);
+                      u32 node_cntr_base_idx = n->error_heap_index;
+                      rmp->pkts_processed +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_PROCESSED]);
+                      rmp->pkts_interest_count +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_INTERESTS]);
+                      n =
+                      vlib_get_node (this_vlib_main,
+                                     hicn_data_pcslookup_node.index);
+                      node_cntr_base_idx = n->error_heap_index;
+                      rmp->pkts_processed +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_PROCESSED]);
+                      n =
+                      vlib_get_node (this_vlib_main,
+                                     hicn_data_pcslookup_node.index);
+                      node_cntr_base_idx = n->error_heap_index;
+                      rmp->pkts_data_count +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_DATAS]);
+                      n =
+                      vlib_get_node (this_vlib_main,
+                                     hicn_interest_hitcs_node.index);
+                      node_cntr_base_idx = n->error_heap_index;
+                      rmp->pkts_from_cache_count +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_CACHED]);
+                      n =
+                      vlib_get_node (this_vlib_main,
+                                     hicn_interest_hitpit_node.index);
+                      node_cntr_base_idx = n->error_heap_index;
+                      rmp->interests_aggregated +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_INTEREST_AGG]);
+                      rmp->interests_retx +=
+                      clib_host_to_net_u64 (em->counters[node_cntr_base_idx +
+                                                         HICNFWD_ERROR_INT_RETRANS]);}));
+  return (HICN_ERROR_NONE);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/mgmt.h b/hicn-plugin/src/mgmt.h
new file mode 100755 (executable)
index 0000000..08b1de0
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_MGMT_H__
+#define __HICN_MGMT_H__
+
+#include <vppinfra/error.h>
+#include "faces/face.h"
+#include "hicn_api.h"
+
+typedef struct icn_stats_s
+{
+  u32 pkts_processed;
+  u32 pkts_interest_count;
+  u32 pkts_data_count;
+  u32 pkts_from_cache_count;
+  u32 pkts_no_pit_count;
+  u32 pit_expired_count;
+  u32 cs_expired_count;
+  u32 no_bufs_count;
+  u32 pkts_interest_agg;
+  u32 pkts_int_retrans;
+  u32 pit_int_count;
+  u32 pit_cs_count;
+} icn_stats_t;
+
+typedef enum
+{
+  HICN_MGMT_FACE_OP_NONE = 0,
+  HICN_MGMT_FACE_OP_CREATE,
+  HICN_MGMT_FACE_OP_DELETE,
+  HICN_MGMT_FACE_OP_ADMIN,
+  HICN_MGMT_FACE_OP_HELLO,
+} hicn_mgmt_face_op_e;
+
+
+typedef enum
+{
+  HICN_MGMT_PUNTING_OP_NONE = 0,
+  HICN_MGMT_PUNTING_OP_CREATE,
+  HICN_MGMT_PUNTING_OP_DELETE,
+  HICN_MGMT_PUNTING_OP_ENABLE,
+  HICN_MGMT_PUNTING_OP_DISABLE
+} hicn_mgmt_punting_op_e;
+
+typedef enum
+{
+  HICN_MGMT_MAPME_OP_NONE = 0,
+  HICN_MGMT_MAPME_OP_CREATE,
+  HICN_MGMT_MAPME_OP_DELETE,
+  HICN_MGMT_MAPME_OP_ENABLE,
+  HICN_MGMT_MAPME_OP_DISABLE
+} hicn_mgmt_mapme_op_e;
+
+typedef enum
+{
+  HICN_ADDRESS_TYPE_NONE,
+  HICN_ADDRESS_TYPE_V4,
+  HICN_ADDRESS_TYPE_V6
+} hicn_address_type_e;
+
+/*
+ * Utility to update error counters in all hICN nodes
+ */
+always_inline void
+update_node_counter (vlib_main_t * vm, u32 node_idx, u32 counter_idx, u64 val)
+{
+  vlib_node_t *node = vlib_get_node (vm, node_idx);
+  vlib_error_main_t *em = &(vm->error_main);
+  u32 base_idx = node->error_heap_index;
+
+  em->counters[base_idx + counter_idx] = val;
+}
+
+
+/*
+ * Stats for the forwarding node, which end up called "error" even though
+ * they aren't...
+ */
+#define foreach_hicnfwd_error                                  \
+  _(PROCESSED, "hICN packets processed")                       \
+  _(INTERESTS, "hICN interests forwarded")                     \
+  _(DATAS, "hICN data msgs forwarded")                         \
+  _(CACHED, "Cached data ")                                    \
+  _(NO_PIT, "hICN no PIT entry drops")                         \
+  _(PIT_EXPIRED, "hICN expired PIT entries")                   \
+  _(CS_EXPIRED, "hICN expired CS entries")                     \
+  _(CS_LRU, "hICN LRU CS entries freed")                       \
+  _(NO_BUFS, "No packet buffers")                              \
+  _(INTEREST_AGG, "Interests aggregated")                      \
+  _(INTEREST_AGG_ENTRY, "Interest aggregated per entry")       \
+  _(INT_RETRANS, "Interest retransmissions")                   \
+  _(INT_COUNT, "Interests in PIT")                             \
+  _(CS_COUNT, "CS total entries")                              \
+  _(CS_NTW_COUNT, "CS ntw entries")                            \
+  _(CS_APP_COUNT, "CS app entries")                            \
+  _(HASH_COLL_HASHTB_COUNT, "Collisions in Hash table")
+
+typedef enum
+{
+#define _(sym, str) HICNFWD_ERROR_##sym,
+  foreach_hicnfwd_error
+#undef _
+    HICNFWD_N_ERROR,
+} hicnfwd_error_t;
+
+/*
+ * Declarations
+ */
+clib_error_t *hicn_api_plugin_hookup (vlib_main_t * vm);
+
+int hicn_mgmt_node_stats_get (vl_api_hicn_api_node_stats_get_reply_t * rmp);
+
+#endif /* // __HICN_MGMT_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/params.h b/hicn-plugin/src/params.h
new file mode 100755 (executable)
index 0000000..fc890f6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_PARAM_H__
+#define __HICN_PARAM_H__
+
+/*
+ * Features
+ */
+#define HICN_FEATURE_CS 1      //1 enable 0 disable
+
+/*
+ * Face compile-time parameters
+ */
+#define HICN_PARAM_FACES_MAX 64
+
+/*
+ * Max length for hICN names
+ */
+#define HICN_PARAM_HICN_NAME_LEN_MAX 20        //bytes
+
+// Max next - hops supported in a FIB entry
+#define HICN_PARAM_FIB_ENTRY_NHOPS_MAX   5
+
+// Default and limit on weight, whatever weight means
+#define HICN_PARAM_FIB_ENTRY_NHOP_WGHT_DFLT   0x10
+#define HICN_PARAM_FIB_ENTRY_NHOP_WGHT_MAX    0xff
+
+/*
+ * PIT compile-time parameters
+ */
+#define HICN_PARAM_PIT_ENTRIES_MIN    1024
+#define HICN_PARAM_PIT_ENTRIES_DFLT    1024 * 128
+#define HICN_PARAM_PIT_ENTRIES_MAX      2 * 1024 * 1024
+
+// aggregation limit(interest previous hops)
+#define HICN_PARAM_PIT_ENTRY_PHOPS_MAX 516
+
+// PIT lifetime limits on API override this(in seconds, long -float type)
+#define HICN_PARAM_PIT_LIFETIME_BOUND_MIN_SEC   0.100L
+#define HICN_PARAM_PIT_LIFETIME_BOUND_MAX_SEC  20.000L
+
+//PIT lifetime params if not set at API(in mseconds, integer type)
+#define HICN_PARAM_PIT_LIFETIME_DFLT_MIN_MS  200
+#define HICN_PARAM_PIT_LIFETIME_DFLT_DFLT_MS 20000
+#define HICN_PARAM_PIT_LIFETIME_DFLT_MAX_MS  20000
+
+// Face CS reservation params
+#define HICN_PARAM_FACE_MAX_CS_RESERVED 10000  //packets
+#define HICN_PARAM_FACE_MIN_CS_RESERVED 0      //packets
+#define HICN_PARAM_FACE_DFT_CS_RESERVED 1000   //packets
+
+/*
+ * CS compile-time parameters
+ */
+#define HICN_PARAM_CS_ENTRIES_MIN       0      // can disable CS
+#define HICN_PARAM_CS_ENTRIES_DFLT      4 * 1024
+#define HICN_PARAM_CS_ENTRIES_MAX       1024 * 1024
+
+#define HICN_PARAM_CS_LRU_DEFAULT    (16 * 1024)
+
+/* CS lifetime defines, in mseconds, integer type */
+#define HICN_PARAM_CS_LIFETIME_MIN      100
+#define HICN_PARAM_CS_LIFETIME_DFLT    (5 * 60 * 1000) // 300 seconds
+#define HICN_PARAM_CS_LIFETIME_MAX      (24 * 3600 * 1000)     //24 hours...
+
+/* CS reserved portion for applications */
+#define HICN_PARAM_CS_RESERVED_APP 30  //%
+
+/* Cloning parameters */
+/* ip4 */
+#define HICN_IP4_VERSION_HEADER_LENGTH 0x45
+#define HICN_IP4_PROTOCOL IP_PROTOCOL_TCP
+#define HICN_IP4_TTL_DEFAULT 128
+
+/* ip6 */
+#define IPV6_DEFAULT_VERSION         6
+#define IPV6_DEFAULT_TRAFFIC_CLASS   0
+#define IPV6_DEFAULT_FLOW_LABEL      0
+#define HCIN_IP6_VERSION_TRAFFIC_FLOW (IPV6_DEFAULT_VERSION << 28) |    \
+  (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |                                  \
+  (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)
+#define HICN_IP6_PROTOCOL IP_PROTOCOL_TCP
+#define HICN_IP6_HOP_LIMIT 0x40
+
+#endif /* // __HICN_PARAM_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/parser.h b/hicn-plugin/src/parser.h
new file mode 100755 (executable)
index 0000000..cbc5696
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_PARSER_H__
+#define __HICN_PARSER_H__
+
+#include <vlib/vlib.h>
+
+#include "hicn.h"
+#include "error.h"
+
+
+/*
+ * Key type codes for header, header tlvs, body tlvs, and child tlvs
+ */
+
+// FIXME(reuse lib struct, no more control ?)
+enum hicn_pkt_type_e
+{
+  HICN_PKT_TYPE_INTEREST = 0,
+  HICN_PKT_TYPE_CONTENT = 1,
+};
+
+always_inline int
+hicn_interest_parse_pkt (vlib_buffer_t * pkt, hicn_name_t * name,
+                        u16 * namelen, hicn_header_t ** pkt_hdrp, u8 * isv6)
+{
+  if (pkt == NULL)
+    return HICN_ERROR_PARSER_PKT_INVAL;
+  hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt);
+  *pkt_hdrp = pkt_hdr;
+  u8 *ip_pkt = vlib_buffer_get_current (pkt);
+  u8 version = (pkt_hdr->v4.ip.version_ihl & 0xf0) >> 4;
+  *isv6 = ((version & 2) >> 1);
+  u8 ip_proto = (*isv6) * IPPROTO_IPV6;
+  u8 next_proto_offset = 6 + (1 - *isv6) * 3;
+  //in the ipv6 header the next header field is at byte 6
+  // in the ipv4 header the protocol field is at byte 9
+  hicn_type_t type = (hicn_type_t) { {
+                                     .l4 = IPPROTO_NONE,.l3 =
+                                     IPPROTO_NONE,.l2 =
+                                     ip_pkt[next_proto_offset],.l1 =
+                                     ip_proto}
+  };
+  hicn_get_buffer (pkt)->type = type;
+
+  hicn_ops_vft[type.l1]->get_interest_name (type, &pkt_hdr->protocol, name);
+  *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN;
+
+  return HICN_ERROR_NONE;
+}
+
+always_inline int
+hicn_data_parse_pkt (vlib_buffer_t * pkt, hicn_name_t * name,
+                    u16 * namelen, hicn_header_t ** pkt_hdrp, u8 * isv6)
+{
+  if (pkt == NULL)
+    return HICN_ERROR_PARSER_PKT_INVAL;
+  hicn_header_t *pkt_hdr = vlib_buffer_get_current (pkt);
+  *pkt_hdrp = pkt_hdr;
+  *pkt_hdrp = pkt_hdr;
+  u8 *ip_pkt = vlib_buffer_get_current (pkt);
+  u8 version = (pkt_hdr->v4.ip.version_ihl & 0xf0) >> 4;
+  *isv6 = ((version & 2) >> 1);
+  u8 ip_proto = (*isv6) * IPPROTO_IPV6;
+  /*
+   * in the ipv6 header the next header field is at byte 6 in the ipv4
+   * header the protocol field is at byte 9
+   */
+  u8 next_proto_offset = 6 + (1 - *isv6) * 3;
+  hicn_type_t type = (hicn_type_t) { {.l4 = IPPROTO_NONE,.l3 =
+                                     IPPROTO_NONE,.l2 =
+                                     ip_pkt[next_proto_offset],.l1 =
+                                     ip_proto}
+  };
+  hicn_get_buffer (pkt)->type = type;
+  hicn_ops_vft[type.l1]->get_data_name (type, &pkt_hdr->protocol, name);
+  *namelen = (1 - (*isv6)) * HICN_V4_NAME_LEN + (*isv6) * HICN_V6_NAME_LEN;
+
+  return HICN_ERROR_NONE;
+}
+
+
+#endif /* // __HICN_PARSER_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/pcs.c b/hicn-plugin/src/pcs.c
new file mode 100755 (executable)
index 0000000..4226291
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdlib.h>
+#include <vlib/vlib.h>
+
+#include "hashtb.h"
+#include "pcs.h"
+#include "cache_policies/cs_lru.h"
+
+int
+hicn_pit_create (hicn_pit_cs_t * p, u32 num_elems)
+{
+  int ret =
+    hicn_hashtb_alloc (&p->pcs_table, num_elems, sizeof (hicn_pcs_entry_t));
+  p->pcs_table->ht_flags |= HICN_HASHTB_FLAG_KEY_FMT_NAME;
+
+  p->pcs_pit_count = p->pcs_cs_count = 0;
+
+  p->policy_state.max =
+    HICN_PARAM_CS_LRU_DEFAULT -
+    (HICN_PARAM_CS_LRU_DEFAULT * HICN_PARAM_CS_RESERVED_APP / 100);
+  p->policy_state.count = 0;
+  p->policy_state.head = p->policy_state.tail = 0;
+  p->pcs_app_max = HICN_PARAM_CS_LRU_DEFAULT - p->policy_state.max;
+
+  p->policy_vft.hicn_cs_insert = hicn_cs_lru.hicn_cs_insert;
+  p->policy_vft.hicn_cs_update = hicn_cs_lru.hicn_cs_update;
+  p->policy_vft.hicn_cs_dequeue = hicn_cs_lru.hicn_cs_dequeue;
+  p->policy_vft.hicn_cs_delete_get = hicn_cs_lru.hicn_cs_delete_get;
+  p->policy_vft.hicn_cs_trim = hicn_cs_lru.hicn_cs_trim;
+
+  return (ret);
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/pcs.h b/hicn-plugin/src/pcs.h
new file mode 100755 (executable)
index 0000000..375a7d5
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_PCS_H__
+#define __HICN_PCS_H__
+
+#include "hashtb.h"
+#include "face_db.h"
+#include "strategy_dpo_manager.h"
+#include "error.h"
+#include "cache_policies/cs_policy.h"
+#include "faces/face.h"
+#include "faces/ip/dpo_ip.h"
+#include "faces/app/face_prod.h"
+
+/* The PIT and CS are stored as a union */
+#define HICN_PIT_NULL_TYPE 0
+#define HICN_PIT_TYPE      1
+#define HICN_CS_TYPE       2
+
+/*
+ * Definitions and Forward refs for the time counters we're trying out.
+ * Counters are maintained by the background process.
+ */
+#define SEC_MS 1000
+#define HICN_INFRA_FAST_TIMER_SECS  1
+#define HICN_INFRA_FAST_TIMER_MSECS (HICN_INFRA_FAST_TIMER_SECS * SEC_MS)
+#define HICN_INFRA_SLOW_TIMER_SECS  60
+#define HICN_INFRA_SLOW_TIMER_MSECS (HICN_INFRA_SLOW_TIMER_SECS * SEC_MS)
+
+/*
+ * Max number of incoming (interest) faces supported, for now. Note that
+ * changing this may change alignment within the PIT struct, so be careful.
+ */
+typedef struct __attribute__ ((packed)) hicn_pcs_shared_s
+{
+
+  /* Installation/creation time (vpp float units, for now) */
+  f64 create_time;
+
+  /* Expiration time (vpp float units, for now) */
+  f64 expire_time;
+
+  /* Shared 'flags' octet */
+  u8 entry_flags;
+
+  /* Needed to align for the pit or cs portion */
+  u8 padding;
+} hicn_pcs_shared_t;
+
+#define HICN_PCS_ENTRY_CS_FLAG 0x01
+
+/*
+ * PIT entry, unioned with a CS entry below
+ */
+typedef struct __attribute__ ((packed)) hicn_pit_entry_s
+{
+
+  /* Shared size 8 + 8 + 2 = 18B */
+
+  /*
+   * Egress next hop (containes the egress face) This id refers to the
+   * nh
+   */
+  /* choosen in the next_hops array of the dpo */
+  /* 18B + 1B = 19B */
+  u8 pe_txnh;
+
+  /* Array of faces */
+  /* 24B + 32B (8B*4) =56B */
+  hicn_face_db_t faces;
+
+} hicn_pit_entry_t;
+
+#define HICN_CS_ENTRY_OPAQUE_SIZE HICN_HASH_NODE_APP_DATA_SIZE - 40
+
+/*
+ * CS entry, unioned with a PIT entry below
+ */
+typedef struct __attribute__ ((packed)) hicn_cs_entry_s
+{
+  /* 22B + 2B = 24B */
+  u16 align;
+
+  /* Packet buffer, if held */
+  /* 18B + 4B = 22B */
+  u32 cs_pkt_buf;
+
+  /* Ingress face */
+  /* 24B + 8B = 32B */
+  //Fix alignment issues
+  union
+  {
+    dpo_id_t cs_rxface;
+    u64 cs_rxface_u64;
+  };
+
+  /* Linkage for LRU, in the form of hashtable node indexes */
+  /* 32B + 8B = 40B */
+  u32 cs_lru_prev;
+  u32 cs_lru_next;
+
+  /* Reserved for implementing cache policy different than LRU */
+  /* 40B + 56B = 96B */
+  u8 opaque[HICN_CS_ENTRY_OPAQUE_SIZE];
+
+
+} __attribute__ ((packed)) hicn_cs_entry_t;
+
+/*
+ * Combined PIT/CS entry data structure, embedded in a hashtable entry after
+ * the common hashtable preamble struct. This MUST fit in the available
+ * (fixed) space in a hashtable node.
+ */
+typedef struct hicn_pcs_entry_s
+{
+
+  hicn_pcs_shared_t shared;
+
+  union
+  {
+    hicn_pit_entry_t pit;
+    hicn_cs_entry_t cs;
+  } u;
+} hicn_pcs_entry_t;
+
+
+/*
+ * Overall PIT/CS table, based on the common hashtable
+ */
+typedef struct hicn_pit_cs_s
+{
+
+  hicn_hashtb_t *pcs_table;
+
+  /* Counters for PIT/CS sentries */
+  u32 pcs_pit_count;
+  u32 pcs_cs_count;
+  u32 pcs_cs_dealloc;
+  u32 pcs_pit_dealloc;
+
+  /* Total size of PCS */
+  u32 pcs_size;
+
+  /* Memory reserved for appfaces */
+  u32 pcs_app_max;
+  u32 pcs_app_count;
+
+  hicn_cs_policy_t policy_state;
+  hicn_cs_policy_vft_t policy_vft;
+
+} hicn_pit_cs_t;
+
+/* Functions declarations */
+int hicn_pit_create (hicn_pit_cs_t * p, u32 num_elems);
+
+always_inline void
+hicn_pit_to_cs (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+               hicn_pcs_entry_t * pcs_entry, hicn_hash_entry_t * hash_entry,
+               hicn_hash_node_t * node, const hicn_dpo_vft_t * dpo_vft,
+               dpo_id_t * hicn_dpo_id, dpo_id_t * inface_id, u8 is_appface);
+
+always_inline void
+hicn_pcs_cs_update (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t * entry, hicn_hash_node_t * node);
+
+always_inline void
+hicn_pcs_cs_delete (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t ** pcs_entry, hicn_hash_node_t ** node,
+                   hicn_hash_entry_t * hash_entry,
+                   const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id);
+
+always_inline int
+hicn_pcs_cs_insert (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                   hicn_hash_entry_t ** hash_entry, u64 hashval,
+                   u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                   u8 * hash_entry_id, u32 * bucket_id,
+                   u8 * bucket_is_overflow);
+
+always_inline int
+hicn_pcs_cs_insert_update (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                          hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                          hicn_hash_entry_t ** hash_entry, u64 hashval,
+                          u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                          u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                          u8 * bucket_is_overflow);
+
+always_inline int
+hicn_pcs_pit_insert (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t * entry,
+                    hicn_hash_node_t * node, hicn_hash_entry_t ** hash_entry,
+                    u64 hashval, u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                    u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                    u8 * bucket_is_overflow);
+
+always_inline void
+hicn_pcs_pit_delete (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                    hicn_hash_node_t ** node, vlib_main_t * vm,
+                    hicn_hash_entry_t * hash_entry,
+                    const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id);
+
+always_inline int
+hicn_pcs_insert (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                hicn_hash_entry_t ** hash_entry, u64 hashval, u32 * node_id,
+                u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs, u8 * hash_entry_id,
+                u32 * bucket_id, u8 * bucket_is_overflow);
+
+always_inline void
+hicn_pcs_delete (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                hicn_hash_node_t ** node, vlib_main_t * vm,
+                hicn_hash_entry_t * hash_entry,
+                const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id);
+
+always_inline void
+hicn_pcs_remove_lock (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                     hicn_hash_node_t ** node, vlib_main_t * vm,
+                     hicn_hash_entry_t * hash_entry,
+                     const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id);
+
+always_inline void
+hicn_cs_delete_trimmed (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                       hicn_hash_entry_t * hash_entry,
+                       hicn_hash_node_t ** node, vlib_main_t * vm);
+
+/* Function implementation */
+/* Accessor for pit/cs data inside hash table node */
+static inline hicn_pcs_entry_t *
+hicn_pit_get_data (hicn_hash_node_t * node)
+{
+  return (hicn_pcs_entry_t *) (hicn_hashtb_node_data (node));
+}
+
+/* Init pit/cs data block (usually inside hash table node) */
+static inline void
+hicn_pit_init_data (hicn_pcs_entry_t * p)
+{
+  memset (p, 0, sizeof (hicn_pcs_entry_t));
+  hicn_face_bucket_t *face_bkt;
+  pool_get (hicn_face_bucket_pool, face_bkt);
+
+  p->u.pit.faces.next_bucket = face_bkt - hicn_face_bucket_pool;
+}
+
+
+
+static inline f64
+hicn_pcs_get_exp_time (f64 cur_time_sec, u64 lifetime_msec)
+{
+  return (cur_time_sec + ((f64) lifetime_msec) / SEC_MS);
+}
+
+/*
+ * Configure CS LRU limit. Zero is accepted, means 'no limit', probably not a
+ * good choice.
+ */
+static inline void
+hicn_pit_set_lru_max (hicn_pit_cs_t * p, u32 limit)
+{
+  p->policy_state.max = limit;
+}
+
+/*
+ * Configure CS LRU limit. Zero is accepted, means 'no limit', probably not a
+ * good choice.
+ */
+static inline void
+hicn_pit_set_lru_app_max (hicn_pit_cs_t * p, u32 limit)
+{
+  p->pcs_app_max = limit;
+}
+
+/*
+ * Accessor for PIT interest counter.
+ */
+static inline u32
+hicn_pit_get_int_count (const hicn_pit_cs_t * pitcs)
+{
+  return (pitcs->pcs_pit_count);
+}
+
+/*
+ * Accessor for PIT cs entries counter.
+ */
+static inline u32
+hicn_pit_get_cs_count (const hicn_pit_cs_t * pitcs)
+{
+  return (pitcs->pcs_cs_count);
+}
+
+static inline u32
+hicn_pcs_get_ntw_count (const hicn_pit_cs_t * pitcs)
+{
+  return (pitcs->policy_state.count);
+}
+
+static inline u32
+hicn_pit_get_htb_bucket_count (const hicn_pit_cs_t * pitcs)
+{
+  return (pitcs->pcs_table->ht_overflow_buckets_used);
+}
+
+static inline int
+hicn_cs_enabled (hicn_pit_cs_t * pit)
+{
+  switch (HICN_FEATURE_CS)
+    {
+    case 0:
+    default:
+      return (0);
+    case 1:
+      return (pit->policy_state.max > 0);
+    }
+}
+
+/*
+ * Delete a PIT/CS entry from the hashtable, freeing the hash node struct.
+ * The caller's pointers are zeroed! If cs_trim is true, entry has already
+ * been removed from lru list The main purpose of this wrapper is helping
+ * maintain the per-PIT stats.
+ */
+always_inline void
+hicn_pcs_delete_internal (hicn_pit_cs_t * pitcs,
+                         hicn_pcs_entry_t ** pcs_entryp,
+                         hicn_hash_entry_t * hash_entry,
+                         hicn_hash_node_t ** node, vlib_main_t * vm,
+                         const hicn_dpo_vft_t * dpo_vft,
+                         dpo_id_t * hicn_dpo_id)
+{
+  hicn_pcs_entry_t *pcs = *pcs_entryp;
+
+  ASSERT (pcs == hicn_hashtb_node_data (*node));
+
+  if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
+    {
+      pitcs->pcs_cs_dealloc++;
+
+      /* Free any associated packet buffer */
+      vlib_buffer_free_one (vm, pcs->u.cs.cs_pkt_buf);
+      pcs->u.cs.cs_pkt_buf = ~0;
+      ASSERT ((pcs->u.cs.cs_lru_prev == 0)
+             && (pcs->u.cs.cs_lru_prev == pcs->u.cs.cs_lru_next));
+    }
+  else
+    {
+      pitcs->pcs_pit_dealloc++;
+      dpo_vft->hicn_dpo_unlock_dpo_ctx (hicn_dpo_id);
+
+      /* Flush faces */
+      hicn_faces_flush (&(pcs->u.pit.faces));
+    }
+
+  hicn_hashtb_delete (pitcs->pcs_table, node, hash_entry->he_msb64);
+  memset (*pcs_entryp, 0, sizeof (hicn_pcs_entry_t));
+  *pcs_entryp = NULL;
+}
+
+/*
+ * Convert a PIT entry into a CS entry (assumes that the entry is already in
+ * the hashtable.) This is primarily here to maintain the internal counters.
+ */
+always_inline void
+hicn_pit_to_cs (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+               hicn_pcs_entry_t * pcs_entry, hicn_hash_entry_t * hash_entry,
+               hicn_hash_node_t * node, const hicn_dpo_vft_t * dpo_vft,
+               dpo_id_t * hicn_dpo_id, dpo_id_t * inface_id, u8 is_appface)
+{
+
+  /*
+   * Different from the insert node. In here we don't need to add a new
+   * hash entry.
+   */
+  pitcs->pcs_pit_count--;
+  dpo_vft->hicn_dpo_unlock_dpo_ctx (hicn_dpo_id);
+  /* Flush faces */
+  hicn_faces_flush (&(pcs_entry->u.pit.faces));
+  memset (&(pcs_entry->u.cs), ~0, sizeof (hicn_cs_entry_t));
+
+  hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_CS_ENTRY;
+  node->hn_flags |= HICN_HASH_NODE_CS_FLAGS;
+  pcs_entry->shared.entry_flags |= HICN_PCS_ENTRY_CS_FLAG;
+
+  pcs_entry->u.cs.cs_rxface = *inface_id;
+
+  /* Update the CS according to the policy */
+  hicn_cs_policy_t *policy_state;
+  hicn_cs_policy_vft_t *policy_vft;
+
+  if (is_appface)
+    {
+      dpo_id_t *face_dpo = (dpo_id_t *) & (pcs_entry->u.cs.cs_rxface);
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_dpo->dpoi_index);
+      hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+      policy_state = &prod_face->policy;
+      policy_vft = &prod_face->policy_vft;
+    }
+  else
+    {
+      policy_state = &pitcs->policy_state;
+      policy_vft = &pitcs->policy_vft;
+    }
+
+  policy_vft->hicn_cs_insert (pitcs, node, pcs_entry, policy_state);
+  pitcs->pcs_cs_count++;
+
+  if (policy_state->count > policy_state->max)
+    {
+      hicn_hash_node_t *node;
+      hicn_pcs_entry_t *pcs_entry;
+      hicn_hash_entry_t *hash_entry;
+      policy_vft->hicn_cs_delete_get (pitcs, policy_state,
+                                     &node, &pcs_entry, &hash_entry);
+
+
+      /*
+       * We don't have to decrease the lock (therefore we cannot
+       * use hicn_pcs_cs_delete function)
+       */
+      policy_vft->hicn_cs_dequeue (pitcs, node, pcs_entry, policy_state);
+
+      hicn_cs_delete_trimmed (pitcs, &pcs_entry, hash_entry, &node, vm);
+
+      /* Update the global CS counter */
+      pitcs->pcs_cs_count--;
+    }
+}
+
+/* Functions specific for PIT or CS */
+
+always_inline void
+hicn_pcs_cs_update (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t * entry, hicn_hash_node_t * node)
+{
+  hicn_cs_policy_t *policy_state;
+  hicn_cs_policy_vft_t *policy_vft;
+
+  dpo_id_t *face_dpo = (dpo_id_t *) & (entry->u.cs.cs_rxface);
+  policy_state = &pitcs->policy_state;
+  policy_vft = &pitcs->policy_vft;
+
+  if (face_dpo->dpoi_type == hicn_face_ip_type)
+    {
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_dpo->dpoi_index);
+      if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD)
+       {
+         hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+         policy_state = &prod_face->policy;
+         policy_vft = &prod_face->policy_vft;
+       }
+    }
+  /* Update the CS LRU, moving this item to the head */
+  policy_vft->hicn_cs_update (pitcs, node, entry, policy_state);
+}
+
+always_inline void
+hicn_pcs_cs_delete (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t ** pcs_entryp, hicn_hash_node_t ** nodep,
+                   hicn_hash_entry_t * hash_entry,
+                   const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id)
+{
+  if (!(hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED))
+    {
+      hicn_cs_policy_t *policy_state;
+      hicn_cs_policy_vft_t *policy_vft;
+
+      dpo_id_t *face_dpo = (dpo_id_t *) & ((*pcs_entryp)->u.cs.cs_rxface);
+      policy_state = &pitcs->policy_state;
+      policy_vft = &pitcs->policy_vft;
+
+      if (face_dpo->dpoi_type == hicn_face_ip_type)
+       {
+         hicn_face_t *face = hicn_dpoi_get_from_idx (face_dpo->dpoi_index);
+         if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD)
+           {
+             hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+             policy_state = &prod_face->policy;
+             policy_vft = &prod_face->policy_vft;
+           }
+       }
+      policy_vft->hicn_cs_dequeue (pitcs, (*nodep), (*pcs_entryp),
+                                  policy_state);
+
+      /* Update the global CS counter */
+      pitcs->pcs_cs_count--;
+    }
+  hash_entry->locks--;
+  if (hash_entry->locks == 0)
+    {
+      hicn_pcs_delete_internal
+       (pitcs, pcs_entryp, hash_entry, nodep, vm, dpo_vft, hicn_dpo_id);
+    }
+  else
+    {
+      hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
+    }
+}
+
+always_inline int
+hicn_pcs_cs_insert (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                   hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                   hicn_hash_entry_t ** hash_entry, u64 hashval,
+                   u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs,
+                   u8 * hash_entry_id, u32 * bucket_id,
+                   u8 * bucket_is_overflow)
+{
+  ASSERT (entry == hicn_hashtb_node_data (node));
+
+  int ret =
+    hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval, node_id,
+                       dpo_ctx_id, vft_id, is_cs, hash_entry_id, bucket_id,
+                       bucket_is_overflow);
+
+  if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
+    {
+      hicn_cs_policy_t *policy_state;
+      hicn_cs_policy_vft_t *policy_vft;
+
+      dpo_id_t *face_dpo = (dpo_id_t *) & (entry->u.cs.cs_rxface);
+      policy_state = &pitcs->policy_state;
+      policy_vft = &pitcs->policy_vft;
+
+      if (face_dpo->dpoi_type == hicn_face_ip_type)
+       {
+         hicn_face_t *face = hicn_dpoi_get_from_idx (face_dpo->dpoi_index);
+         if (face->shared.flags & HICN_FACE_FLAGS_APPFACE_PROD)
+           {
+             hicn_face_prod_t *prod_face = (hicn_face_prod_t *) face->data;
+             policy_state = &prod_face->policy;
+             policy_vft = &prod_face->policy_vft;
+           }
+       }
+      policy_vft->hicn_cs_insert (pitcs, node, entry, policy_state);
+      pitcs->pcs_cs_count++;
+
+      if (policy_state->count > policy_state->max)
+       {
+         hicn_hash_node_t *node;
+         hicn_pcs_entry_t *pcs_entry;
+         hicn_hash_entry_t *hash_entry;
+         policy_vft->hicn_cs_delete_get (pitcs, policy_state,
+                                         &node, &pcs_entry, &hash_entry);
+
+         hicn_pcs_cs_delete (vm, pitcs, &pcs_entry, &node, hash_entry, NULL,
+                             NULL);
+       }
+    }
+  return ret;
+}
+
+/*
+ * Insert CS entry into the hashtable The main purpose of this wrapper is
+ * helping maintain the per-PIT stats.
+ */
+always_inline int
+hicn_pcs_cs_insert_update (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                          hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                          hicn_hash_entry_t ** hash_entry, u64 hashval,
+                          u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                          u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                          u8 * bucket_is_overflow)
+{
+  int ret;
+
+  ASSERT (entry == hicn_hashtb_node_data (node));
+
+  ret =
+    hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval, node_id,
+                       dpo_ctx_id, vft_id, is_cs, hash_entry_id, bucket_id,
+                       bucket_is_overflow);
+
+  /* A content already exists in CS with the same name */
+  if (ret == HICN_ERROR_HASHTB_EXIST)
+    {
+      /* Update the entry */
+      hicn_hash_node_t *existing_node =
+       hicn_hashtb_node_from_idx (pitcs->pcs_table, *node_id);
+      hicn_pcs_entry_t *pitp = hicn_pit_get_data (existing_node);
+
+      /* Free associated packet buffer and update counter */
+      pitcs->pcs_cs_dealloc++;
+      vlib_buffer_free_one (vm, pitp->u.cs.cs_pkt_buf);
+
+      pitp->shared.create_time = entry->shared.create_time;
+      pitp->shared.expire_time = entry->shared.expire_time;
+      pitp->u.cs.cs_pkt_buf = entry->u.cs.cs_pkt_buf;
+      hicn_pcs_cs_update (vm, pitcs, pitp, existing_node);
+    }
+  return (ret);
+}
+
+/*
+ * Insert PIT entry into the hashtable The main purpose of this wrapper is
+ * helping maintain the per-PIT stats.
+ */
+always_inline int
+hicn_pcs_pit_insert (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t * entry,
+                    hicn_hash_node_t * node, hicn_hash_entry_t ** hash_entry,
+                    u64 hashval, u32 * node_id, u8 * dpo_ctx_id, u8 * vft_id,
+                    u8 * is_cs, u8 * hash_entry_id, u32 * bucket_id,
+                    u8 * bucket_is_overflow)
+{
+  ASSERT (entry == hicn_hashtb_node_data (node));
+
+  int ret =
+    hicn_hashtb_insert (pitcs->pcs_table, node, hash_entry, hashval, node_id,
+                       dpo_ctx_id, vft_id, is_cs, hash_entry_id, bucket_id,
+                       bucket_is_overflow);
+
+  if (PREDICT_TRUE (ret == HICN_ERROR_NONE))
+    pitcs->pcs_pit_count++;
+
+  return ret;
+}
+
+always_inline void
+hicn_pcs_pit_delete (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                    hicn_hash_node_t ** node, vlib_main_t * vm,
+                    hicn_hash_entry_t * hash_entry,
+                    const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id)
+{
+  hash_entry->locks--;
+  pitcs->pcs_pit_count--;
+  if (hash_entry->locks == 0)
+    {
+      hicn_pcs_delete_internal
+       (pitcs, pcs_entryp, hash_entry, node, vm, dpo_vft, hicn_dpo_id);
+    }
+  else
+    {
+      hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
+    }
+}
+
+
+/* Generic functions for PIT/CS */
+
+/*
+ * Insert PIT/CS entry into the hashtable The main purpose of this wrapper is
+ * helping maintain the per-PIT stats.
+ */
+always_inline int
+hicn_pcs_insert (vlib_main_t * vm, hicn_pit_cs_t * pitcs,
+                hicn_pcs_entry_t * entry, hicn_hash_node_t * node,
+                hicn_hash_entry_t ** hash_entry, u64 hashval, u32 * node_id,
+                u8 * dpo_ctx_id, u8 * vft_id, u8 * is_cs, u8 * hash_entry_id,
+                u32 * bucket_id, u8 * bucket_is_overflow)
+{
+  int ret;
+
+  if ((*hash_entry)->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
+    {
+      ret =
+       hicn_pcs_cs_insert (vm, pitcs, entry, node, hash_entry, hashval,
+                           node_id, dpo_ctx_id, vft_id, is_cs, hash_entry_id,
+                           bucket_id, bucket_is_overflow);
+    }
+  else
+    {
+      ret =
+       hicn_pcs_pit_insert (pitcs, entry, node, hash_entry, hashval, node_id,
+                            dpo_ctx_id, vft_id, is_cs, hash_entry_id,
+                            bucket_id, bucket_is_overflow);
+    }
+
+  return (ret);
+}
+
+
+/*
+ * Delete entry if there are no pending lock on the entry, otherwise mark it
+ * as to delete.
+ */
+always_inline void
+hicn_pcs_delete (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                hicn_hash_node_t ** nodep, vlib_main_t * vm,
+                hicn_hash_entry_t * hash_entry,
+                const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id)
+{
+  /*
+   * If the entry has already been marked as deleted, it has already
+   * been dequeue
+   */
+  if (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_CS_ENTRY)
+    {
+      hicn_pcs_cs_delete (vm, pitcs, pcs_entryp, nodep, hash_entry,
+                         dpo_vft, hicn_dpo_id);
+    }
+  else
+    {
+      hicn_pcs_pit_delete (pitcs, pcs_entryp, nodep, vm,
+                          hash_entry, dpo_vft, hicn_dpo_id);
+    }
+}
+
+/*
+ * Remove a lock in the entry and delete it if there are no pending lock and
+ * the entry is marked as to be deleted
+ */
+always_inline void
+hicn_pcs_remove_lock (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                     hicn_hash_node_t ** node, vlib_main_t * vm,
+                     hicn_hash_entry_t * hash_entry,
+                     const hicn_dpo_vft_t * dpo_vft, dpo_id_t * hicn_dpo_id)
+{
+  hash_entry->locks--;
+  if (hash_entry->locks == 0
+      && (hash_entry->he_flags & HICN_HASH_ENTRY_FLAG_DELETED))
+    {
+      hicn_pcs_delete_internal
+       (pitcs, pcs_entryp, hash_entry, node, vm, dpo_vft, hicn_dpo_id);
+    }
+}
+
+/*
+ * Delete entry which has already been bulk-removed from lru list
+ */
+always_inline void
+hicn_cs_delete_trimmed (hicn_pit_cs_t * pitcs, hicn_pcs_entry_t ** pcs_entryp,
+                       hicn_hash_entry_t * hash_entry,
+                       hicn_hash_node_t ** node, vlib_main_t * vm)
+{
+
+
+  if (hash_entry->locks == 0)
+    {
+      const hicn_dpo_vft_t *dpo_vft = hicn_dpo_get_vft (hash_entry->vft_id);
+      dpo_id_t hicn_dpo_id =
+       { dpo_vft->hicn_dpo_get_type (), 0, 0, hash_entry->dpo_ctx_id };
+
+      hicn_pcs_delete_internal
+       (pitcs, pcs_entryp, hash_entry, node, vm, dpo_vft, &hicn_dpo_id);
+    }
+  else
+    {
+      hash_entry->he_flags |= HICN_HASH_ENTRY_FLAG_DELETED;
+    }
+}
+
+/*
+ * wrappable counter math (assumed uint16_t): return sum of addends
+ */
+always_inline u16
+hicn_infra_seq16_sum (u16 addend1, u16 addend2)
+{
+  return (addend1 + addend2);
+}
+
+/*
+ * for comparing wrapping numbers, return lt,eq,gt 0 for a lt,eq,gt b
+ */
+always_inline int
+hicn_infra_seq16_cmp (u16 a, u16 b)
+{
+  return ((int16_t) (a - b));
+}
+
+/*
+ * below are wrappers for lt, le, gt, ge seq16 comparators
+ */
+always_inline int
+hicn_infra_seq16_lt (u16 a, u16 b)
+{
+  return (hicn_infra_seq16_cmp (a, b) < 0);
+}
+
+always_inline int
+hicn_infra_seq16_le (u16 a, u16 b)
+{
+  return (hicn_infra_seq16_cmp (a, b) <= 0);
+}
+
+always_inline int
+hicn_infra_seq16_gt (u16 a, u16 b)
+{
+  return (hicn_infra_seq16_cmp (a, b) > 0);
+}
+
+always_inline int
+hicn_infra_seq16_ge (u16 a, u16 b)
+{
+  return (hicn_infra_seq16_cmp (a, b) >= 0);
+}
+
+
+extern u16 hicn_infra_fast_timer;      /* Counts at 1 second intervals */
+extern u16 hicn_infra_slow_timer;      /* Counts at 1 minute intervals */
+
+/*
+ * Utilities to convert lifetime into expiry time based on compressed clock,
+ * suitable for the opportunistic hashtable entry timeout processing.
+ */
+
+//convert time in msec to time in clicks
+always_inline u16
+hicn_infra_ms2clicks (u64 time_ms, u64 ms_per_click)
+{
+  f64 time_clicks =
+    ((f64) (time_ms + ms_per_click - 1)) / ((f64) ms_per_click);
+  return ((u16) time_clicks);
+}
+
+always_inline u16
+hicn_infra_get_fast_exp_time (u64 lifetime_ms)
+{
+  u16 lifetime_clicks =
+    hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_FAST_TIMER_MSECS);
+  return (hicn_infra_seq16_sum (hicn_infra_fast_timer, lifetime_clicks));
+}
+
+always_inline u16
+hicn_infra_get_slow_exp_time (u64 lifetime_ms)
+{
+  u16 lifetime_clicks =
+    hicn_infra_ms2clicks (lifetime_ms, HICN_INFRA_SLOW_TIMER_MSECS);
+  return (hicn_infra_seq16_sum (hicn_infra_slow_timer, lifetime_clicks));
+}
+
+#endif /* // __HICN_PCS_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/pg.c b/hicn-plugin/src/pg.c
new file mode 100755 (executable)
index 0000000..643aff2
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include "hicn.h"
+#include "pg.h"
+#include "parser.h"
+#include "infra.h"
+
+/* Registration struct for a graph node */
+vlib_node_registration_t hicn_pg_interest_node;
+vlib_node_registration_t hicn_pg_data_node;
+
+/* Stats, which end up called "error" even though they aren't... */
+#define foreach_hicnpg_error                                  \
+  _(PROCESSED, "hICN PG packets processed")                   \
+  _(DROPPED, "hICN PG packets dropped")                       \
+  _(INTEREST_MSGS_GENERATED, "hICN PG Interests generated")   \
+  _(CONTENT_MSGS_RECEIVED, "hICN PG Content msgs received")
+
+typedef enum
+{
+#define _(sym,str) HICNPG_ERROR_##sym,
+  foreach_hicnpg_error
+#undef _
+    HICNPG_N_ERROR,
+} hicnpg_error_t;
+
+static char *hicnpg_error_strings[] = {
+#define _(sym,string) string,
+  foreach_hicnpg_error
+#undef _
+};
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_INTEREST_NEXT_V4_LOOKUP,
+  HICNPG_INTEREST_NEXT_V6_LOOKUP,
+  HICNPG_INTEREST_NEXT_IFACE_IP4_INPUT,
+  HICNPG_INTEREST_NEXT_IFACE_IP6_INPUT,
+  HICNPG_INTEREST_NEXT_DROP,
+  HICNPG_N_NEXT,
+} hicnpg_interest_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} hicnpg_trace_t;
+
+hicnpg_main_t hicnpg_main = {
+  .index = (u32) 0,
+  .index_ifaces = (u32) 1,
+  .max_seq_number = (u32) ~ 0,
+  .interest_lifetime = 4,
+  .n_flows = (u32) 0,
+  .n_ifaces = (u32) 1,
+  .hicn_underneath = 0
+};
+
+hicnpg_server_main_t hicnpg_server_main = {
+  .node_index = 0,
+  .hicn_underneath = 0
+};
+
+/* packet trace format function */
+static u8 *
+format_hicnpg_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 *);
+  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
+
+  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, (int) t->msg_type,
+             t->sw_if_index, t->next_index);
+  return (s);
+}
+
+always_inline void
+hicn_rewrite_interestv4 (vlib_main_t * vm, vlib_buffer_t * b0, u32 seq_number,
+                        u16 lifetime, u32 next_flow, u32 iface);
+
+always_inline void
+hicn_rewrite_interestv6 (vlib_main_t * vm, vlib_buffer_t * b0, u32 seq_number,
+                        u16 lifetime, u32 next_flow, u32 iface);
+
+always_inline void
+convert_interest_to_data_v4 (vlib_main_t * vm, vlib_buffer_t * b0,
+                            vlib_buffer_t * rb, u32 bi0);
+
+always_inline void
+convert_interest_to_data_v6 (vlib_main_t * vm, vlib_buffer_t * b0,
+                            vlib_buffer_t * rb, u32 bi0);
+
+always_inline void
+calculate_tcp_checksum_v4 (vlib_main_t * vm, vlib_buffer_t * b0);
+
+always_inline void
+calculate_tcp_checksum_v6 (vlib_main_t * vm, vlib_buffer_t * b0);
+/*
+ * Node function for the icn packet-generator client. The goal here is to
+ * manipulate/tweak a stream of packets that have been injected by the vpp
+ * packet generator to generate icn request traffic.
+ */
+static uword
+hicnpg_client_interest_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                               vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicnpg_interest_next_t next_index;
+  u32 pkts_processed = 0, pkts_dropped = 0;
+  u32 interest_msgs_generated = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 0, msg_type1 = 0;
+  hicn_header_t *hicn0 = NULL, *hicn1 = NULL;
+  hicn_name_t name0, name1;
+  u16 namelen0, namelen1;
+  hicnpg_main_t *hpgm = &hicnpg_main;
+  int iface = 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 = HICNPG_INTEREST_NEXT_DROP;
+         u32 next1 = HICNPG_INTEREST_NEXT_DROP;
+         u32 sw_if_index0 = ~0, sw_if_index1 = ~0;
+         u8 isv6_0;
+         u8 isv6_1;
+
+         /* 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, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+         /* Check icn packets, locate names */
+         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, &isv6_0)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+             /* Rewrite and send */
+             isv6_0 ? hicn_rewrite_interestv6 (vm, b0,
+                                               (hpgm->index /
+                                                hpgm->n_flows) %
+                                               hpgm->max_seq_number,
+                                               hpgm->interest_lifetime,
+                                               hpgm->index % hpgm->n_flows,
+                                               iface) :
+               hicn_rewrite_interestv4 (vm, b0,
+                                        (hpgm->index / hpgm->n_flows) %
+                                        hpgm->max_seq_number,
+                                        hpgm->interest_lifetime,
+                                        hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next0 =
+               isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+               HICNPG_INTEREST_NEXT_V4_LOOKUP;
+             next0 += 2 * hpgm->hicn_underneath;
+           }
+         if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1, &isv6_1)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+             /* Rewrite and send */
+             isv6_1 ? hicn_rewrite_interestv6 (vm, b1,
+                                               (hpgm->index /
+                                                hpgm->n_flows) %
+                                               hpgm->max_seq_number,
+                                               hpgm->interest_lifetime,
+                                               hpgm->index % hpgm->n_flows,
+                                               iface) :
+               hicn_rewrite_interestv4 (vm, b1,
+                                        (hpgm->index / hpgm->n_flows) %
+                                        hpgm->max_seq_number,
+                                        hpgm->interest_lifetime,
+                                        hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next1 =
+               isv6_1 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+               HICNPG_INTEREST_NEXT_V4_LOOKUP;
+             next1 += 2 * hpgm->hicn_underneath;
+           }
+         /* Send pkt to next node */
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+         vnet_buffer (b1)->sw_if_index[VLIB_TX] = ~0;
+
+         pkts_processed += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+         if (next0 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         if (next1 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * 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 next0 = HICNPG_INTEREST_NEXT_DROP;
+         u32 sw_if_index0;
+         u8 isv6_0;
+
+         /* 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         /* Check icn packets, locate names */
+         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, &isv6_0)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+
+             /* Increment the appropriate message counter */
+             interest_msgs_generated++;
+
+             iface = (hpgm->index_ifaces % hpgm->n_ifaces);
+
+             /* Rewrite and send */
+             isv6_0 ? hicn_rewrite_interestv6 (vm, b0,
+                                               (hpgm->index /
+                                                hpgm->n_flows) %
+                                               hpgm->max_seq_number,
+                                               hpgm->interest_lifetime,
+                                               hpgm->index % hpgm->n_flows,
+                                               iface) :
+               hicn_rewrite_interestv4 (vm, b0,
+                                        (hpgm->index / hpgm->n_flows) %
+                                        hpgm->max_seq_number,
+                                        hpgm->interest_lifetime,
+                                        hpgm->index % hpgm->n_flows, iface);
+
+             hpgm->index_ifaces++;
+             if (iface == (hpgm->n_ifaces - 1))
+               hpgm->index++;
+
+             next0 =
+               isv6_0 ? HICNPG_INTEREST_NEXT_V6_LOOKUP :
+               HICNPG_INTEREST_NEXT_V4_LOOKUP;
+             next0 += 2 * hpgm->hicn_underneath;
+           }
+         /* Send pkt to ip lookup */
+         vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicnpg_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         pkts_processed += 1;
+
+         if (next0 == HICNPG_INTEREST_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * 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);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_DROPPED, pkts_dropped);
+  vlib_node_increment_counter (vm, hicn_pg_interest_node.index,
+                              HICNPG_ERROR_INTEREST_MSGS_GENERATED,
+                              interest_msgs_generated);
+
+  return (frame->n_vectors);
+}
+
+void
+hicn_rewrite_interestv4 (vlib_main_t * vm, vlib_buffer_t * b0, u32 seq_number,
+                        u16 interest_lifetime, u32 next_flow, u32 iface)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Generate the right src and dst corresponding to flow and iface */
+  ip46_address_t src_addr = {
+    .ip4 = hicnpg_main.pgen_clt_src_addr.ip4,
+  };
+  hicn_name_t dst_name = {
+    .ip4.prefix_as_ip4 = hicnpg_main.pgen_clt_hicn_name.ip4,
+    .ip4.suffix = seq_number,
+  };
+
+  src_addr.ip4.as_u32 += clib_host_to_net_u32 (iface);
+  dst_name.ip4.prefix_as_ip4.as_u32 += clib_net_to_host_u32 (next_flow);
+
+  /* Update locator and name */
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  HICN_OPS4->set_interest_locator (type, &h0->protocol, &src_addr);
+  HICN_OPS4->set_interest_name (type, &h0->protocol, &dst_name);
+
+  /* Update lifetime  (currently L4 checksum is not updated) */
+  HICN_OPS4->set_lifetime (type, &h0->protocol, interest_lifetime);
+
+  /* Update checksums */
+  HICN_OPS4->update_checksums (type, &h0->protocol, 0, 0);
+}
+
+/**
+ * @brief Rewrite the IPv6 header as the next generated packet
+ *
+ * Set up a name prefix
+ *  - etiher generate interest in which the name varies only after the prefix
+ *  (inc : seq_number), then the flow acts on the prefix (CHECK)
+ *  seq_number => TCP, FLOW =>
+ *
+ *  SRC : pgen_clt_src_addr.ip6 DST = generate name (pgen_clt_hicn_name.ip6)
+ *  ffff:ffff:ffff:ffff         ffff:ffff:ffff:ffff
+ *                 \__/                        \__/
+ *                 +iface                      + flow
+ *  Source is used to emulate different consumers.
+ *    FIXME iface is ill-named, better name it consumer id
+ *  Destination is used to iterate on the content.
+ */
+void
+hicn_rewrite_interestv6 (vlib_main_t * vm, vlib_buffer_t * b0, u32 seq_number,
+                        u16 interest_lifetime, u32 next_flow, u32 iface)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Generate the right src and dst corresponding to flow and iface */
+  ip46_address_t src_addr = {
+    .ip6 = hicnpg_main.pgen_clt_src_addr.ip6,
+  };
+  hicn_name_t dst_name = {
+    .ip6.prefix_as_ip6 = hicnpg_main.pgen_clt_hicn_name.ip6,
+    .ip6.suffix = seq_number,
+  };
+  src_addr.ip6.as_u32[3] += clib_host_to_net_u32 (iface);
+  dst_name.ip6.prefix_as_ip6.as_u32[3] += clib_net_to_host_u32 (next_flow);
+
+  /* Update locator and name */
+  hicn_type_t type = hicn_get_buffer (b0)->type;
+  HICN_OPS6->set_interest_locator (type, &h0->protocol, &src_addr);
+  HICN_OPS6->set_interest_name (type, &h0->protocol, &dst_name);
+
+  /* Update lifetime */
+  HICN_OPS6->set_lifetime (type, &h0->protocol, interest_lifetime);
+
+  /* Update checksums */
+  calculate_tcp_checksum_v6 (vm, b0);
+}
+
+
+
+void
+calculate_tcp_checksum_v4 (vlib_main_t * vm, vlib_buffer_t * b0)
+{
+  ip4_header_t *ip0;
+  tcp_header_t *tcp0;
+  ip_csum_t sum0;
+  u32 tcp_len0;
+
+  ip0 = (ip4_header_t *) (vlib_buffer_get_current (b0));
+  tcp0 =
+    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip4_header_t));
+  tcp_len0 = clib_net_to_host_u16 (ip0->length) - sizeof (ip4_header_t);
+
+  /* Initialize checksum with header. */
+  if (BITS (sum0) == 32)
+    {
+      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
+      sum0 =
+       ip_csum_with_carry (sum0,
+                           clib_mem_unaligned (&ip0->dst_address, u32));
+    }
+  else
+    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
+
+  sum0 = ip_csum_with_carry
+    (sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
+
+  /* Invalidate possibly old checksum. */
+  tcp0->checksum = 0;
+
+  u32 tcp_offset = sizeof (ip4_header_t);
+  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+
+  tcp0->checksum = ~ip_csum_fold (sum0);
+}
+
+void
+calculate_tcp_checksum_v6 (vlib_main_t * vm, vlib_buffer_t * b0)
+{
+  ip6_header_t *ip0;
+  tcp_header_t *tcp0;
+  ip_csum_t sum0;
+  u32 tcp_len0;
+
+  ip0 = (ip6_header_t *) (vlib_buffer_get_current (b0));
+  tcp0 =
+    (tcp_header_t *) (vlib_buffer_get_current (b0) + sizeof (ip6_header_t));
+  tcp_len0 = clib_net_to_host_u16 (ip0->payload_length);
+
+  /* Initialize checksum with header. */
+  if (BITS (sum0) == 32)
+    {
+      sum0 = clib_mem_unaligned (&ip0->src_address, u32);
+      sum0 =
+       ip_csum_with_carry (sum0,
+                           clib_mem_unaligned (&ip0->dst_address, u32));
+    }
+  else
+    sum0 = clib_mem_unaligned (&ip0->src_address, u64);
+
+  sum0 = ip_csum_with_carry
+    (sum0, clib_host_to_net_u32 (tcp_len0 + (ip0->protocol << 16)));
+
+  /* Invalidate possibly old checksum. */
+  tcp0->checksum = 0;
+
+  u32 tcp_offset = sizeof (ip6_header_t);
+  sum0 = ip_incremental_checksum_buffer (vm, b0, tcp_offset, tcp_len0, sum0);
+
+  tcp0->checksum = ~ip_csum_fold (sum0);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_pg_interest_node) ={
+  .function = hicnpg_client_interest_node_fn,
+  .name = "hicnpg-interest",
+  .vector_size = sizeof(u32),
+  .format_trace = format_hicnpg_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicnpg_error_strings),
+  .error_strings = hicnpg_error_strings,
+  .n_next_nodes = HICNPG_N_NEXT,
+  .next_nodes =
+  {
+    [HICNPG_INTEREST_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICNPG_INTEREST_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICNPG_INTEREST_NEXT_IFACE_IP4_INPUT] = "hicn-iface-ip4-input",
+    [HICNPG_INTEREST_NEXT_IFACE_IP6_INPUT] = "hicn-iface-ip6-input",
+    [HICNPG_INTEREST_NEXT_DROP] = "error-drop"
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_DATA_NEXT_DROP,
+  HICNPG_DATA_N_NEXT,
+} hicnpg_data_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} icnpg_data_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_hicnpg_data_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 *);
+  hicnpg_trace_t *t = va_arg (*args, hicnpg_trace_t *);
+
+  s = format (s, "HICNPG: pkt: %d, msg %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, (int) t->msg_type,
+             t->sw_if_index, t->next_index);
+  return (s);
+}
+
+
+/*
+ * Node function for the icn packet-generator client. The goal here is to
+ * manipulate/tweak a stream of packets that have been injected by the vpp
+ * packet generator to generate icn request traffic.
+ */
+static uword
+hicnpg_client_data_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+                           vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  hicnpg_data_next_t next_index;
+  u32 pkts_processed = 0;
+  u32 content_msgs_received = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 1, msg_type1 = 1;
+
+  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 = HICNPG_DATA_NEXT_DROP;
+         u32 next1 = HICNPG_DATA_NEXT_DROP;
+         u32 sw_if_index0, sw_if_index1;
+
+         /* 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, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+         /* Increment a counter */
+         content_msgs_received += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 icnpg_data_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 icnpg_data_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+         pkts_processed += 2;
+       }
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         u32 next0 = HICNPG_DATA_NEXT_DROP;
+         u32 sw_if_index0;
+
+         /* 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+         /* Increment a counter */
+         content_msgs_received++;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             icnpg_data_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         pkts_processed++;
+       }
+      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
+                              HICNPG_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_data_node.index,
+                              HICNPG_ERROR_CONTENT_MSGS_RECEIVED,
+                              content_msgs_received);
+  return (frame->n_vectors);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_pg_data_node) =
+{
+  .function = hicnpg_client_data_node_fn,
+  .name = "hicnpg-data",
+  .vector_size = sizeof(u32),
+  .format_trace = format_hicnpg_data_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(hicnpg_error_strings),
+  .error_strings = hicnpg_error_strings,
+  .n_next_nodes = HICNPG_DATA_N_NEXT,
+  .next_nodes =
+  {
+    [HICNPG_DATA_NEXT_DROP] = "error-drop"
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * End of packet-generator client node
+ */
+
+/*
+ * Beginning of packet-generation server node
+ */
+
+/* Registration struct for a graph node */
+vlib_node_registration_t hicn_pg_server_node;
+
+/* Stats, which end up called "error" even though they aren't... */
+#define foreach_icnpg_server_error             \
+_(PROCESSED, "hICN PG Server packets processed")       \
+_(DROPPED, "hICN PG Server packets dropped")
+
+typedef enum
+{
+#define _(sym,str) HICNPG_SERVER_ERROR_##sym,
+  foreach_icnpg_server_error
+#undef _
+    HICNPG_SERVER_N_ERROR,
+} icnpg_server_error_t;
+
+static char *icnpg_server_error_strings[] = {
+#define _(sym,string) string,
+  foreach_icnpg_server_error
+#undef _
+};
+
+/*
+ * Next graph nodes, which reference the list in the actual registration
+ * block below
+ */
+typedef enum
+{
+  HICNPG_SERVER_NEXT_V4_LOOKUP,
+  HICNPG_SERVER_NEXT_V6_LOOKUP,
+  HICNPG_SERVER_NEXT_FACE_IP4_INPUT,
+  HICNPG_SERVER_NEXT_FACE_IP6_INPUT,
+  HICNPG_SERVER_NEXT_DROP,
+  HICNPG_SERVER_N_NEXT,
+} icnpg_server_next_t;
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+  u16 msg_type;
+} hicnpg_server_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_icnpg_server_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 *);
+  hicnpg_server_trace_t *t = va_arg (*args, hicnpg_server_trace_t *);
+
+  s =
+    format (s,
+           "HICNPG SERVER: pkt: %d, msg %d, sw_if_index %d, next index %d",
+           (int) t->pkt_type, (int) t->msg_type, t->sw_if_index,
+           t->next_index);
+  return (s);
+}
+
+/*
+ * Node function for the icn packet-generator server.
+ */
+static uword
+hicnpg_node_server_fn (vlib_main_t * vm,
+                      vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  u32 n_left_from, *from, *to_next;
+  icnpg_server_next_t next_index;
+  u32 pkts_processed = 0, pkts_dropped = 0;
+  u32 bi0, bi1;
+  vlib_buffer_t *b0, *b1;
+  u8 pkt_type0 = 0, pkt_type1 = 0;
+  u16 msg_type0 = 0, msg_type1 = 0;
+  hicn_header_t *hicn0 = NULL, *hicn1 = NULL;
+  hicn_name_t name0, name1;
+  u16 namelen0, namelen1;
+
+  hicnpg_server_main_t *hpgsm = &hicnpg_server_main;
+
+  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 = HICNPG_SERVER_NEXT_DROP;
+         u32 next1 = HICNPG_SERVER_NEXT_DROP;
+         u8 isv6_0 = 0;
+         u8 isv6_1 = 0;
+         u32 sw_if_index0, sw_if_index1;
+
+         /* 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, (2 * CLIB_CACHE_LINE_BYTES), STORE);
+           CLIB_PREFETCH (p3->data, (2 * 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+         sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, &isv6_0)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
+
+             isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb,
+                                                   bi0) :
+               convert_interest_to_data_v4 (vm, b0, rb, bi0);
+
+             next0 =
+               isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+               HICNPG_SERVER_NEXT_V4_LOOKUP;
+             /* if hicn_underneath ,the following will results as next0 = HICNPG_SERVER_NEXT_DATA_LOOKUP */
+             next0 += 2 * hpgsm->hicn_underneath;
+           }
+         if (hicn_interest_parse_pkt (b1, &name1, &namelen1, &hicn1, &isv6_1)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
+
+             isv6_1 ? convert_interest_to_data_v6 (vm, b1, rb,
+                                                   bi1) :
+               convert_interest_to_data_v4 (vm, b1, rb, bi1);
+
+             next1 =
+               isv6_1 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+               HICNPG_SERVER_NEXT_V4_LOOKUP;
+             /* if hicn_underneath ,the following will results as next0 = HICNPG_SERVER_NEXT_DATA_LOOKUP */
+             next1 += 2 * hpgsm->hicn_underneath;
+           }
+         pkts_processed += 2;
+
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+           {
+             if (b0->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_server_trace_t *t =
+                   vlib_add_trace (vm, node, b0, sizeof (*t));
+                 t->pkt_type = pkt_type0;
+                 t->msg_type = msg_type0;
+                 t->sw_if_index = sw_if_index0;
+                 t->next_index = next0;
+               }
+             if (b1->flags & VLIB_BUFFER_IS_TRACED)
+               {
+                 hicnpg_server_trace_t *t =
+                   vlib_add_trace (vm, node, b1, sizeof (*t));
+                 t->pkt_type = pkt_type1;
+                 t->msg_type = msg_type1;
+                 t->sw_if_index = sw_if_index1;
+                 t->next_index = next1;
+               }
+           }
+         if (next0 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         if (next1 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * 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 next0 = HICNPG_SERVER_NEXT_DROP;
+         u32 sw_if_index0 = ~0;
+         u8 isv6_0 = 0;
+
+         /* 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);
+
+         sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+
+
+         if (hicn_interest_parse_pkt (b0, &name0, &namelen0, &hicn0, &isv6_0)
+             == HICN_ERROR_NONE)
+           {
+             /* this node grabs only interests */
+             vlib_buffer_t *rb = NULL;
+             rb = vlib_get_buffer (vm, hpgsm->pgen_svr_buffer_idx);
+
+             isv6_0 ? convert_interest_to_data_v6 (vm, b0, rb,
+                                                   bi0) :
+               convert_interest_to_data_v4 (vm, b0, rb, bi0);
+
+             next0 =
+               isv6_0 ? HICNPG_SERVER_NEXT_V6_LOOKUP :
+               HICNPG_SERVER_NEXT_V4_LOOKUP;
+             /* if hicn_underneath ,the following will results as next0 = HICNPG_SERVER_NEXT_DATA_LOOKUP */
+             next0 += 2 * hpgsm->hicn_underneath;
+           }
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+                            && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicnpg_server_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = pkt_type0;
+             t->msg_type = msg_type0;
+             t->sw_if_index = sw_if_index0;
+             t->next_index = next0;
+           }
+         pkts_processed += 1;
+
+         if (next0 == HICNPG_SERVER_NEXT_DROP)
+           {
+             pkts_dropped++;
+           }
+         /*
+          * 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);
+    }
+
+  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
+                              HICNPG_SERVER_ERROR_PROCESSED, pkts_processed);
+  vlib_node_increment_counter (vm, hicn_pg_server_node.index,
+                              HICNPG_SERVER_ERROR_DROPPED, pkts_dropped);
+
+  return (frame->n_vectors);
+}
+
+void
+convert_interest_to_data_v4 (vlib_main_t * vm, vlib_buffer_t * b0,
+                            vlib_buffer_t * rb, u32 bi0)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Get the packet length */
+  u16 pkt_len = clib_net_to_host_u16 (h0->v4.ip.len);
+
+  /*
+   * Rule of thumb: We want the size of the IP packet to be <= 1500 bytes
+   */
+  u16 bytes_to_copy = rb->current_length;
+  if ((bytes_to_copy + pkt_len) > 1500)
+    {
+      bytes_to_copy = 1500 - pkt_len;
+    }
+  /* Add content to the data packet */
+  vlib_buffer_add_data (vm,
+                       VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX, &bi0,
+                       rb->data, bytes_to_copy);
+
+  b0 = vlib_get_buffer (vm, bi0);
+
+  h0 = vlib_buffer_get_current (b0);
+
+  ip4_address_t src_addr = h0->v4.ip.saddr;
+  h0->v4.ip.saddr = h0->v4.ip.daddr;
+  h0->v4.ip.daddr = src_addr;
+
+  h0->v4.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+  h0->v4.ip.csum = ip4_header_checksum ((ip4_header_t *) & (h0->v4.ip));
+  calculate_tcp_checksum_v4 (vm, b0);
+}
+
+void
+convert_interest_to_data_v6 (vlib_main_t * vm, vlib_buffer_t * b0,
+                            vlib_buffer_t * rb, u32 bi0)
+{
+  hicn_header_t *h0 = vlib_buffer_get_current (b0);
+
+  /* Get the packet length */
+  uint16_t pkt_len =
+    clib_net_to_host_u16 (h0->v6.ip.len) + sizeof (ip6_header_t);
+
+  /*
+   * Figure out how many bytes we can add to the content
+   *
+   * Rule of thumb: We want the size of the IP packet to be <= 1400 bytes
+   */
+  u16 bytes_to_copy = rb->current_length;
+  if ((bytes_to_copy + pkt_len) > 1500)
+    {
+      bytes_to_copy = 1500 - pkt_len;
+    }
+  /* Add content to the data packet */
+  vlib_buffer_add_data (vm,
+                       VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX, &bi0,
+                       rb->data, bytes_to_copy);
+
+  b0 = vlib_get_buffer (vm, bi0);
+
+  h0 = vlib_buffer_get_current (b0);
+  ip6_address_t src_addr = h0->v6.ip.saddr;
+  h0->v6.ip.saddr = h0->v6.ip.daddr;
+  h0->v6.ip.daddr = src_addr;
+
+  h0->v6.ip.len = clib_host_to_net_u16 (vlib_buffer_length_in_chain
+                                       (vm, b0) - sizeof (ip6_header_t));
+  h0->v6.tcp.data_offset_and_reserved |= 0x0f;
+  h0->v6.tcp.urg_ptr = htons (0xffff);
+
+  calculate_tcp_checksum_v6 (vm, b0);
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE(hicn_pg_server_node) =
+{
+  .function = hicnpg_node_server_fn,
+  .name = "hicnpg-server",
+  .vector_size = sizeof(u32),
+  .format_trace = format_icnpg_server_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN(icnpg_server_error_strings),
+  .error_strings = icnpg_server_error_strings,
+  .n_next_nodes = HICNPG_SERVER_N_NEXT,
+  /* edit / add dispositions here */
+  .next_nodes =
+  {  
+    [HICNPG_SERVER_NEXT_V4_LOOKUP] = "ip4-lookup",
+    [HICNPG_SERVER_NEXT_V6_LOOKUP] = "ip6-lookup",
+    [HICNPG_SERVER_NEXT_FACE_IP4_INPUT] = "hicn-face-ip4-input",
+    [HICNPG_SERVER_NEXT_FACE_IP6_INPUT] = "hicn-face-ip6-input",
+    [HICNPG_SERVER_NEXT_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * End of packet-generator server node
+ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/pg.h b/hicn-plugin/src/pg.h
new file mode 100755 (executable)
index 0000000..083afb6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_PG_H__
+#define __HICN_PG_H__
+
+/* Subnet-mask for punting data in the client node */
+#define SUBNET_MASK4 32
+#define SUBNET_MASK6 128
+
+typedef struct hicnpg_main_s
+{
+  u32 index;
+  u32 index_ifaces;
+  u32 max_seq_number;
+  u32 n_flows;
+  u32 n_ifaces;
+  u32 hicn_underneath;
+  ip46_address_t pgen_clt_src_addr;
+  ip46_address_t pgen_clt_hicn_name;
+  u16 interest_lifetime;
+} hicnpg_main_t;
+
+extern hicnpg_main_t hicnpg_main;
+
+typedef struct hicnpg_server_main_s
+{
+  u32 node_index;
+  u32 hicn_underneath;
+  /* Arbitrary content */
+  u32 pgen_svr_buffer_idx;
+} hicnpg_server_main_t;
+
+extern hicnpg_server_main_t hicnpg_server_main;
+
+#endif // __HICN_PG_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/punt.c b/hicn-plugin/src/punt.c
new file mode 100755 (executable)
index 0000000..ea553bf
--- /dev/null
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdarg.h>
+#include <stddef.h>            // offsetof()
+#include <inttypes.h>
+#include <vlib/vlib.h>
+#include <vppinfra/error.h>
+#include <vnet/ip/format.h>
+#include <vnet/classify/in_out_acl.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/ethernet/packet.h>
+#include <vlib/global_funcs.h>
+#include <hicn/hicn.h>
+
+#include "hicn.h"
+#include "infra.h"
+#include "parser.h"
+#include "mgmt.h"
+#include "punt.h"
+#include "error.h"
+#include "route.h"
+
+/* Those are not static as they are used for pgen in hicn_cli.c */
+ip_version_t ipv4 = {
+  .tbl = (u32 *) hicn_punt_glb.ip4_vnet_tbl_idx,
+  .addr_len_bits = IPV4_ADDR_LEN_BITS,
+  .protocol_field = &ipv4_protocol,
+  .version_field = &ipv4_version,
+  .ip_version = 0x40,
+};
+
+ip_version_t ipv6 = {
+  .tbl = (u32 *) hicn_punt_glb.ip6_vnet_tbl_idx,
+  .addr_len_bits = IPV6_ADDR_LEN_BITS,
+  .protocol_field = &ipv6_protocol,
+  .version_field = &ipv6_version,
+  .ip_version = 0x60,
+};
+
+ip_version_t ipv44 = {
+  .tbl = (u32 *) hicn_punt_glb.udp44_vnet_tbl_idx,
+  .addr_len_bits = IPV4_ADDR_LEN_BITS,
+  .protocol_field = &udp4_protocol,
+  .udp_sport = &udp4_sport,
+  .udp_dport = &udp4_dport,
+  .ip_version = 0x40,
+};
+
+ip_version_t ipv64 = {
+  .tbl = (u32 *) hicn_punt_glb.udp64_vnet_tbl_idx,
+  .addr_len_bits = IPV4_ADDR_LEN_BITS,
+  .protocol_field = &udp6_protocol,
+  .udp_sport = &udp6_sport,
+  .udp_dport = &udp6_dport,
+  .ip_version = 0x60,
+};
+
+ip_version_t ipv46 = {
+  .tbl = (u32 *) hicn_punt_glb.udp46_vnet_tbl_idx,
+  .addr_len_bits = IPV6_ADDR_LEN_BITS,
+  .protocol_field = &udp4_protocol,
+  .udp_sport = &udp4_sport,
+  .udp_dport = &udp4_dport,
+  .ip_version = 0x40,
+};
+
+ip_version_t ipv66 = {
+  .tbl = (u32 *) hicn_punt_glb.udp66_vnet_tbl_idx,
+  .addr_len_bits = IPV6_ADDR_LEN_BITS,
+  .protocol_field = &udp6_protocol,
+  .udp_sport = &udp6_sport,
+  .udp_dport = &udp6_dport,
+  .ip_version = 0x60,
+};
+
+#define _(NAME, BASE, LAYER, FIELD, PUNT_ID)          \
+    field_t NAME = {                     \
+        .offset = BASE + offsetof(LAYER, FIELD),       \
+        .len = STRUCT_SIZE_OF(LAYER, FIELD),       \
+        .punt_id = PUNT_ID,                     \
+    };
+foreach_field
+#undef _
+/*
+ * In the latest version, we let faces direct the traffic towards Interest
+ * processing, or MAP-Me nodes. Punting should only make sure that the ICMP
+ * packets are also sent to the face node. We added the following defines to
+ * determine the next node to send punted packets. Ideally we might remove
+ * protocol number check from punting rule.
+ */
+#define NEXT_MAPME_CTRL4 hicn_punt_glb.next_hit_interest_ipv4
+#define NEXT_MAPME_ACK4 hicn_punt_glb.next_hit_data_ipv4
+#define NEXT_MAPME_CTRL6 hicn_punt_glb.next_hit_interest_ipv6
+#define NEXT_MAPME_ACK6 hicn_punt_glb.next_hit_data_ipv6
+
+/* Maximum number of vector allowed in match. Value hardcoded in vnet_classify_hash_packet_inline in vnet_classify.h */
+#define MAX_MATCH_SIZE 5
+/**
+ * HICN global Punt Info
+ *
+ *
+ *
+ */
+hicn_punt_glb_t hicn_punt_glb;
+
+/**
+ * We use the function build_bit_array to populate an initially empty buffer
+ * with masks/values for the parts of the packet to match. The function also
+ * returns the correct skip and match values to pass to vnet_classify_*, which
+ * are the number of vectors to skip/match during classification (they should be
+ * multiples of vector size = CLASSIFIER_VECTOR_SIZE).
+ *
+ * offsets:
+ * 0         14     offsetof(IP_HDR, SRC)
+ * |          |    /
+ * +----------+----+-------+-------+----+-...
+ * |   ETH    | IP .  src  .  dst  .    |
+ * +----------+----+-------+-------+----+-...
+ * |            |                   |
+ * |<- skip=1 ->|<--- match=2/3 --->|
+ *
+ *
+ */
+
+/**
+ * The following section defines a couple of protocol fields that we will use
+ * for creating the buffer. We retrieve the offset and length on those fields
+ * based on the (portable) header struct aliases defined in libhicn.
+ *
+ * In the foreach_field macro, the punt_id field is used as convenience as we
+ * will have to create different classifier tables based on whether we punt
+ * interests (on dst) or data (on src). It is undefined (NA) otherwise.
+ */
+
+#define NA 0
+
+
+/**
+ * @brief Create a bitmask from mask length.
+ * @param mask [in] mask length (in bits)
+ * @param buffer [out] output buffer
+ * @param len [out] output buffer length
+ */
+static void
+build_ip_address_mask (u8 mask, u8 * buffer, u32 len)
+{
+  u32 hi_bytes = mask / 8;
+  u32 hi_bits = mask % 8;
+  u8 byte_mask = 0xff;
+
+  /*
+   * memset buffer with 0xff in case of IPV6 16 bytes will be used for
+   * match
+   */
+  memset (buffer, 0, len);
+  //might not be needed if buffer is already 0 'ed XXX
+  memset (buffer, 0xff, hi_bytes);
+  if (hi_bits != 0)
+    {
+      for (int i = 0; i < (8 - hi_bits); i++)
+       byte_mask = byte_mask << 1;
+      buffer[hi_bytes] = byte_mask;
+    }
+}
+
+#define CEIL_DIV(x, y) (1 + ((x - 1) / y))
+
+/**
+ * @brief Create a bit array from field/value list
+ * @param buffer [out] output buffer
+ * @param len [out] output buffer length
+ * @param skip [out] number of CLASSIFIER_VECTOR to skip
+ * @param match [out] number of CLASSIFIER_VECTOR to match
+ * @param ... [in] list of [field_t *, value] * used to populate buffer
+ */
+static int
+build_bit_array (u8 * buffer, u32 len, u32 base_offset, u32 * skip,
+                u32 * match, va_list vl)
+{
+  u8 min = len, max = 0;
+  field_t *field;
+  u8 *value;
+  int pos;
+  int count = 0;
+
+  /* Clear buffer */
+  memset (buffer, 0, len);
+
+  for (;;)
+    {
+      count++;
+      field = va_arg (vl, field_t *);
+      if (!field)
+       break;
+
+      /* Check that the field belongs to the reserved buffer */
+      if (field->offset + field->len > len)
+       goto ERR_PUNT;
+
+      /*
+       * Copy the value of the field inside the buffer at the
+       * correct offset
+       */
+      pos = base_offset + field->offset;
+      value = va_arg (vl, u8 *);
+      memcpy (buffer + pos, value, field->len);
+      if (min > pos)
+       min = pos;
+      if (max < pos + field->len)
+       max = pos + field->len;
+    }
+
+  /* We can skip multiples of the vector match */
+  *skip = min / CLASSIFIER_VECTOR_SIZE;
+  *match = CEIL_DIV (max, CLASSIFIER_VECTOR_SIZE) - *skip;
+
+  if (*match > MAX_MATCH_SIZE)
+    *match = MAX_MATCH_SIZE;
+
+  return HICN_ERROR_NONE;
+
+ERR_PUNT:
+  *skip = 0;
+  *match = 0;
+  return HICN_ERROR_PUNT_INVAL;
+}
+
+void
+update_table4_index (u32 intfc, u32 table_index)
+{
+  vnet_classify_main_t *cm = &vnet_classify_main;
+
+  if (hicn_punt_glb.head_ip4[intfc] == ~0)
+    hicn_punt_glb.head_ip4[intfc] = table_index;
+
+  /* Update the table in tail to poin to this */
+  if (hicn_punt_glb.tail_ip4[intfc] != ~0)
+    {
+      vnet_classify_table_t *t =
+       pool_elt_at_index (cm->tables, hicn_punt_glb.tail_ip4[intfc]);
+      t->next_table_index = table_index;
+    }
+  hicn_punt_glb.tail_ip4[intfc] = table_index;
+}
+
+void
+update_table6_index (u32 intfc, u32 table_index)
+{
+  vnet_classify_main_t *cm = &vnet_classify_main;
+
+  if (hicn_punt_glb.head_ip6[intfc] == ~0)
+    hicn_punt_glb.head_ip6[intfc] = table_index;
+
+  /* Update the table in tail to poin to this */
+  if (hicn_punt_glb.tail_ip6[intfc] != ~0)
+    {
+      vnet_classify_table_t *t =
+       pool_elt_at_index (cm->tables, hicn_punt_glb.tail_ip6[intfc]);
+      t->next_table_index = table_index;
+    }
+  hicn_punt_glb.tail_ip6[intfc] = table_index;
+}
+
+/**
+ * @brief Add or remove a vnet table matching the list of fields/values passed
+ * as parameters.
+ *
+ * @param punt_id Storage identifier (HICN_PUNT_SRC | HICN_PUNT_DST)
+ * @param mask Subnet mask to match in the table
+ * @param next_tbl_index next table to match in case of miss
+ * @param intfc Interface identifier
+ * @param is_add 1 if the table must be created, 0 if removed
+ * @param ... list of (field_t, value) to be matched
+ *
+ * @result Returns:
+ *    HICN_ERROR_TBL_EXIST if is_add == 1 and a table for the same mask
+ *      already exists,
+ *    HICN_ERROR_TBL_NOT_FOUND if is_add == 0 and there is no table for the
+ *      given mask,
+ *    HICN_ERROR_NONE if no * error occurred.
+ */
+int
+_hicn_punt_add_del_vnettbl (ip_version_t * ip, u8 punt_id, u8 mask,
+                           u32 next_tbl_index, u32 intfc, int base_offset,
+                           int is_add, u8 use_current_data, ...)
+{
+  u8 buffer[PUNT_BUFFER_SIZE]; /* must be dimensioned
+                                * large enough */
+  int rt;
+  va_list vl;
+  u32 *table_index;
+  u32 new_table_index;
+  u32 skip, match;
+
+
+  /* Build the buffer right from the start to determine the skip size */
+  va_start (vl, use_current_data);
+  build_bit_array (buffer, sizeof (buffer), base_offset, &skip, &match, vl);
+  va_end (vl);
+
+  ASSERT (skip < 4);
+  //Hardcoded limit in following array
+
+  table_index = TABLE_ELT_P (ip, intfc, skip, punt_id, mask);
+
+  if (is_add && *table_index != HICNP_PUNY_INVALID_TBL)
+    return HICN_ERROR_PUNT_TBL_EXIST;
+  if (!is_add && *table_index == HICNP_PUNY_INVALID_TBL)
+    return HICN_ERROR_PUNT_TBL_NOT_FOUND;
+
+  new_table_index = ~0;
+  rt = vnet_classify_add_del_table (&vnet_classify_main,
+                                   buffer + skip * CLASSIFIER_VECTOR_SIZE,
+                                   HICN_CLASSIFY_NBUCKETS,
+                                   HICN_CLASSIFY_TABLE_MEMORY_SIZE, skip,
+                                   match, HICN_CLASSIFY_NO_NEXT_TABLE,
+                                   HICN_CLASSIFY_MISS_NEXT_INDEX,
+                                   &new_table_index,
+                                   use_current_data,
+                                   HICN_CLASSIFY_CURRENT_DATA_OFFSET, is_add,
+                                   HICN_CLASSIFY_DON_T_DEL_CHAIN);
+
+  if (rt != 0)
+    return HICN_ERROR_PUNT_INVAL;
+
+  *table_index = new_table_index;
+  if (ip->ip_version == 0x40)
+    update_table4_index (intfc, new_table_index);
+  else
+    update_table6_index (intfc, new_table_index);
+  return HICN_ERROR_NONE;
+}
+
+/**
+ * @brief Add or remove a vnet table matching the ip_version and field (src/dst)
+ */
+int
+hicn_punt_add_del_vnettbl (ip_version_t * ip, field_t * field, u8 mask,
+                          u32 next_tbl_index, u32 intfc, u8 base_offset,
+                          u8 use_current_data, int is_add)
+{
+  u8 ip_mask[IPV6_ADDR_LEN];
+  build_ip_address_mask (mask, ip_mask, sizeof (ip_mask));
+
+  return _hicn_punt_add_del_vnettbl (ip, field->punt_id, mask, next_tbl_index,
+                                    intfc, base_offset, is_add,
+                                    use_current_data, field, ip_mask, NULL);
+}
+
+
+/**
+ * @brief Add or remove a vnet table for udp tunnels matching the ip_version and field (src/dst)
+ *
+ */
+int
+hicn_punt_add_del_vnettbl_udp (ip_version_t * outer, ip_version_t * inner,
+                              field_t * field, u8 mask, u32 next_tbl_index,
+                              u32 intfc, u8 base_offset, int is_add)
+{
+  u8 udp_mask[inner->addr_len_bits];
+  build_ip_address_mask (mask, udp_mask, sizeof (udp_mask));
+  u16 port_value = 0xffff;
+  u8 protocol_value = 0xff;
+  
+  return _hicn_punt_add_del_vnettbl (outer, field->punt_id, mask,
+                                    next_tbl_index, intfc, base_offset,
+                                    is_add,
+                                    HICN_CLASSIFY_NO_CURRENT_DATA_FLAG,
+                                    outer->protocol_field, &protocol_value,
+                                    outer->udp_sport, &port_value,
+                                    outer->udp_dport, &port_value, field,
+                                    udp_mask, NULL);
+}
+
+#define hicn_punt_add_vnettbl_udp(outer, inner, field, mask, next_tbl_index, intfc, base_offset) \
+  (hicn_punt_add_del_vnettbl_udp(outer, inner, field, mask, next_tbl_index, intfc, base_offset, OP_ADD))
+
+#define hicn_punt_del_vnettbl_udp(outer, inner, field, mask, next_tbl_index, intfc, base_offset) \
+  (hicn_punt_add_del_vnettbl_udp(outer, inner, field, mask, next_tbl_index, intfc, base_offset, OP_DEL))
+
+/**
+ * @brief Add or remove a vnet session matching the list of fields/values passed
+ * as parameters.
+ *
+ * @param punt_id Storage identifier (HICN_PUNT_SRC | HICN_PUNT_DST)
+ * @param v4_address IPv4 address to match in the session // XXX v4/v6
+ * @param mask Subnet mask to match in the session
+ * @param next_hit_index vlib arch id pointing to the next node
+ * @param intfc Interface identifier
+ * @param is_add 1 if the session must be create, 0 if removed
+ * @param ... list of (field_t, value) to be matched
+ *
+ * @result Returns:
+ *   HICN_ERROR_TBL_NOT_FOUND there is no table for the given mask,
+ *   HICN_ERROR_PUNT_SSN_NOT_FOUND if is_add == 0 and there is no session for
+ *     the given address,
+ *   HICN_ERROR_NONE if no error * occurred.
+ */
+int
+_hicn_punt_add_del_vnetssn (ip_version_t * ip, u8 punt_id, u8 mask,
+                           u32 next_hit_index, u32 intfc, int base_offset,
+                           int is_add, ...)
+{
+  u8 buffer[PUNT_BUFFER_SIZE]; /* must be dimensioned
+                                * large enough */
+  int rt;
+  va_list vl;
+  u32 table_index;
+  u32 skip, match;
+
+  /* Build the buffer right from the start to determine the skip size */
+  va_start (vl, is_add);
+  build_bit_array (buffer, sizeof (buffer), base_offset, &skip, &match, vl);
+  va_end (vl);
+
+  ASSERT (skip < 4);
+  //Hardcoded limit in following array
+
+  table_index = TABLE_ELT (ip, intfc, skip, punt_id, mask);
+
+  if (table_index == HICNP_PUNY_INVALID_TBL)
+    return HICN_ERROR_PUNT_TBL_NOT_FOUND;
+
+  rt = vnet_classify_add_del_session (&vnet_classify_main, table_index, buffer,        //+skip * CLASSIFIER_VECTOR_SIZE,
+                                     next_hit_index,
+                                     HICN_CLASSIFY_OPAQUE_INDEX,
+                                     HICN_CLASSIFY_ADVANCE,
+                                     HICN_CLASSIFY_ACTION,
+                                     HICN_CLASSIFY_METADATA, is_add);
+
+  if (rt == VNET_API_ERROR_NO_SUCH_ENTRY)
+    rt = HICN_ERROR_PUNT_SSN_NOT_FOUND;
+
+  return rt;
+}
+
+/**
+ * @brief Add or remove a vnet session matching the ip6 src address
+ *
+ * See hicn_punt_add_del_vnetssn for details about parameters.
+ */
+int
+hicn_punt_add_del_vnetssn (ip_version_t * ip, field_t * field,
+                          ip46_address_t * v46_address, u8 mask,
+                          u32 next_hit_index, u32 intfc, u8 base_offset,
+                          int is_add)
+{
+  return _hicn_punt_add_del_vnetssn (ip, field->punt_id, mask, next_hit_index,
+                                    intfc, base_offset, is_add, field,
+                                    ip46_address_is_ip4 (v46_address) ?
+                                    v46_address->ip4.as_u8 : v46_address->
+                                    ip6.as_u8, NULL);
+}
+
+
+
+/**
+ * @brief Add or remove a vnet session for udp tunnels matching the ip6 src address
+ *
+ * See hicn_punt_add_del_vnetssn for details about parameters.
+ */
+int
+hicn_punt_add_del_vnetssn_udp (ip_version_t * outer, ip_version_t * inner,
+                              field_t * field, ip46_address_t * v46_address,
+                              u8 mask, u32 next_hit_index, u32 intfc,
+                              u8 base_offset, u8 protocol, u16 sport,
+                              u16 dport, int is_add)
+{    
+  return _hicn_punt_add_del_vnetssn (outer, field->punt_id, mask,
+                                    next_hit_index, intfc, base_offset,
+                                    is_add, outer->protocol_field, &protocol,
+                                    outer->udp_sport, &sport,
+                                    outer->udp_dport, &dport, field,
+                                    v46_address->as_u8, NULL);
+}
+
+#define hicn_punt_add_vnetssn_udp(outer, inner, field, addr, mask, index, intfc, offset, protocol, sport, dport) \
+  (hicn_punt_add_del_vnetssn_udp(outer, inner, field, addr, mask, index, intfc, offset, protocol, sport, dport, OP_ADD))
+
+#define hicn_punt_del_vnetssn_udp(outer, inner, field, addr, mask, index, intfc, offset, protocol, sport, dport) \
+  (hicn_punt_add_del_vnetssn_udp(outer, inner, field, addr, mask, index, intfc, offset, protocol, sport, dport, OP_DEL))
+
+/*
+ * Enable the table on a given interface considering the table type
+ */
+void
+hicn_punt_enable_disable_vnet_ip4_table_on_intf (vlib_main_t * vm,
+                                                u32 sw_if_index,
+                                                int is_enable)
+{
+  if (hicn_punt_glb.head_ip4[sw_if_index] != HICNP_PUNY_INVALID_TBL)
+    (void) vnet_set_input_acl_intfc (vm, sw_if_index,
+                                    hicn_punt_glb.head_ip4[sw_if_index],
+                                    0xFFFFFFFF, 0xFFFFFFFF, is_enable);
+  return;
+}
+
+/*
+ * Enable the table on a given interface considering the table type
+ *
+ * XXX replace skip by base_offset XXX are we sure we always have ETH_L2, and
+ * not base_offset ???
+ */
+int
+hicn_punt_remove_ip4_address (vlib_main_t * vm, ip4_address_t * addr,
+                             u8 mask, int skip, u32 sw_if_index,
+                             int is_enable)
+{
+
+  vnet_classify_main_t *cm = &vnet_classify_main;
+  vnet_classify_table_t *vnet_table = NULL;
+
+  u32 table_index = ~0;
+
+  u32 base_offset = (skip ? ETH_L2 : NO_L2);
+  ip46_address_t addr46;
+  ip46_address_set_ip4 (&addr46, addr);
+
+  hicn_punt_del_vnetssn (&ipv4, &ipv4_src, &addr46, mask,
+                        hicn_punt_glb.next_hit_data_ipv4, sw_if_index,
+                        ETH_L2);
+  hicn_punt_del_vnetssn (&ipv4, &ipv4_dst, &addr46, mask,
+                        hicn_punt_glb.next_hit_interest_ipv4, sw_if_index,
+                        ETH_L2);
+
+  table_index =
+    hicn_punt_glb.ip4_vnet_tbl_idx[sw_if_index][skip][HICN_PUNT_DST][mask];
+  vnet_table = pool_elt_at_index (cm->tables, table_index);
+  if (vnet_table->active_elements == 0)
+    {
+      hicn_punt_del_vnettbl (&ipv4, &ipv4_dst, mask,
+                            hicn_punt_glb.ip4_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][mask], sw_if_index, base_offset);
+    }
+  table_index =
+    hicn_punt_glb.ip4_vnet_tbl_idx[sw_if_index][skip][HICN_PUNT_SRC][mask];
+  vnet_table = pool_elt_at_index (cm->tables, table_index);
+  if (vnet_table->active_elements == 0)
+    {
+      hicn_punt_del_vnettbl (&ipv4, &ipv4_src, mask, ~0, sw_if_index,
+                            base_offset);
+    }
+  return HICN_ERROR_NONE;
+}
+
+int
+hicn_punt_remove_ip6_address (vlib_main_t * vm, ip6_address_t * addr,
+                             u8 mask, int skip, u32 sw_if_index,
+                             int is_enable)
+{
+
+  vnet_classify_main_t *cm = &vnet_classify_main;
+  vnet_classify_table_t *vnet_table = NULL;
+
+  u32 table_index = ~0;
+
+  u32 base_offset = (skip ? ETH_L2 : NO_L2);
+
+  hicn_punt_del_vnetssn (&ipv6, &ipv6_src, (ip46_address_t *) addr, mask,
+                        hicn_punt_glb.next_hit_data_ipv6, sw_if_index,
+                        ETH_L2);
+  hicn_punt_del_vnetssn (&ipv6, &ipv6_dst, (ip46_address_t *) addr, mask,
+                        hicn_punt_glb.next_hit_interest_ipv6, sw_if_index,
+                        ETH_L2);
+
+  table_index =
+    hicn_punt_glb.ip6_vnet_tbl_idx[sw_if_index][skip][HICN_PUNT_DST][mask];
+  vnet_table = pool_elt_at_index (cm->tables, table_index);
+  if (vnet_table->active_elements == 0)
+    {
+      hicn_punt_del_vnettbl (&ipv6, &ipv6_dst, mask,
+                            hicn_punt_glb.ip6_vnet_tbl_idx[sw_if_index][skip]
+                            [HICN_PUNT_SRC][mask], sw_if_index, base_offset);
+    }
+  table_index =
+    hicn_punt_glb.ip6_vnet_tbl_idx[sw_if_index][skip][HICN_PUNT_SRC][mask];
+  vnet_table = pool_elt_at_index (cm->tables, table_index);
+  if (vnet_table->active_elements == 0)
+    {
+      hicn_punt_del_vnettbl (&ipv6, &ipv6_src, mask, ~0, sw_if_index,
+                            base_offset);
+    }
+  return HICN_ERROR_NONE;
+}
+
+/*
+ * Enable the table on a given interface considering the table type
+ */
+void
+hicn_punt_enable_disable_vnet_ip6_table_on_intf (vlib_main_t * vm,
+                                                u32 sw_if_index,
+                                                int is_enable)
+{
+  if (hicn_punt_glb.head_ip6[sw_if_index] != HICNP_PUNY_INVALID_TBL)
+    (void) vnet_set_input_acl_intfc (vm, sw_if_index,
+                                    0xFFFFFFFF,
+                                    hicn_punt_glb.head_ip6[sw_if_index],
+                                    0xFFFFFFFF, is_enable);
+  return;
+}
+
+/*
+ * HICN PUNT vlibd node addtion
+ */
+void
+hicn_punt_vlib_node_add (vlib_main_t * vm)
+{
+  u32 hit_next_index = 0xFFFFFFFF;
+  vlib_node_t *node;
+
+  /* to remove the warning */
+  hit_next_index = hit_next_index;
+
+  //Accquire the node indexes
+
+  /* ip face */
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-ip4-input");
+  hicn_punt_glb.hicn_node_info.hicn_face_ip4_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-ip6-input");
+  hicn_punt_glb.hicn_node_info.hicn_face_ip6_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-ip4-output");
+  hicn_punt_glb.hicn_node_info.hicn_face_ip4_output_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-ip6-output");
+  hicn_punt_glb.hicn_node_info.hicn_face_ip6_output_index = node->index;
+
+  /* ip iface */
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-ip4-input");
+  hicn_punt_glb.hicn_node_info.hicn_iface_ip4_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-ip6-input");
+  hicn_punt_glb.hicn_node_info.hicn_iface_ip6_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-ip4-output");
+  hicn_punt_glb.hicn_node_info.hicn_iface_ip4_output_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-ip6-output");
+  hicn_punt_glb.hicn_node_info.hicn_iface_ip4_output_index = node->index;
+
+  /* udp face */
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-udp4-input");
+  hicn_punt_glb.hicn_node_info.hicn_face_udp4_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-udp6-input");
+  hicn_punt_glb.hicn_node_info.hicn_face_udp6_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-udp4-output");
+  hicn_punt_glb.hicn_node_info.hicn_face_udp4_output_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-face-udp6-output");
+  hicn_punt_glb.hicn_node_info.hicn_face_udp6_output_index = node->index;
+
+  /* udp iface */
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-udp4-input");
+  hicn_punt_glb.hicn_node_info.hicn_iface_udp4_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-udp6-input");
+  hicn_punt_glb.hicn_node_info.hicn_iface_udp6_input_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-udp4-output");
+  hicn_punt_glb.hicn_node_info.hicn_iface_udp4_output_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "hicn-iface-udp6-output");
+  hicn_punt_glb.hicn_node_info.hicn_iface_udp6_output_index = node->index;
+
+  node = vlib_get_node_by_name (vm, (u8 *) "ip4-inacl");
+  hicn_punt_glb.hicn_node_info.ip4_inacl_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "ip6-inacl");
+  hicn_punt_glb.hicn_node_info.ip6_inacl_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
+  hicn_punt_glb.hicn_node_info.ip4_lookup_node_index = node->index;
+  node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
+  hicn_punt_glb.hicn_node_info.ip6_lookup_node_index = node->index;
+
+
+  hicn_punt_glb.next_hit_data_ipv4 = vlib_node_add_next (vm,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        ip4_inacl_node_index,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        hicn_face_ip4_input_index);
+
+  hicn_punt_glb.next_hit_interest_ipv4 = vlib_node_add_next (vm,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            ip4_inacl_node_index,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            hicn_iface_ip4_input_index);
+
+  hicn_punt_glb.next_hit_data_ipv6 = vlib_node_add_next (vm,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        ip6_inacl_node_index,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        hicn_face_ip6_input_index);
+
+  hicn_punt_glb.next_hit_interest_ipv6 = vlib_node_add_next (vm,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            ip6_inacl_node_index,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            hicn_iface_ip6_input_index);
+
+  hicn_punt_glb.next_hit_data_udp4 = vlib_node_add_next (vm,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        ip4_inacl_node_index,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        hicn_face_udp4_input_index);
+
+  hicn_punt_glb.next_hit_interest_udp4 = vlib_node_add_next (vm,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            ip4_inacl_node_index,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            hicn_iface_udp4_input_index);
+
+  hicn_punt_glb.next_hit_data_udp6 = vlib_node_add_next (vm,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        ip6_inacl_node_index,
+                                                        hicn_punt_glb.hicn_node_info.
+                                                        hicn_face_udp6_input_index);
+
+  hicn_punt_glb.next_hit_interest_udp6 = vlib_node_add_next (vm,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            ip6_inacl_node_index,
+                                                            hicn_punt_glb.hicn_node_info.
+                                                            hicn_iface_udp6_input_index);
+
+  return;
+}
+
+/*
+ * HICN PUNT INIT
+ */
+void
+hicn_punt_init (vlib_main_t * vm)
+{
+  u32 table_index = ~0;
+  //Create vnet classify tables and store the table indexes
+  memset (hicn_punt_glb.ip4_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP4_MASK * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.ip6_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP6_MASK * HICN_MAX_INTFC);
+
+  memset (hicn_punt_glb.udp44_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP4_MASK * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.udp46_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP6_MASK * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.udp64_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP4_MASK * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.udp66_vnet_tbl_idx, table_index,
+         sizeof (u32) * 4 * 2 * HICN_PUNT_IP6_MASK * HICN_MAX_INTFC);
+  //Register hicn nodes after vnet table creation
+  hicn_punt_vlib_node_add (vm);
+  memset (hicn_punt_glb.head_ip4, ~0, sizeof (u32) * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.tail_ip4, ~0, sizeof (u32) * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.head_ip6, ~0, sizeof (u32) * HICN_MAX_INTFC);
+  memset (hicn_punt_glb.tail_ip6, ~0, sizeof (u32) * HICN_MAX_INTFC);
+  return;
+}
+
+u32
+hicn_punt_interest_data_for_udp (vlib_main_t * vm,
+                                ip46_address_t * prefix, u8 mask,
+                                u32 swif, u8 punt_type, u16 sport, u16 dport)
+{
+  int skip = 1;
+  u32 table_index;
+
+  if (punt_type != HICN_PUNT_IP_TYPE && punt_type != HICN_PUNT_UDP4_TYPE
+      && punt_type != HICN_PUNT_UDP6_TYPE)
+    return HICN_ERROR_PUNT_INVAL;
+
+  if (ip46_address_is_ip4 (prefix))
+    {
+      if (mask > IPV4_ADDR_LEN_BITS)
+       return HICN_ERROR_PUNT_INVAL;
+
+      if (punt_type == HICN_PUNT_UDP4_TYPE)
+       {
+         skip = 2;
+         /* Create Vnet table for a given mask */
+         hicn_punt_add_vnettbl_udp (&ipv44, &ipv4, &udp44_src, mask, ~0,
+                                    swif, ETH_L2);
+
+         table_index =
+           hicn_punt_glb.udp44_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+
+         hicn_punt_add_vnettbl_udp (&ipv44, &ipv4, &udp44_dst, mask,
+                                    table_index, swif, ETH_L2);
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn_udp (&ipv44, &ipv4, &udp44_src,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_data_udp4,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_add_vnetssn_udp (&ipv44, &ipv4, &udp44_dst,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_interest_udp4,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+      else                     //PUNTING is UDP6
+       {
+         skip = 3;
+         /* Create Vnet table for a given mask */
+         hicn_punt_add_vnettbl_udp (&ipv64, &ipv6, &udp64_src, mask, ~0,
+                                    swif, ETH_L2);
+
+         table_index =
+           hicn_punt_glb.udp64_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+
+         hicn_punt_add_vnettbl_udp (&ipv64, &ipv6, &udp64_dst, mask,
+                                    table_index, swif, ETH_L2);
+
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn_udp (&ipv64, &ipv4, &udp64_src,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_data_udp6,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_add_vnetssn_udp (&ipv64, &ipv4, &udp64_dst,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_interest_udp6,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+    }
+  else
+    {
+      if (punt_type == HICN_PUNT_UDP4_TYPE)
+       {
+         skip = 2;
+         /* Create Vnet table for a given mask */
+         if (mask > 96)
+           return HICN_ERROR_PUNT_INVAL;
+
+         hicn_punt_add_vnettbl_udp (&ipv46, &ipv4, &udp46_src, mask, ~0,
+                                    swif, ETH_L2);
+
+         table_index =
+           hicn_punt_glb.udp46_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+         hicn_punt_add_vnettbl_udp (&ipv46, &ipv4, &udp46_dst, mask,
+                                    table_index, swif, ETH_L2);
+
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn_udp (&ipv46, &ipv4, &udp46_src,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_data_udp4,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+         hicn_punt_add_vnetssn_udp (&ipv46, &ipv4, &udp46_dst,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_interest_udp4,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+      else
+       {
+         if (mask > 122)
+           return HICN_ERROR_PUNT_INVAL;
+         
+         skip = 3;
+         hicn_punt_add_vnettbl_udp (&ipv66, &ipv6, &udp66_src, mask, ~0,
+                                    swif, ETH_L2);
+
+         table_index =
+           hicn_punt_glb.udp66_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+         hicn_punt_add_vnettbl_udp (&ipv66, &ipv6, &udp66_dst, mask,
+                                    table_index, swif, ETH_L2);
+
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn_udp (&ipv66, &ipv6, &udp66_src,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_data_udp6,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+         hicn_punt_add_vnetssn_udp (&ipv66, &ipv6, &udp66_dst,
+                                    prefix, mask,
+                                    hicn_punt_glb.next_hit_interest_udp6,
+                                    swif, ETH_L2, IPPROTO_UDP, sport, dport);
+
+         hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+
+    }
+  return HICN_ERROR_NONE;
+}
+
+
+
+u32
+hicn_punt_interest_data_for_ethernet (vlib_main_t * vm,
+                                     ip46_address_t * prefix, u8 mask,
+                                     u32 swif, u8 punt_type)
+{
+  int skip = 1;
+  u32 table_index;
+  u8 use_current_data = HICN_CLASSIFY_NO_CURRENT_DATA_FLAG;
+
+  if (punt_type != HICN_PUNT_IP_TYPE && punt_type != HICN_PUNT_UDP4_TYPE
+      && punt_type != HICN_PUNT_UDP6_TYPE)
+    return HICN_ERROR_PUNT_INVAL;
+
+  if (ip46_address_is_ip4 (prefix))
+    {
+      if (mask > IPV4_ADDR_LEN_BITS)
+       return HICN_ERROR_PUNT_INVAL;
+
+      if (punt_type == HICN_PUNT_IP_TYPE)
+       {
+         /* Create Vnet table for a given mask */
+         hicn_punt_add_vnettbl (&ipv4, &ipv4_src, mask, ~0, swif, ETH_L2,
+                                use_current_data);
+
+         table_index =
+           hicn_punt_glb.ip4_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+
+         hicn_punt_add_vnettbl (&ipv4, &ipv4_dst, mask, table_index, swif,
+                                ETH_L2, use_current_data);
+
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn (&ipv4, &ipv4_src,
+                                prefix, mask,
+                                hicn_punt_glb.next_hit_data_ipv4, swif,
+                                ETH_L2);
+         hicn_punt_add_vnetssn (&ipv4, &ipv4_dst,
+                                prefix, mask,
+                                hicn_punt_glb.next_hit_interest_ipv4, swif,
+                                ETH_L2);
+
+         hicn_punt_enable_disable_vnet_ip4_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+      else
+       {
+         return HICN_ERROR_PUNT_INVAL;
+       }
+    }
+  else
+    {
+      if (punt_type == HICN_PUNT_IP_TYPE)
+       {
+         if (mask > IPV6_ADDR_LEN_BITS)
+           return HICN_ERROR_PUNT_INVAL;
+
+         /* Create Vnet table for a given mask */
+         hicn_punt_add_vnettbl (&ipv6, &ipv6_src, mask, ~0, swif, ETH_L2,
+                                use_current_data);
+
+         table_index =
+           hicn_punt_glb.ip6_vnet_tbl_idx[swif][skip][HICN_PUNT_SRC][mask];
+
+         hicn_punt_add_vnettbl (&ipv6, &ipv6_dst, mask, table_index, swif,
+                                ETH_L2, use_current_data);
+
+         /*
+          * Add a session for the specified ip address and
+          * subnet mask
+          */
+         hicn_punt_add_vnetssn (&ipv6, &ipv6_src, prefix,
+                                mask, hicn_punt_glb.next_hit_data_ipv6, swif,
+                                ETH_L2);
+         hicn_punt_add_vnetssn (&ipv6, &ipv6_dst, prefix,
+                                mask, hicn_punt_glb.next_hit_interest_ipv6,
+                                swif, ETH_L2);
+
+         hicn_punt_enable_disable_vnet_ip6_table_on_intf (vm, swif,
+                                                          OP_ENABLE);
+       }
+      else
+       {
+         return HICN_ERROR_PUNT_INVAL;
+       }
+
+    }
+  return HICN_ERROR_NONE;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/punt.h b/hicn-plugin/src/punt.h
new file mode 100755 (executable)
index 0000000..ebc27e9
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_PUNT_H__
+#define __HICN_PUNT_H__
+
+#include <vppinfra/error.h>
+#include <hicn/hicn.h>
+
+#define HICN_CLASSIFY_TABLE_MEMORY_SIZE (2*1024*1024)  // 2MB allocated for the classification table
+#define HICN_PUNTING_BUFFER_SIZE_32 (32)
+#define HICN_PUNTING_BUFFER_SIZE_48 (48)
+#define HICN_PUNTING_BUFFER_SIZE_64 (64)
+#define HICN_PUNTING_BUFFER_SIZE_80 (80)
+#define HICN_PUNTING_BUFFER_SIZE_128 (128)
+
+/* Limits */
+
+#define HICN_PUNT_IP4     0
+#define HICN_PUNT_IP6     1
+
+#define HICN_MAX_INTFC 256
+
+/* We also consider mask = 0 to match everything */
+#define HICN_PUNT_IP4_MASK   33
+#define HICN_PUNT_IP6_MASK   129
+
+#define HICN_PUNT_IP_TYPE 0
+#define HICN_PUNT_UDP4_TYPE 1
+#define HICN_PUNT_UDP6_TYPE 2
+/*
+ * u32 ip4_vnet_tbl_idx[HICN_MAX_INTFC][2][3][HICN_PUNT_IP4_MASK];
+ * //[skip][src][mask],[skip][dst][mask] u32
+ * ip6_vnet_tbl_idx[HICN_MAX_INTFC][2][3][HICN_PUNT_IP6_MASK];
+ * //[skip][src][mask],[skip][dst][mask]
+ */
+#define PUNT_MASK(ip) (ip->addr_len_bits + 1)
+#define TABLE_ELT_P(ip, i, j, k, l) (ip->tbl + (4 * 2 * PUNT_MASK(ip)) * i + (2 * PUNT_MASK(ip)) * j + k * PUNT_MASK(ip) + l)
+#define TABLE_ELT(ip, i, j, k, l)  (*(TABLE_ELT_P(ip, i, j, k, l)))
+
+#define NO_L2 0
+#define ETH_L2 sizeof(ethernet_header_t)
+
+#define IPPROTO_MASK 0xFF
+
+/* Index to access vnet table index */
+#define HICN_PUNT_SRC     0
+#define HICN_PUNT_DST     1
+
+#define HICN_PUNT_OK      0
+#define HICN_PUNT_ERR     1
+
+#define HICNP_PUNY_INVALID_TBL ~0
+
+/* Number of bytes before the next header/protocol field in ip6/4 */
+#define BYTES_TO_PROTOCOL_IP4 9
+#define BYTES_TO_NEXT_HEADER_IP6 6
+
+#define PUNT_BUFFER_SIZE 100   /* B */
+#define CLASSIFIER_VECTOR_SIZE 16      /* B */
+
+#define OP_DEL 0
+#define OP_ADD 1
+#define OP_DISABLE 0
+#define OP_ENABLE 1
+
+/* vnet_classify_add_del_table */
+#define HICN_CLASSIFY_NO_NEXT_TABLE  0xFFFFFFFF
+#define HICN_CLASSIFY_MISS_NEXT_INDEX 16
+#define HICN_CLASSIFY_CURRENT_DATA_FLAG CLASSIFY_FLAG_USE_CURR_DATA
+#define HICN_CLASSIFY_NO_CURRENT_DATA_FLAG 0
+#define HICN_CLASSIFY_CURRENT_DATA_OFFSET 0
+#define HICN_CLASSIFY_DON_T_DEL_CHAIN 0
+
+/* vnet_classify_add_del_session */
+#define HICN_CLASSIFY_OPAQUE_INDEX 0xFFFFFFFF
+#define HICN_CLASSIFY_ADVANCE 0
+#define HICN_CLASSIFY_ACTION 0
+#define HICN_CLASSIFY_METADATA 0
+
+/* This should be equal to the number of rules we expect in each table */
+#define HICN_CLASSIFY_NBUCKETS 3
+
+
+/* HICN punt node index */
+typedef struct _hicn_node_info_s
+{
+  u32 hicn_face_ip4_input_index;
+  u32 hicn_face_ip6_input_index;
+  u32 hicn_iface_ip4_input_index;
+  u32 hicn_iface_ip6_input_index;
+  u32 hicn_face_ip4_output_index;
+  u32 hicn_face_ip6_output_index;
+  u32 hicn_iface_ip4_output_index;
+  u32 hicn_iface_ip6_output_index;
+  u32 hicn_face_udp4_input_index;
+  u32 hicn_face_udp6_input_index;
+  u32 hicn_iface_udp4_input_index;
+  u32 hicn_iface_udp6_input_index;
+  u32 hicn_face_udp4_output_index;
+  u32 hicn_face_udp6_output_index;
+  u32 hicn_iface_udp4_output_index;
+  u32 hicn_iface_udp6_output_index;
+  u32 ip4_inacl_node_index;
+  u32 ip6_inacl_node_index;
+  u32 ip4_lookup_node_index;
+  u32 ip6_lookup_node_index;
+} hicn_node_info_t;
+
+/*
+ * HICN global PUNT info
+ */
+typedef struct _hicn_punt_glb_s
+{
+  hicn_node_info_t hicn_node_info;
+
+  /*
+   * The following nodes are used to create the vlib node graph, and
+   * point classified packets to the right node.
+   */
+  u32 next_hit_interest_ipv4;
+  //node - graph index to forward packets to our hicn nodes
+  u32 next_hit_data_ipv4;
+  u32 next_hit_interest_ipv6;
+  //node - graph index to forward packets to our hicn nodes
+  u32 next_hit_data_ipv6;
+  u32 next_hit_interest_udp4;
+  //node - graph index to forward packets to our hicn nodes
+  u32 next_hit_data_udp4;
+  u32 next_hit_interest_udp6;
+  //node - graph index to forward packets to our hicn nodes
+  u32 next_hit_data_udp6;
+
+  /*
+   * One table is created : - per interface : so that we can have
+   * different punted prefixes per interface, and thus decrease the
+   * amount of matched rules per packet. An interface will be
+   * consistently receiving packets with or without the ethernet
+   * header, and thus the offsets should always be correct. - per skip
+   * (assuming it is for the base offset (ethernet or not), in which
+   * case the interface should be sufficient. - per prefix length to
+   * allow for sorting later. - per src / dst (?)
+   *
+   * Note that there is no test on the packet type (v4 or v6), as they
+   * follow distinct paths in the vpp graph and will thus be dispatched
+   * to distinct classifiers. This is also why we duplicate the state
+   * for both IPv4 and IPv6 in this implementation.
+   *
+   * Tables are chained per interface in the order they are added. Each
+   * table consists in a set of rules (named sessions).
+   *
+   * / interface --> table i [.next_table_index=j] --> table j [.nti=~0]
+   * -- drop \      |                                 | +-- on match,
+   * send to node m      +-- [...] to node n
+   *
+   * For debugging purposes, you can use the following commands:
+   *
+   * vppctl show inacl type ip4 vppctl show inacl type ip6
+   *
+   * vppctl show classify tables [verbose]
+   *
+   * TODO: - allow tables to be removed - sort tables with decreasing
+   * prefix length to allow for LPM. - directly access the linked list
+   * through vpp APIs and remove global variables. They are not
+   * sufficient anyways for removal.
+   */
+
+  /**
+   * Given the current implementation, the following multidimensional array
+   * stores the table indexes uniquerly identified by the 4-tuple (interface,
+   * skip, src/dst, mask).
+   *
+   * For flexibility, some macros and functions will be defined in the .c to
+   * manipulate this array.
+   */
+  u32 ip4_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+  u32 ip6_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+  u32 udp44_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+  u32 udp46_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+  u32 udp64_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP4_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+  u32 udp66_vnet_tbl_idx[HICN_MAX_INTFC][4][2][HICN_PUNT_IP6_MASK];
+  //[skip][src][mask],[skip][dst][mask]
+
+  /*
+   * The first and last tables associated to each interface (both for
+   * v4 and v6) are stored. They are respectively used to : - start
+   * classification on the correct table depending on the input
+   * interface: the assumption is that different interfaces with punt
+   * different prefixes, which should decreate the number of potential
+   * rules to match for each incoming packet. see.
+   * vnet_set_input_acl_intfc() - maintain the chaining between tables
+   * so that upon addition, the newly created table can be chained to
+   * the previous last one.
+   */
+  u32 head_ip4[HICN_MAX_INTFC];
+  u32 tail_ip4[HICN_MAX_INTFC];
+  u32 head_ip6[HICN_MAX_INTFC];
+  u32 tail_ip6[HICN_MAX_INTFC];
+
+} hicn_punt_glb_t;
+
+extern hicn_punt_glb_t hicn_punt_glb;
+
+
+
+/* XXX The two following structs might be opaque */
+
+#define NA 0
+
+typedef struct
+{
+  u32 offset;
+  u32 len;                     /* bytes */
+  u32 punt_id;                 /* see explanation in hicn_punt.c */
+} field_t;
+
+/* Format: _(name, base, layer, field, punt_id) */
+#define foreach_field                                            \
+  _(ipv6_src, 0, _ipv6_header_t, saddr, HICN_PUNT_SRC)           \
+  _(ipv6_dst, 0, _ipv6_header_t, daddr, HICN_PUNT_DST)           \
+  _(ipv6_protocol, 0, _ipv6_header_t, nxt, NA)                   \
+  _(ipv4_src, 0, _ipv4_header_t, saddr, HICN_PUNT_SRC)           \
+  _(ipv4_dst, 0, _ipv4_header_t, daddr, HICN_PUNT_DST)           \
+  _(ipv4_protocol, 0, _ipv4_header_t, protocol, NA)              \
+                                                                 \
+  _(ipv4_version, 0, _ipv4_header_t, version_ihl, NA)                   \
+  _(ipv6_version, 0, _ipv6_header_t, vfc, NA)                           \
+  _(udp4_sport, IPV4_HDRLEN, _udp_header_t, src_port, NA)               \
+  _(udp4_dport, IPV4_HDRLEN, _udp_header_t, dst_port, NA)               \
+  _(udp6_sport, IPV6_HDRLEN, _udp_header_t, src_port, NA)               \
+  _(udp6_dport, IPV6_HDRLEN, _udp_header_t, dst_port, NA)               \
+  _(udp6_protocol, 0, _ipv6_header_t, nxt, NA)                         \
+  _(udp4_protocol, 0, _ipv4_header_t, protocol, NA) \
+  _(udp46_src, IPV4_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
+  _(udp46_dst, IPV4_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \
+  _(udp44_src, IPV4_HDRLEN + UDP_HDRLEN, _ipv4_header_t, saddr, HICN_PUNT_SRC) \
+  _(udp44_dst, IPV4_HDRLEN + UDP_HDRLEN, _ipv4_header_t, daddr, HICN_PUNT_DST) \
+  _(udp66_src, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
+  _(udp66_dst, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \
+  _(udp64_src, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, saddr, HICN_PUNT_SRC) \
+  _(udp64_dst, IPV6_HDRLEN + UDP_HDRLEN, _ipv6_header_t, daddr, HICN_PUNT_DST) \
+
+
+#define _(NAME, BASE, LAYER, FIELD, PUNT_ID)          \
+    extern field_t NAME;
+foreach_field
+#undef _
+  typedef struct
+{
+  u32 *tbl;
+  u8 addr_len_bits;
+  field_t *protocol_field;
+  field_t *version_field;
+  field_t *udp_sport;
+  field_t *udp_dport;
+  u8 ip_version;
+} ip_version_t;
+
+extern ip_version_t ipv4;
+extern ip_version_t ipv6;
+
+
+/* ------------------------- */
+
+/**
+ * @brief Punt table APIs
+ *
+ * Those APIs are called when the first punting table is created for a given
+ * interface, so as to point to the start of the chain.
+ */
+void
+hicn_punt_enable_disable_vnet_ip4_table_on_intf (vlib_main_t * vm,
+                                                u32 sw_if_index,
+                                                int is_enable);
+void
+hicn_punt_enable_disable_vnet_ip6_table_on_intf (vlib_main_t * vm,
+                                                u32 sw_if_index,
+                                                int is_enable);
+u32 hicn_punt_interest_data_for_udp (vlib_main_t * vm,
+                                    ip46_address_t * prefix, u8 mask,
+                                    u32 swif, u8 punt_type, u16 sport,
+                                    u16 dport);
+u32 hicn_punt_interest_data_for_ethernet (vlib_main_t * vm,
+                                         ip46_address_t * prefix, u8 mask,
+                                         u32 swif, u8 type);
+int hicn_punt_remove_ip6_address (vlib_main_t * vm, ip6_address_t * addr,
+                                 u8 mask, int skip, u32 swif, int is_enable);
+int hicn_punt_remove_ip4_address (vlib_main_t * vm, ip4_address_t * addr,
+                                 u8 mask, int skip, u32 swif, int is_enable);
+void hicn_punt_init (vlib_main_t * vm);
+
+int
+hicn_punt_add_del_vnettbl (ip_version_t * ip, field_t * field, u8 mask, u32
+                          next_tbl_index, u32 intfc, u8 base_offset,
+                          u8 use_current_data, int is_add);
+
+#define hicn_punt_add_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, use_current_data) \
+  (hicn_punt_add_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, use_current_data, OP_ADD))
+
+#define hicn_punt_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset) \
+  (hicn_punt_add_del_vnettbl(ip, field, mask, next_tbl_index, intfc, base_offset, HICN_CLASSIFY_NO_CURRENT_DATA_FLAG, OP_DEL))
+
+int
+hicn_punt_add_del_vnetssn (ip_version_t * ip, field_t * field,
+                          ip46_address_t * v46_address, u8 mask,
+                          u32 next_hit_index, u32 intfc, u8 base_offset,
+                          int is_add);
+
+#define hicn_punt_add_vnetssn(ip, field, addr, mask, index, intfc, offset) \
+    (hicn_punt_add_del_vnetssn(ip, field, addr, mask, index, intfc, offset, OP_ADD))
+
+#define hicn_punt_del_vnetssn(ip, field, addr, mask, index, intfc, offset) \
+    (hicn_punt_add_del_vnetssn(ip, field, addr, mask, index, intfc, offset, OP_DEL))
+
+#endif /* // __HICN_PUNT_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/route.c b/hicn-plugin/src/route.c
new file mode 100755 (executable)
index 0000000..9202efb
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/dpo/dpo.h>
+#include <vnet/dpo/load_balance.h>
+#include <vlib/global_funcs.h>
+
+#include "strategy_dpo_ctx.h"
+#include "strategy_dpo_manager.h"
+#include "strategy.h"
+#include "faces/face.h"
+#include "error.h"
+#include "strategies/dpo_mw.h"
+
+int
+hicn_route_get_dpo (const ip46_address_t * prefix, u8 plen,
+                   const dpo_id_t ** hicn_dpo, u32 * fib_index)
+{
+  fib_prefix_t fib_pfx;
+  const dpo_id_t *load_balance_dpo_id;
+  const dpo_id_t *former_dpo_id;
+  int found = 0, ret = HICN_ERROR_ROUTE_NOT_FOUND;
+  fib_node_index_t fib_entry_index;
+
+  /* At this point the face exists in the face table */
+  fib_prefix_from_ip46_addr (prefix, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+
+  /* Check if the route already exist in the fib */
+  /*
+   * ASSUMPTION: we use table 0 which is the default table and it is
+   * already existing and locked
+   */
+  *fib_index = fib_table_find_or_create_and_lock (fib_pfx.fp_proto,
+                                                 HICN_FIB_TABLE,
+                                                 FIB_SOURCE_PLUGIN_HI);
+  fib_entry_index = fib_table_lookup_exact_match (*fib_index, &fib_pfx);
+
+  if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+    {
+      /* Route already existing. We need to update the dpo. */
+      load_balance_dpo_id =
+       fib_entry_contribute_ip_forwarding (fib_entry_index);
+
+      /* The dpo is not a load balance dpo as expected */
+      if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE)
+       ret = HICN_ERROR_ROUTE_NO_LD;
+      else
+       {
+         /* former_dpo_id is a load_balance dpo */
+         load_balance_t *lb =
+           load_balance_get (load_balance_dpo_id->dpoi_index);
+
+         /* FIB entry exists but there is no hicn dpo. */
+         ret = HICN_ERROR_ROUTE_DPO_NO_HICN;
+         for (int i = 0; i < lb->lb_n_buckets && !found; i++)
+           {
+             former_dpo_id = load_balance_get_bucket_i (lb, i);
+
+             if (dpo_is_hicn (former_dpo_id))
+               {
+                 *hicn_dpo = former_dpo_id;
+                 ret = HICN_ERROR_NONE;
+                 found = 1;
+               }
+           }
+       }
+    }
+  /*
+   * Remove the lock from the table. We keep one lock per route, not
+   * per dpo
+   */
+  fib_table_unlock (*fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+
+  return ret;
+}
+
+/* Add a new route for a name prefix */
+int
+hicn_route_add (hicn_face_id_t * face_id, u32 len,
+               const ip46_address_t * prefix, u8 plen)
+{
+
+  fib_prefix_t fib_pfx;
+  dpo_id_t dpo = DPO_INVALID;
+  const dpo_id_t *hicn_dpo_id;
+  int ret = HICN_ERROR_NONE;
+  dpo_id_t face_dpo_tmp[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+  int n_face_dpo = 0;
+  index_t dpo_idx;
+  u32 fib_index;
+  vlib_main_t *vm = vlib_get_main ();
+  hicn_face_vft_t *face_vft = NULL;
+
+  if (face_id == NULL)
+    {
+      return HICN_ERROR_ROUTE_INVAL;
+    }
+  /*
+   * Check is the faces are available, otherwise skip the face
+   * id_adjacency existance is not checked. It should be checked before
+   * sending a packet out
+   */
+  for (int i = 0; i < clib_min (HICN_PARAM_FIB_ENTRY_NHOPS_MAX, len); i++)
+    {
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_id[i]);
+      face_vft = hicn_face_get_vft (face->shared.face_type);
+      dpo_id_t face_dpo = DPO_INVALID;
+      face_vft->hicn_face_get_dpo (face, &face_dpo);
+
+      if (!dpo_id_is_valid (&face_dpo))
+       {
+         vlib_cli_output (vm, "Face %d not found, skip...\n", face_id[i]);
+         return ret;
+       }
+      else
+       {
+         face_dpo_tmp[n_face_dpo++] = face_dpo;
+       }
+    }
+
+  ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index);
+
+  if (ret == HICN_ERROR_ROUTE_NOT_FOUND)
+    {
+      /* The Fib entry does not exist */
+      /* At this point the face exists in the face table */
+      fib_prefix_from_ip46_addr (prefix, &fib_pfx);
+      fib_pfx.fp_len = plen;
+
+      dpo_id_t nhops[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+      for (int i = 0; i < n_face_dpo; i++)
+       {
+         clib_memcpy (&nhops[i], &face_dpo_tmp[i], sizeof (dpo_id_t));
+       }
+
+      ret =
+       default_dpo.hicn_dpo_create (fib_pfx.fp_proto, nhops, n_face_dpo,
+                                    &dpo_idx);
+
+      if (ret)
+       {
+         return ret;
+       }
+      /* the value we got when we registered */
+      /*
+       * This should be taken from the name?!? the index of the
+       * object
+       */
+      dpo_set (&dpo,
+              default_dpo.hicn_dpo_get_type (),
+              (ip46_address_is_ip4 (prefix) ? DPO_PROTO_IP4 : DPO_PROTO_IP6),
+              dpo_idx);
+
+      /* Here is where we create the "via" like route */
+      /*
+       * For the moment we use the global one the prefix you want
+       * to match Neale suggested -- FIB_SOURCE_HICN the client
+       * that is adding them -- no easy explanation at this time…
+       */
+      fib_node_index_t new_fib_node_index =
+       fib_table_entry_special_dpo_add (fib_index,
+                                        &fib_pfx,
+                                        FIB_SOURCE_PLUGIN_HI,
+                                        FIB_ENTRY_FLAG_EXCLUSIVE,
+                                        &dpo);
+
+      /* We added a route, therefore add one lock to the table */
+      fib_table_lock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+
+      dpo_unlock (&dpo);
+      ret =
+       (new_fib_node_index !=
+        FIB_NODE_INDEX_INVALID) ? HICN_ERROR_NONE :
+       HICN_ERROR_ROUTE_NO_INSERT;
+
+      /*
+       * TODO: we might want to store the fib index in the face.
+       * This will help to update the fib entries when a face is
+       * deleted. Fib_index_t is returned from
+       * fib_table_entry_special_dpo_add.
+       */
+    }
+  else if (ret == HICN_ERROR_NONE)
+    {
+      ret = HICN_ERROR_ROUTE_ALREADY_EXISTS;
+    }
+  return ret;
+}
+
+int
+hicn_route_add_nhops (hicn_face_id_t * face_id, u32 len,
+                     const ip46_address_t * prefix, u8 plen)
+{
+  const dpo_id_t *hicn_dpo_id;
+  int ret = HICN_ERROR_NONE;
+  dpo_id_t faces_dpo_tmp[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+  int n_face_dpo = 0;
+  const hicn_dpo_vft_t *dpo_vft;
+  u32 fib_index;
+  vlib_main_t *vm = vlib_get_main ();
+  hicn_face_vft_t *face_vft = NULL;
+
+  if (face_id == NULL)
+    {
+      return HICN_ERROR_ROUTE_INVAL;
+    }
+  /*
+   * Check is the faces are available, otherwise skip the face
+   * id_adjacency existance is not checked. It should be checked before
+   * sending a packet out
+   */
+  for (int i = 0; i < clib_min (HICN_PARAM_FIB_ENTRY_NHOPS_MAX, len); i++)
+    {
+      hicn_face_t *face = hicn_dpoi_get_from_idx (face_id[i]);
+      face_vft = hicn_face_get_vft (face->shared.face_type);
+      dpo_id_t face_dpo = DPO_INVALID;
+      face_vft->hicn_face_get_dpo (face, &face_dpo);
+
+      if (!dpo_id_is_valid (&face_dpo))
+       {
+         vlib_cli_output (vm, "Face %d not found, skip...\n", face_id[i]);
+         return ret;
+       }
+      else
+       {
+         faces_dpo_tmp[n_face_dpo++] = face_dpo;
+       }
+    }
+
+  ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index);
+
+  if (ret == HICN_ERROR_NONE)
+    {
+      for (int i = 0; i < n_face_dpo && (ret == HICN_ERROR_NONE); i++)
+       {
+         u32 vft_id = hicn_dpo_get_vft_id (hicn_dpo_id);
+         dpo_vft = hicn_dpo_get_vft (vft_id);
+         ret = dpo_vft->hicn_dpo_add_update_nh (&faces_dpo_tmp[i],
+                                                hicn_dpo_id->dpoi_index);
+       }
+    }
+  return ret;
+}
+
+int
+hicn_route_del (ip46_address_t * prefix, u8 plen)
+{
+  fib_prefix_t fib_pfx;
+  const dpo_id_t *hicn_dpo_id;
+  int ret = HICN_ERROR_NONE;
+  u32 fib_index;
+
+  /* At this point the face exists in the face table */
+  fib_prefix_from_ip46_addr (prefix, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+  /* Remove the fib entry only if the dpo is of type hicn */
+  ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index);
+
+  if (ret == HICN_ERROR_NONE)
+    {
+      fib_table_entry_special_remove (HICN_FIB_TABLE, &fib_pfx,
+                                     FIB_SOURCE_PLUGIN_HI);
+
+      /*
+       * Remove the lock from the table. We keep one lock per route
+       */
+      fib_table_unlock (fib_index, fib_pfx.fp_proto, FIB_SOURCE_PLUGIN_HI);
+    }
+  //Remember to remove the lock from the table when removing the entry
+  return ret;
+}
+
+int
+hicn_route_del_nhop (ip46_address_t * prefix, u8 plen, hicn_face_id_t face_id)
+{
+
+  fib_prefix_t fib_pfx;
+  const dpo_id_t *hicn_dpo_id;
+  int ret;
+  u32 vft_id;
+  const hicn_dpo_vft_t *dpo_vft;
+  u32 fib_index;
+
+  /* At this point the face exists in the face table */
+  fib_prefix_from_ip46_addr (prefix, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+  ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index);
+
+  /* Check if the dpo is an hicn_dpo_t */
+  if (ret == HICN_ERROR_NONE)
+    {
+      vft_id = hicn_dpo_get_vft_id (hicn_dpo_id);
+      dpo_vft = hicn_dpo_get_vft (vft_id);
+      return dpo_vft->hicn_dpo_del_nh (face_id, hicn_dpo_id->dpoi_index,
+                                      &fib_pfx);
+    }
+  //Remember to remove the lock from the table when removing the entry
+  return ret;
+}
+
+int
+hicn_route_set_strategy (ip46_address_t * prefix, u8 plen, u8 strategy_id)
+{
+  fib_prefix_t fib_pfx;
+  const dpo_id_t *hicn_dpo_id;
+  dpo_id_t new_dpo_id = DPO_INVALID;
+  int ret;
+  hicn_dpo_ctx_t *old_hicn_dpo_ctx;
+  const hicn_dpo_vft_t *old_dpo_vft;
+  const hicn_dpo_vft_t *new_dpo_vft;
+  index_t new_hicn_dpo_idx;
+  u32 fib_index;
+  u32 old_vft_id;
+
+  /* At this point the face exists in the face table */
+  fib_prefix_from_ip46_addr (prefix, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+  ret = hicn_route_get_dpo (prefix, plen, &hicn_dpo_id, &fib_index);
+
+  if (ret == HICN_ERROR_NONE)
+    {
+      old_vft_id = hicn_dpo_get_vft_id (hicn_dpo_id);
+      old_dpo_vft = hicn_dpo_get_vft (old_vft_id);
+      old_hicn_dpo_ctx =
+       old_dpo_vft->hicn_dpo_get_ctx (hicn_dpo_id->dpoi_index);
+
+      new_dpo_vft = hicn_dpo_get_vft_from_id (strategy_id);
+
+      if (new_dpo_vft == NULL)
+       return HICN_ERROR_STRATEGY_NOT_FOUND;
+
+      /* Create a new dpo for the new strategy */
+      new_dpo_vft->hicn_dpo_create (hicn_dpo_id->dpoi_proto,
+                                   old_hicn_dpo_ctx->next_hops,
+                                   old_hicn_dpo_ctx->entry_count,
+                                   &new_hicn_dpo_idx);
+
+      /* the value we got when we registered */
+      dpo_set (&new_dpo_id,
+              new_dpo_vft->hicn_dpo_get_type (),
+              (ip46_address_is_ip4 (prefix) ? DPO_PROTO_IP4 :
+               DPO_PROTO_IP6), new_hicn_dpo_idx);
+
+      /* Here is where we create the "via" like route */
+      /*
+       * For the moment we use the global one the prefix you want
+       * to match Neale suggested -- FIB_SOURCE_HICN the client
+       * that is adding them -- no easy explanation at this time…
+       */
+      fib_node_index_t new_fib_node_index =
+       fib_table_entry_special_dpo_update (fib_index,
+                                           &fib_pfx,
+                                           FIB_SOURCE_PLUGIN_HI,
+                                           FIB_ENTRY_FLAG_EXCLUSIVE,
+                                           &new_dpo_id);
+
+      dpo_unlock (&new_dpo_id);
+      ret =
+       (new_fib_node_index !=
+        FIB_NODE_INDEX_INVALID) ? HICN_ERROR_NONE :
+       HICN_ERROR_ROUTE_NOT_UPDATED;
+    }
+  //Remember to remove the lock from the table when removing the entry
+  return ret;
+
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/route.h b/hicn-plugin/src/route.h
new file mode 100755 (executable)
index 0000000..be15b99
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_ROUTE__
+#define __HICN_ROUTE__
+
+#include <vlib/vlib.h>
+#include <vppinfra/error.h>
+#include "hicn.h"
+#include "faces/face.h"
+
+/*
+ * Retrieve the hicn dpo corresponding to a hicn prefix
+ */
+int
+hicn_route_get_dpo (const ip46_address_t * prefix, u8 plen,
+                   const dpo_id_t ** hicn_dpo, u32 * fib_index);
+
+/*
+ * Add a new route for a name prefix
+ */
+int
+hicn_route_add (hicn_face_id_t * face_id, u32 len,
+               const ip46_address_t * prefix, u8 plen);
+
+/*
+ * Add new next hops for a prefix route
+ */
+int
+hicn_route_add_nhops (hicn_face_id_t * face_id, u32 len,
+                     const ip46_address_t * prefix, u8 plen);
+
+/* Remove a route for a name prefix */
+int hicn_route_del (ip46_address_t * prefix, u8 plen);
+
+/* Remove a next hop route for a name prefix */
+int hicn_route_del_nhop (ip46_address_t * prefix, u8 plen, u32 face_id);
+
+/* Remove a next hop route for a name prefix */
+int
+hicn_route_set_strategy (ip46_address_t * prefix, u8 plen, u32 strategy_id);
+
+#endif /* //__HICN_ROUTE__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/state.h b/hicn-plugin/src/state.h
new file mode 100755 (executable)
index 0000000..7e984e6
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_STATE__
+#define __HICN_STATE__
+
+#include <netinet/in.h>
+#include <vnet/buffer.h>
+
+#include "hicn.h"
+#include "pcs.h"
+#include "hashtb.h"
+#include "strategy.h"
+#include "strategy_dpo_ctx.h"
+#include "strategy_dpo_manager.h"
+
+always_inline void
+hicn_prefetch_pcs_entry (hicn_buffer_t * hicnb, hicn_pit_cs_t * pitcs)
+{
+  hicn_hash_node_t *node = pool_elt_at_index (pitcs->pcs_table->ht_nodes,
+                                             hicnb->node_id);
+
+  hicn_hash_bucket_t *bucket;
+  if (hicnb->hash_bucket_flags & HICN_HASH_NODE_OVERFLOW_BUCKET)
+    bucket =
+      pool_elt_at_index (pitcs->pcs_table->ht_overflow_buckets,
+                        hicnb->bucket_id);
+  else
+    bucket =
+      (hicn_hash_bucket_t *) (pitcs->pcs_table->ht_buckets +
+                             hicnb->bucket_id);
+
+  CLIB_PREFETCH (node, CLIB_CACHE_LINE_BYTES, STORE);
+  CLIB_PREFETCH (bucket, CLIB_CACHE_LINE_BYTES, STORE);
+}
+
+always_inline void
+hicn_get_internal_state (hicn_buffer_t * hicnb, hicn_pit_cs_t * pitcs,
+                        hicn_hash_node_t ** node,
+                        const hicn_strategy_vft_t ** strategy_vft,
+                        const hicn_dpo_vft_t ** dpo_vft, u8 * dpo_ctx_id,
+                        hicn_hash_entry_t ** hash_entry)
+{
+  *node = pool_elt_at_index (pitcs->pcs_table->ht_nodes, hicnb->node_id);
+  *strategy_vft = hicn_dpo_get_strategy_vft (hicnb->vft_id);
+  *dpo_vft = hicn_dpo_get_vft (hicnb->vft_id);
+  *dpo_ctx_id = hicnb->dpo_ctx_id;
+
+  hicn_hash_bucket_t *bucket;
+  if (hicnb->hash_bucket_flags & HICN_HASH_NODE_OVERFLOW_BUCKET)
+    bucket =
+      pool_elt_at_index (pitcs->pcs_table->ht_overflow_buckets,
+                        hicnb->bucket_id);
+  else
+    bucket =
+      (hicn_hash_bucket_t *) (pitcs->pcs_table->ht_buckets +
+                             hicnb->bucket_id);
+
+  *hash_entry = &(bucket->hb_entries[hicnb->hash_entry_id]);
+}
+
+/*
+ * This function set the PCS entry index, the dpo index and the vft index in
+ * the opaque2 buffer. In this way, the interest-hitpit and interest-hitcs
+ * nodes can prefetch the corresponding state (PIT entry, dpo_ctx and the
+ * strategy vft
+ */
+always_inline void
+hicn_store_internal_state (vlib_buffer_t * b, u64 name_hash, u32 node_id,
+                          u8 dpo_ctx_id, u8 vft_id, u8 hash_entry_id,
+                          u32 bucket_id, u8 bucket_is_overflow)
+{
+  hicn_buffer_t *hicnb = hicn_get_buffer (b);
+  hicnb->name_hash = name_hash;
+  hicnb->node_id = node_id;
+  hicnb->dpo_ctx_id = dpo_ctx_id;
+  hicnb->vft_id = vft_id;
+  hicnb->hash_entry_id = hash_entry_id;
+  hicnb->bucket_id = bucket_id;
+  hicnb->hash_bucket_flags =
+    HICN_HASH_NODE_OVERFLOW_BUCKET * bucket_is_overflow;
+}
+
+#endif /* // __HICN_STATE__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/strategies/dpo_mw.c b/hicn-plugin/src/strategies/dpo_mw.c
new file mode 100755 (executable)
index 0000000..882368e
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2017-2019 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 "../strategy_dpo_ctx.h"
+#include "dpo_mw.h"
+#include "strategy_mw.h"
+#include "../strategy_dpo_manager.h"
+
+hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx_pool;
+
+const static char *const hicn_ip6_nodes[] = {
+  "hicn-mw-strategy",          // this is the name you give your node in VLIB_REGISTER_NODE
+  NULL,
+};
+
+const static char *const hicn_ip4_nodes[] = {
+  "hicn-mw-strategy",          // this is the name you give your node in VLIB_REGISTER_NODE
+  NULL,
+};
+
+const static char *const *const hicn_nodes_mw[DPO_PROTO_NUM] = {
+  [DPO_PROTO_IP6] = hicn_ip6_nodes,
+  [DPO_PROTO_IP4] = hicn_ip4_nodes,
+};
+
+/**
+ * @brief DPO type value for the mw_strategy
+ */
+static dpo_type_t hicn_dpo_type_mw;
+
+static const hicn_dpo_vft_t hicn_dpo_mw_vft = {
+  .hicn_dpo_get_ctx = &hicn_strategy_mw_ctx_get,
+  .hicn_dpo_is_type = &hicn_dpo_is_type_strategy_mw,
+  .hicn_dpo_get_type = &hicn_dpo_strategy_mw_get_type,
+  .hicn_dpo_module_init = &hicn_dpo_strategy_mw_module_init,
+  .hicn_dpo_create = &hicn_strategy_mw_ctx_create,
+  .hicn_dpo_add_update_nh = &hicn_strategy_mw_ctx_add_nh,
+  .hicn_dpo_del_nh = &hicn_strategy_mw_ctx_del_nh,
+  .hicn_dpo_lock_dpo_ctx = &hicn_strategy_mw_ctx_lock,
+  .hicn_dpo_unlock_dpo_ctx = hicn_strategy_mw_ctx_unlock,
+  .format_hicn_dpo = &format_hicn_dpo_strategy_mw
+};
+
+int
+hicn_dpo_is_type_strategy_mw (const dpo_id_t * dpo)
+{
+  return dpo->dpoi_type == hicn_dpo_type_mw;
+}
+
+void
+hicn_dpo_strategy_mw_module_init (void)
+{
+  pool_validate_index (hicn_strategy_mw_ctx_pool, 0);
+  /*
+   * Register our type of dpo
+   */
+  hicn_dpo_type_mw =
+    hicn_dpo_register_new_type (hicn_nodes_mw, &hicn_dpo_mw_vft,
+                               hicn_mw_strategy_get_vft (),
+                               &dpo_strategy_mw_ctx_vft);
+}
+
+u8 *
+format_hicn_dpo_strategy_mw (u8 * s, va_list * ap)
+{
+
+  u32 indent = va_arg (*ap, u32);
+  s =
+    format (s,
+           "Static Weights: weights are updated by the control plane, next hop is the one with the maximum weight.\n",
+           indent);
+  return (s);
+}
+
+dpo_type_t
+hicn_dpo_strategy_mw_get_type (void)
+{
+  return hicn_dpo_type_mw;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void
+hicn_strategy_mw_ctx_lock (dpo_id_t * dpo)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx =
+    (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (dpo->dpoi_index);
+  hicn_strategy_mw_ctx->default_ctx.locks++;
+}
+
+void
+hicn_strategy_mw_ctx_unlock (dpo_id_t * dpo)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx =
+    (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (dpo->dpoi_index);
+  hicn_strategy_mw_ctx->default_ctx.locks--;
+
+  if (0 == hicn_strategy_mw_ctx->default_ctx.locks)
+    {
+      pool_put (hicn_strategy_mw_ctx_pool, hicn_strategy_mw_ctx);
+    }
+}
+
+u8 *
+format_hicn_strategy_mw_ctx (u8 * s, va_list * ap)
+{
+  int i = 0;
+  index_t index = va_arg (*ap, index_t);
+  hicn_strategy_mw_ctx_t *dpo = NULL;
+  dpo_id_t *next_hop = NULL;
+  hicn_face_vft_t *face_vft = NULL;
+  u32 indent = va_arg (*ap, u32);;
+
+  dpo = (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (index);
+
+  s = format (s, "hicn-mw");
+  for (i = 0; i < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; i++)
+    {
+      next_hop = &dpo->default_ctx.next_hops[i];
+      face_vft = hicn_face_get_vft (next_hop->dpoi_type);
+      if (face_vft != NULL)
+       {
+         s = format (s, "\n");
+         s =
+           format (s, "%U ", face_vft->format_face, next_hop->dpoi_index,
+                   indent);
+         s = format (s, "weight %u", dpo->weight[i]);
+       }
+    }
+
+  return (s);
+}
+
+static index_t
+hicn_strategy_mw_ctx_get_index (hicn_strategy_mw_ctx_t * cd)
+{
+  return (cd - hicn_strategy_mw_ctx_pool);
+}
+
+int
+hicn_strategy_mw_ctx_create (dpo_proto_t proto, const dpo_id_t * next_hop,
+                            int nh_len, index_t * dpo_idx)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx;
+  int ret = HICN_ERROR_NONE, i;
+  dpo_id_t invalid = NEXT_HOP_INVALID;
+
+  /* Allocate a hicn_dpo_ctx on the vpp pool and initialize it */
+  pool_get (hicn_strategy_mw_ctx_pool, hicn_strategy_mw_ctx);
+
+  *dpo_idx = hicn_strategy_mw_ctx_get_index (hicn_strategy_mw_ctx);
+  for (int i = 0; i < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; i++)
+    {
+      hicn_strategy_mw_ctx->default_ctx.next_hops[i] = invalid;
+    }
+
+  hicn_strategy_mw_ctx->default_ctx.entry_count = 0;
+  hicn_strategy_mw_ctx->default_ctx.locks = 0;
+
+  for (i = 0; i < HICN_PARAM_FIB_ENTRY_NHOPS_MAX && i < nh_len; i++)
+    {
+      clib_memcpy (&hicn_strategy_mw_ctx->default_ctx.next_hops[i],
+                  &next_hop[i], sizeof (dpo_id_t));
+      hicn_strategy_mw_ctx->default_ctx.entry_count++;
+    }
+
+  memset (hicn_strategy_mw_ctx->weight, 0, HICN_PARAM_FIB_ENTRY_NHOPS_MAX);
+
+  return ret;
+}
+
+hicn_dpo_ctx_t *
+hicn_strategy_mw_ctx_get (index_t index)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx = NULL;
+  if (!pool_is_free_index (hicn_strategy_mw_ctx_pool, index))
+    {
+      hicn_strategy_mw_ctx =
+       (pool_elt_at_index (hicn_strategy_mw_ctx_pool, index));
+    }
+  return &hicn_strategy_mw_ctx->default_ctx;
+}
+
+int
+hicn_strategy_mw_ctx_add_nh (const dpo_id_t * nh, index_t dpo_idx)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx =
+    (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (dpo_idx);
+
+  if (hicn_strategy_mw_ctx != NULL)
+    {
+
+      int empty = hicn_strategy_mw_ctx->default_ctx.entry_count;
+
+      /* Iterate through the list of faces to add new faces */
+      for (int i = 0; i < hicn_strategy_mw_ctx->default_ctx.entry_count; i++)
+       {
+         if (!memcmp
+             (nh, &hicn_strategy_mw_ctx->default_ctx.next_hops[i],
+              sizeof (dpo_id_t)))
+           {
+             /* If face is marked as deleted, ignore it */
+             hicn_face_t *face =
+               hicn_dpoi_get_from_idx (hicn_strategy_mw_ctx->
+                                       default_ctx.next_hops[i].dpoi_index);
+             if (face->shared.flags & HICN_FACE_FLAGS_DELETED)
+               {
+                 continue;
+               }
+             return HICN_ERROR_DPO_CTX_NHOPS_EXISTS;
+           }
+       }
+
+      /* Get an empty place */
+      if (empty > HICN_PARAM_FIB_ENTRY_NHOPS_MAX)
+       {
+         return HICN_ERROR_DPO_CTX_NHOPS_NS;
+       }
+      if (PREDICT_FALSE (empty > HICN_PARAM_FIB_ENTRY_NHOPS_MAX))
+       {
+         return HICN_ERROR_DPO_CTX_NHOPS_NS;
+       }
+      clib_memcpy (&hicn_strategy_mw_ctx->default_ctx.next_hops[empty], nh,
+                  sizeof (dpo_id_t));
+      hicn_strategy_mw_ctx->default_ctx.entry_count++;
+
+      return HICN_ERROR_NONE;
+    }
+  return HICN_ERROR_DPO_CTX_NOT_FOUND;
+}
+
+int
+hicn_strategy_mw_ctx_del_nh (hicn_face_id_t face_id, index_t dpo_idx,
+                            fib_prefix_t * fib_pfx)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx =
+    (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (dpo_idx);
+  int ret = HICN_ERROR_NONE;
+  int nh_id = ~0;
+  dpo_id_t invalid = NEXT_HOP_INVALID;
+
+  if (hicn_strategy_mw_ctx != NULL)
+    {
+      for (int i = 0; i < hicn_strategy_mw_ctx->default_ctx.entry_count; i++)
+       {
+         if (hicn_strategy_mw_ctx->default_ctx.next_hops[i].dpoi_index ==
+             face_id)
+           {
+             nh_id = i;
+             hicn_face_unlock (&hicn_strategy_mw_ctx->default_ctx.
+                               next_hops[i]);
+             hicn_strategy_mw_ctx->default_ctx.next_hops[i] = invalid;
+             hicn_strategy_mw_ctx->default_ctx.entry_count--;
+           }
+       }
+
+      if (0 == hicn_strategy_mw_ctx->default_ctx.entry_count)
+       {
+         fib_table_entry_special_remove (HICN_FIB_TABLE, fib_pfx,
+                                         FIB_SOURCE_PLUGIN_HI);
+       }
+    }
+  else
+    {
+      ret = HICN_ERROR_DPO_CTX_NOT_FOUND;
+    }
+
+  /*
+   * Remove any possible hole in the arrays of dpos
+   */
+  if (hicn_strategy_mw_ctx->default_ctx.entry_count > 0 && nh_id != ~0
+      && nh_id < hicn_strategy_mw_ctx->default_ctx.entry_count - 1)
+    {
+      int i;
+      for (i = nh_id; i < hicn_strategy_mw_ctx->default_ctx.entry_count; i++)
+       {
+         clib_memcpy (&hicn_strategy_mw_ctx->default_ctx.next_hops[i],
+                      &hicn_strategy_mw_ctx->default_ctx.next_hops[i + 1],
+                      sizeof (dpo_id_t));
+       }
+      /* Set as invalid the last dpo */
+      hicn_strategy_mw_ctx->default_ctx.next_hops[i] = invalid;
+    }
+  return ret;
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/strategies/dpo_mw.h b/hicn-plugin/src/strategies/dpo_mw.h
new file mode 100755 (executable)
index 0000000..a8c0a3b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_DPO_MW_H__
+#define __HICN_DPO_MW_H__
+
+#include <vnet/dpo/dpo.h>
+#include "../strategy_dpo_ctx.h"
+
+typedef struct hicn_strategy_mw_ctx_s
+{
+  hicn_dpo_ctx_t default_ctx;
+
+  u8 weight[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+} hicn_strategy_mw_ctx_t;
+
+/**
+ * @brief Lock the mw ctx
+ *
+ * @param dpo Identifier of the dpo of the mw ctx
+ */
+void hicn_strategy_mw_ctx_lock (dpo_id_t * dpo);
+
+/**
+ * @brief Unlock the mw ctx
+ *
+ * @param dpo Identifier of the dpo of the mw ctx
+ */
+void hicn_strategy_mw_ctx_unlock (dpo_id_t * dpo);
+
+/**
+ * @brief Format the dpo ctx for a human-readable string
+ *
+ * @param s String to which to append the formatted dpo ctx
+ * @param ap List of parameters for the formatting
+ *
+ * @result The string with the formatted dpo ctx
+ */
+u8 *format_hicn_strategy_mw_ctx (u8 * s, va_list * ap);
+
+const static dpo_vft_t dpo_strategy_mw_ctx_vft = {
+  .dv_lock = hicn_strategy_mw_ctx_lock,
+  .dv_unlock = hicn_strategy_mw_ctx_unlock,
+  .dv_format = format_hicn_strategy_mw_ctx,
+};
+
+/**
+ * @brief Retrieve an hicn_strategy_mw_ctx object
+ *
+ * @param indext Index of the hicn_dpo_ctx to retrieve
+ * @return The hicn_dpo_ctx object or NULL
+ */
+hicn_dpo_ctx_t *hicn_strategy_mw_ctx_get (index_t index);
+
+/**
+ * @brief Create a new mw ctx
+ *
+ * @param proto The protocol to which the dpo is meant for (see vpp docs)
+ * @param next_hop A list of next hops to be inserted in the dpo ctx
+ * @param nh_len Size of the list
+ * @param dpo_idx index_t that will hold the index of the created dpo ctx
+ * @return HICN_ERROR_NONE if the creation was fine, otherwise EINVAL
+ */
+int
+hicn_strategy_mw_ctx_create (dpo_proto_t proto, const dpo_id_t * next_hop,
+                            int nh_len, index_t * dpo_idx);
+
+/**
+ * @brief Add or update a next hop in the dpo ctx.
+ *
+ * This function is meant to be used in the control plane and not in the data plane,
+ * as it is not optimized for the latter.
+ *
+ * @param nh Next hop to insert in the dpo ctx
+ * @param dpo_idx Index of the dpo ctx to update with the new or updated next
+ * hop
+ * @return HICN_ERROR_NONE if the update or insert was fine,
+ * otherwise HICN_ERROR_DPO_CTX_NOT_FOUND
+ */
+int hicn_strategy_mw_ctx_add_nh (const dpo_id_t * nh, index_t dpo_idx);
+
+/**
+ * @brief Delete a next hop in the dpo ctx.
+ *
+ * @param face_id Face identifier of the next hop
+ * @param dpo_idx Index of the dpo ctx to update with the new or updated next
+ * hop
+ * @return HICN_ERROR_NONE if the update or insert was fine,
+ * otherwise HICN_ERROR_DPO_CTS_NOT_FOUND
+ */
+int
+hicn_strategy_mw_ctx_del_nh (hicn_face_id_t face_id, index_t dpo_idx,
+                            fib_prefix_t * fib_pfx);
+
+/**
+ * @brief Prefetch a dpo
+ *
+ * @param dpo_idx Index of the dpo ctx to prefetch
+ */
+void hicn_strategy_mw_ctx_prefetch (index_t dpo_idx);
+
+int hicn_dpo_is_type_strategy_mw (const dpo_id_t * dpo);
+
+void hicn_dpo_strategy_mw_module_init (void);
+
+dpo_type_t hicn_dpo_strategy_mw_get_type (void);
+
+u8 *format_hicn_dpo_strategy_mw (u8 * s, va_list * ap);
+
+
+#endif // __HICN_DPO_MW_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/strategies/strategy_mw.c b/hicn-plugin/src/strategies/strategy_mw.c
new file mode 100755 (executable)
index 0000000..144dd14
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "../strategy.h"
+#include "../strategy_dpo_ctx.h"
+#include "dpo_mw.h"
+#include "../faces/face.h"
+#include "../route.h"
+#include "../pcs.h"
+#include "../strategy_dpo_manager.h"
+
+/* Simple strategy that chooses the next hop with the maximum weight */
+/* It does not require to exend the hicn_dpo */
+void hicn_receive_data_mw (index_t dpo_idx, int nh_idx);
+void hicn_add_interest_mw (index_t dpo_idx, hicn_hash_entry_t * pit_entry);
+void hicn_on_interest_timeout_mw (index_t dpo_idx);
+u32 hicn_select_next_hop_mw (index_t dpo_idx, int *nh_idx,
+                            dpo_id_t ** outface);
+u32 get_strategy_node_index_mw (void);
+
+static hicn_strategy_vft_t hicn_strategy_mw_vft = {
+  .hicn_receive_data = &hicn_receive_data_mw,
+  .hicn_add_interest = &hicn_add_interest_mw,
+  .hicn_on_interest_timeout = &hicn_on_interest_timeout_mw,
+  .hicn_select_next_hop = &hicn_select_next_hop_mw,
+  .get_strategy_node_index = get_strategy_node_index_mw
+};
+
+/* Stats string values */
+static char *hicn_strategy_error_strings[] = {
+#define _(sym, string) string,
+  foreach_hicnfwd_error
+#undef _
+};
+
+/*
+ * Return the vft of the strategy.
+ */
+hicn_strategy_vft_t *
+hicn_mw_strategy_get_vft (void)
+{
+  return &hicn_strategy_mw_vft;
+}
+
+/* Registration struct for a graph node */
+vlib_node_registration_t hicn_mw_strategy_node;
+
+u32
+get_strategy_node_index_mw (void)
+{
+  return hicn_mw_strategy_node.index;
+}
+
+/* DPO should be give in input as it containes all the information to calculate the next hops*/
+u32
+hicn_select_next_hop_mw (index_t dpo_idx, int *nh_idx, dpo_id_t ** outface)
+{
+  hicn_strategy_mw_ctx_t *hicn_strategy_mw_ctx =
+    (hicn_strategy_mw_ctx_t *) hicn_strategy_mw_ctx_get (dpo_idx);
+
+  u8 next_hop_index = 0;
+  for (int i = 0; i < HICN_PARAM_FIB_ENTRY_NHOPS_MAX; i++)
+    {
+      if (dpo_id_is_valid (&hicn_strategy_mw_ctx->default_ctx.next_hops[i]))
+       {
+         if (hicn_strategy_mw_ctx->weight[next_hop_index] <
+             hicn_strategy_mw_ctx->weight[i])
+           {
+             next_hop_index = i;
+           }
+       }
+    }
+
+  if (!dpo_id_is_valid
+      (&hicn_strategy_mw_ctx->default_ctx.next_hops[next_hop_index]))
+    return HICN_ERROR_MW_STRATEGY_NH_NOT_FOUND;
+
+  *outface =
+    (dpo_id_t *) & hicn_strategy_mw_ctx->default_ctx.
+    next_hops[next_hop_index];
+
+  return HICN_ERROR_NONE;
+}
+
+uword
+hicn_mw_strategy_node_fn (vlib_main_t * vm,
+                         vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+  return hicn_forward_interest_fn (vm, node, frame, &hicn_strategy_mw_vft,
+                                  &hicn_mw_strategy_node);
+}
+
+void
+hicn_add_interest_mw (index_t dpo_ctx_idx, hicn_hash_entry_t * hash_entry)
+{
+  hash_entry->dpo_ctx_id = dpo_ctx_idx;
+  dpo_id_t hicn_dpo_id =
+    { hicn_dpo_strategy_mw_get_type (), 0, 0, dpo_ctx_idx };
+  hicn_strategy_mw_ctx_lock (&hicn_dpo_id);
+  hash_entry->vft_id = hicn_dpo_get_vft_id (&hicn_dpo_id);
+}
+
+void
+hicn_on_interest_timeout_mw (index_t dpo_idx)
+{
+  /* Nothign to do in the mw strategy when we receive an interest */
+}
+
+void
+hicn_receive_data_mw (index_t dpo_idx, int nh_idx)
+{
+}
+
+
+/* packet trace format function */
+static u8 *
+hicn_strategy_format_trace_mw (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 *);
+  hicn_strategy_trace_t *t = va_arg (*args, hicn_strategy_trace_t *);
+
+  s = format (s, "Strategy_mw: pkt: %d, sw_if_index %d, next index %d",
+             (int) t->pkt_type, t->sw_if_index, t->next_index);
+  return (s);
+}
+
+/*
+ * Node registration for the forwarder node
+ */
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_mw_strategy_node) =
+{
+  .name = "hicn-mw-strategy",
+  .function = hicn_mw_strategy_node_fn,
+  .vector_size = sizeof (u32),
+  .runtime_data_bytes = sizeof (int) + sizeof(hicn_pit_cs_t *),
+  .format_trace = hicn_strategy_format_trace_mw,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+  .n_errors = ARRAY_LEN (hicn_strategy_error_strings),
+  .error_strings = hicn_strategy_error_strings,
+  .n_next_nodes = HICN_STRATEGY_N_NEXT,
+  .next_nodes = {
+    [HICN_STRATEGY_NEXT_INTEREST_HITPIT] = "hicn-interest-hitpit",
+    [HICN_STRATEGY_NEXT_ERROR_DROP] = "error-drop",
+  },
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/strategies/strategy_mw.h b/hicn-plugin/src/strategies/strategy_mw.h
new file mode 100755 (executable)
index 0000000..10b08c0
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_STRATEGY_MW_H__
+#define __HICN_STRATEGY_MW_H__
+
+#include "../strategy.h"
+
+hicn_strategy_vft_t *hicn_mw_strategy_get_vft (void);
+
+#endif // __HICN_STRATEGY_MW_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/strategies/strategy_mw_cli.c b/hicn-plugin/src/strategies/strategy_mw_cli.c
new file mode 100755 (executable)
index 0000000..ff41252
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/vnet.h>
+#include <vnet/dpo/dpo.h>
+#include <vlib/vlib.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_table.h>
+
+#include "../strategy_dpo_manager.h"
+#include "../faces/face.h"
+#include "../error.h"
+#include "../route.h"
+#include "dpo_mw.h"
+
+static clib_error_t *
+hicn_mw_strategy_cli_set_weight_command_fn (vlib_main_t * vm,
+                                           unformat_input_t * main_input,
+                                           vlib_cli_command_t * cmd)
+{
+  clib_error_t *cl_err = 0;
+  int ret = HICN_ERROR_NONE;
+  ip46_address_t prefix;
+  hicn_face_id_t faceid = HICN_FACE_NULL;
+  u32 fib_index;
+  u32 weight = HICN_PARAM_FIB_ENTRY_NHOP_WGHT_DFLT;
+  u32 plen = 0;
+  hicn_dpo_ctx_t *hicn_dpo_ctx;
+  const dpo_id_t *hicn_dpo_id;
+  u32 vft_id;
+  const hicn_dpo_vft_t *dpo_vft;
+
+  /* Get a line of input. */
+  unformat_input_t _line_input, *line_input = &_line_input;
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "prefix %U/%u", unformat_ip46_address,
+                       &prefix, IP46_TYPE_ANY, &plen))
+           ;
+         else if (unformat (line_input, "face %u", &faceid))
+           ;
+         else if (unformat (line_input, "weight %u", &weight))
+           ;
+         else
+           {
+             return clib_error_return (0, "%s",
+                                       get_error_string
+                                       (HICN_ERROR_CLI_INVAL));
+           }
+
+       }
+    }
+
+  if (((weight < 0) || (weight > HICN_PARAM_FIB_ENTRY_NHOP_WGHT_MAX)))
+    {
+      cl_err = clib_error_return (0,
+                                 "Next-hop weight must be between 0 and %d",
+                                 (int) HICN_PARAM_FIB_ENTRY_NHOP_WGHT_MAX);
+      goto done;
+    }
+
+  if (((ip46_address_is_zero (&prefix)) || faceid == HICN_FACE_NULL))
+    {
+      cl_err =
+       clib_error_return (0, "Please specify prefix and a valid faceid...");
+      goto done;
+    }
+
+  fib_prefix_t fib_pfx;
+  fib_prefix_from_ip46_addr (&prefix, &fib_pfx);
+  fib_pfx.fp_len = plen;
+
+  ret = hicn_route_get_dpo (&prefix, plen, &hicn_dpo_id, &fib_index);
+
+  if (ret == HICN_ERROR_NONE)
+    {
+      vft_id = hicn_dpo_get_vft_id (hicn_dpo_id);
+      dpo_vft = hicn_dpo_get_vft (vft_id);
+      hicn_dpo_ctx = dpo_vft->hicn_dpo_get_ctx (hicn_dpo_id->dpoi_index);
+
+      if (hicn_dpo_ctx == NULL
+         || hicn_dpo_id->dpoi_type != hicn_dpo_strategy_mw_get_type ())
+       {
+         cl_err = clib_error_return (0, get_error_string (ret));
+         goto done;
+       }
+
+      hicn_strategy_mw_ctx_t *mw_dpo =
+       (hicn_strategy_mw_ctx_t *) hicn_dpo_ctx;
+      int idx = ~0;
+      for (int i = 0; i < hicn_dpo_ctx->entry_count; i++)
+       if (hicn_dpo_ctx->next_hops[i].dpoi_index == (index_t) faceid)
+         idx = i;
+
+      if (idx == ~0)
+       {
+         cl_err =
+           clib_error_return (0,
+                              get_error_string
+                              (HICN_ERROR_MW_STRATEGY_NH_NOT_FOUND));
+         goto done;
+       }
+
+      mw_dpo->weight[idx] = weight;
+    }
+  else
+    {
+      cl_err = clib_error_return (0, get_error_string (ret));
+
+    }
+
+done:
+
+  return (cl_err);
+
+}
+
+/* cli declaration for 'strategy mw' */
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND(hicn_mw_strategy_cli_set_weight_command, static)=
+{
+  .path = "hicn strategy mw set",
+  .short_help = "hicn strategy mw set prefix <prefix> face <face_id> weight <weight>",
+  .function = hicn_mw_strategy_cli_set_weight_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/strategy.c b/hicn-plugin/src/strategy.c
new file mode 100755 (executable)
index 0000000..56de34e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017-2019 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 <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "hicn.h"
+#include "parser.h"
+#include "strategy.h"
+#include "strategy_dpo_ctx.h"
+#include "face_db.h"
+#include "infra.h"
+#include "mgmt.h"
+#include "pcs.h"
+#include "state.h"
+
+/*
+ * Node context data (to be used in all the strategy nodes); we think this is
+ * per-thread/instance
+ */
+typedef struct hicn_strategy_runtime_s
+{
+  int id;
+  hicn_pit_cs_t *pitcs;
+} hicn_strategy_runtime_t;
+
+always_inline int
+hicn_new_interest (hicn_strategy_runtime_t * rt, vlib_buffer_t * b0,
+                  u32 * next, f64 tnow, u8 * nameptr,
+                  u16 namelen, dpo_id_t * outface, int nh_idx,
+                  index_t hicn_dpo_idx, hicn_strategy_vft_t * strategy,
+                  u8 isv6, vl_api_hicn_api_node_stats_get_reply_t * stats)
+{
+  int ret;
+  hicn_hash_node_t *nodep;
+  hicn_pcs_entry_t *pitp;
+  hicn_header_t *hicn0;
+  hicn_main_t *sm = &hicn_main;
+  hicn_buffer_t *hicnb0 = hicn_get_buffer (b0);
+  u32 node_id0 = 0;
+  u8 dpo_ctx_id0 = 0;
+  u8 vft_id0 = 0;
+  u8 is_cs0 = 0;
+  u8 hash_entry_id = 0;
+  u8 bucket_is_overflow = 0;
+  u32 bucket_id = ~0;
+
+
+  /* Create PIT node and init PIT entry */
+  nodep = hicn_hashtb_alloc_node (rt->pitcs->pcs_table);
+  if (PREDICT_FALSE (nodep == NULL))
+    {
+      /* Nothing we can do - no mem */
+      *next = HICN_STRATEGY_NEXT_ERROR_DROP;
+      return HICN_ERROR_HASHTB_NOMEM;
+    }
+  pitp = hicn_pit_get_data (nodep);
+  hicn_pit_init_data (pitp);
+  pitp->shared.create_time = tnow;
+
+  hicn0 = vlib_buffer_get_current (b0);
+  hicn_lifetime_t imsg_lifetime;
+  hicn_type_t type = hicnb0->type;
+  hicn_ops_vft[type.l1]->get_lifetime (type, &hicn0->protocol,
+                                      &imsg_lifetime);
+
+  if (imsg_lifetime < sm->pit_lifetime_min_ms
+      || imsg_lifetime > sm->pit_lifetime_max_ms)
+    {
+      imsg_lifetime = sm->pit_lifetime_dflt_ms;
+    }
+  pitp->shared.expire_time = hicn_pcs_get_exp_time (tnow, imsg_lifetime);
+
+  /* Set up the hash node and insert it */
+  hicn_hash_entry_t *hash_entry;
+  hicn_hashtb_init_node (rt->pitcs->pcs_table, nodep, nameptr, namelen);
+
+  ret =
+    hicn_pcs_pit_insert (rt->pitcs, pitp, nodep, &hash_entry,
+                        hicnb0->name_hash, &node_id0, &dpo_ctx_id0, &vft_id0,
+                        &is_cs0, &hash_entry_id, &bucket_id,
+                        &bucket_is_overflow);
+  if (ret == HICN_ERROR_NONE)
+    {
+      strategy->hicn_add_interest (vnet_buffer (b0)->ip.adj_index[VLIB_TX],
+                                  hash_entry);
+
+      /* Add face */
+      hicn_face_db_add_face_dpo (&hicnb0->face_dpo_id, &(pitp->u.pit.faces));
+
+      /* Remove lock on the dpo stored in the vlib_buffer */
+      dpo_unlock (&hicnb0->face_dpo_id);
+
+      *next = outface->dpoi_next_node;
+
+      vnet_buffer (b0)->ip.adj_index[VLIB_TX] = outface->dpoi_index;
+      stats->pkts_interest_count++;
+    }
+  else
+    {
+      /* Interest aggregate in PIT */
+      if (ret == HICN_ERROR_HASHTB_EXIST)
+       {
+         hicn_store_internal_state (b0, hicnb0->name_hash, node_id0,
+                                    dpo_ctx_id0, vft_id0, hash_entry_id,
+                                    bucket_id, bucket_is_overflow);
+         *next = HICN_STRATEGY_NEXT_INTEREST_HITPIT;
+       }
+      else
+       {
+         /* Send the packet to the interest-hitpit node */
+         *next = HICN_STRATEGY_NEXT_ERROR_DROP;
+       }
+      hicn_faces_flush (&(pitp->u.pit.faces));
+      hicn_hashtb_free_node (rt->pitcs->pcs_table, nodep);
+    }
+
+  return (ret);
+
+}
+
+/*
+ * ICN strategy later node for interests: - 1 packet at a time - ipv4/tcp
+ * ipv6/tcp
+ */
+uword
+hicn_forward_interest_fn (vlib_main_t * vm,
+                         vlib_node_runtime_t * node,
+                         vlib_frame_t * frame,
+                         hicn_strategy_vft_t * strategy,
+                         vlib_node_registration_t * hicn_strategy_node)
+{
+
+  u32 n_left_from, *from, *to_next, n_left_to_next;
+  hicn_strategy_next_t next_index;
+  hicn_strategy_runtime_t *rt;
+  vl_api_hicn_api_node_stats_get_reply_t stats = { 0 };
+  f64 tnow;
+
+  from = vlib_frame_vector_args (frame);
+  n_left_from = frame->n_vectors;
+  next_index = (hicn_strategy_next_t) node->cached_next_index;
+  rt = vlib_node_get_runtime_data (vm, hicn_strategy_node->index);
+  rt->pitcs = &hicn_main.pitcs;
+  /* Capture time in vpp terms */
+  tnow = vlib_time_now (vm);
+
+  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)
+       {
+         u8 isv6;
+         u8 *nameptr;
+         u16 namelen;
+         hicn_name_t name;
+         hicn_header_t *hicn0;
+         vlib_buffer_t *b0;
+         u32 bi0;
+         dpo_id_t *outface = NULL;
+         int nh_idx;
+         u32 next0 = next_index;
+         int ret;
+
+         /* Prefetch for next iteration. */
+         if (n_left_from > 1)
+           {
+             vlib_buffer_t *b1;
+             b1 = vlib_get_buffer (vm, from[1]);
+             CLIB_PREFETCH (b1, CLIB_CACHE_LINE_BYTES, LOAD);
+             CLIB_PREFETCH (&b1->trace_index, 2 * CLIB_CACHE_LINE_BYTES,
+                            STORE);
+           }
+         /* Dequeue a packet buffer */
+         bi0 = from[0];
+         from += 1;
+         n_left_from -= 1;
+         to_next[0] = bi0;
+         to_next += 1;
+         n_left_to_next -= 1;
+
+         b0 = vlib_get_buffer (vm, bi0);
+         next0 = HICN_STRATEGY_NEXT_ERROR_DROP;
+
+         ret = hicn_interest_parse_pkt (b0, &name, &namelen, &hicn0, &isv6);
+
+         stats.pkts_processed++;
+         /* Select next hop */
+         /*
+          * Double check that the interest has been through
+          * the interest-pcslookup node due to misconfiguration in
+          * the punting rules.
+          */
+         if (PREDICT_TRUE
+             (ret == HICN_ERROR_NONE && HICN_IS_NAMEHASH_CACHED (b0)
+              && strategy->hicn_select_next_hop (vnet_buffer (b0)->
+                                                 ip.adj_index[VLIB_TX],
+                                                 &nh_idx,
+                                                 &outface) ==
+              HICN_ERROR_NONE))
+           {
+             /*
+              * No need to check if parsing was successful
+              * here. Already checked in the interest_pcslookup
+              * node
+              */
+             nameptr = (u8 *) (&name);
+             hicn_new_interest (rt, b0, &next0, tnow, nameptr, namelen,
+                                outface, nh_idx,
+                                vnet_buffer (b0)->ip.adj_index[VLIB_TX],
+                                strategy, isv6, &stats);
+           }
+         /* Maybe trace */
+         if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+                            (b0->flags & VLIB_BUFFER_IS_TRACED)))
+           {
+             hicn_strategy_trace_t *t =
+               vlib_add_trace (vm, node, b0, sizeof (*t));
+             t->pkt_type = HICN_PKT_TYPE_CONTENT;
+             t->sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+             t->next_index = next0;
+           }
+         /*
+          * Verify speculative enqueue, maybe switch current
+          * next frame
+          */
+         /*
+          * Fix in case of a wrong speculation. Needed for
+          * cloning the data in the right 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);
+    }
+
+  vlib_node_increment_counter (vm, hicn_strategy_node->index,
+                              HICNFWD_ERROR_PROCESSED, stats.pkts_processed);
+  vlib_node_increment_counter (vm, hicn_strategy_node->index,
+                              HICNFWD_ERROR_INTERESTS,
+                              stats.pkts_interest_count);
+
+  return (frame->n_vectors);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/strategy.h b/hicn-plugin/src/strategy.h
new file mode 100755 (executable)
index 0000000..6b06a6c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_STRATEGY__
+#define __HICN_STRATEGY__
+
+#include "hicn.h"
+#include "hashtb.h"
+#include "mgmt.h"
+#include "faces/face.h"
+
+/**
+ * @File
+ *
+ * A strategy is defined as a vpp node and a set of function that will be called
+ * during the packet processing. Having one vpp node per strategy allows to
+ * easily process multiple interests in the same node (x2 or x4) and call the
+ * same function for choosing the next hop.
+ * Here we provide:
+ * - a template for the callbacks to implement in order to create a new strategy
+ *   (hicn_fwd_strategy_t)
+ * - the base structure for a strategy node
+ *   (list of next vpp nodes, errors, tracing and the main function processing an
+ *    interest and calling hicn_select_next_hop)
+ */
+
+typedef struct hicn_strategy_vft_s
+{
+  void (*hicn_receive_data) (index_t dpo_idx, int nh_idx);
+  void (*hicn_on_interest_timeout) (index_t dpo_idx);
+  void (*hicn_add_interest) (index_t dpo_idx, hicn_hash_entry_t * pit_entry);
+    u32 (*hicn_select_next_hop) (index_t dpo_idx, int *nh_idx,
+                                dpo_id_t ** outface);
+    u32 (*get_strategy_node_index) (void);
+                                        /**< Return the vlib node index implementing the strategy */
+} hicn_strategy_vft_t;
+
+hicn_face_vft_t *hicn_strategy_get_face_vft (u16 index);
+
+/* Strategy node API */
+/* Basic interest processing function. To be called in all the strategy nodes */
+uword
+hicn_forward_interest_fn (vlib_main_t * vm,
+                         vlib_node_runtime_t * node,
+                         vlib_frame_t * frame,
+                         hicn_strategy_vft_t * strategy,
+                         vlib_node_registration_t * hicn_strategy_node);
+
+/* Trace context struct */
+typedef struct
+{
+  u32 next_index;
+  u32 sw_if_index;
+  u8 pkt_type;
+} hicn_strategy_trace_t;
+
+typedef enum
+{
+  HICN_STRATEGY_NEXT_INTEREST_HITPIT,
+  HICN_STRATEGY_NEXT_ERROR_DROP,
+  HICN_STRATEGY_N_NEXT,
+} hicn_strategy_next_t;
+
+#endif /* //__HICN_STRATEGY__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/strategy_dpo_ctx.h b/hicn-plugin/src/strategy_dpo_ctx.h
new file mode 100755 (executable)
index 0000000..5d2dbc4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_STRATEGY_DPO_CTX_H__
+#define __HICN_STRATEGY_DPO_CTX_H__
+
+#include <vnet/dpo/dpo.h>
+#include <vnet/fib/fib_table.h>
+
+#include "hicn.h"
+#include "params.h"
+#include "faces/face.h"
+
+#define HICN_FIB_TABLE 0
+
+#define DATA_LEN 8
+
+#define NEXT_HOP_INVALID DPO_INVALID
+
+/*
+ * An hicn dpo is a list of next hops (face + weight).
+ */
+typedef struct __attribute__ ((packed)) hicn_dpo_ctx_s
+{
+  CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+  /* 8B*5 = 40B */
+  dpo_id_t next_hops[HICN_PARAM_FIB_ENTRY_NHOPS_MAX];
+  /* 40B + 4B = 44B */
+  u32 locks;
+  /* 44B + 1B = 45B */
+  u8 entry_count;
+  /* 45B + 1B = 46B */
+  /* Number of TFIB entries (stored at the end of the next_hops array */
+  u8 tfib_entry_count;
+
+  /* 46B + 2B = 48B */
+  u16 padding;                 /* To align to 8B */
+
+#ifdef HICN_MAPME_NOTIFICATIONS
+  /* (8B) last acked update for IU/IN heuristic on producer */
+  f64 last_iu_ack;
+#endif
+  /* (4B) last sequence number */
+  seq_t seq;
+
+} hicn_dpo_ctx_t;
+
+STATIC_ASSERT (sizeof (hicn_dpo_ctx_t) <= CLIB_CACHE_LINE_BYTES,
+              "sizeof hicn_dpo_ctx_t is greater than 64B");
+
+#endif /* // __HICN_STRATEGY_DPO_CTX_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/strategy_dpo_manager.c b/hicn-plugin/src/strategy_dpo_manager.c
new file mode 100755 (executable)
index 0000000..c1723ec
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2017-2019 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 <vnet/dpo/dpo.h>
+
+#include "strategy_dpo_manager.h"
+#include "strategies/dpo_mw.h"
+#include "strategy.h"
+#include "faces/face.h"
+
+static dpo_type_t *strategies_id;
+static const hicn_dpo_vft_t **hicn_dpo_vfts;
+
+static const hicn_strategy_vft_t **hicn_strategy_vfts;
+
+int hicn_strategies = 0;
+
+hicn_dpo_vft_t default_dpo;
+
+dpo_type_t
+hicn_dpo_register_new_type (const char *const *const *hicn_nodes,
+                           const hicn_dpo_vft_t * hicn_dpo_vft,
+                           const hicn_strategy_vft_t * hicn_strategy_vft,
+                           const dpo_vft_t * dpo_ctx_vft)
+{
+  dpo_type_t dpo_type = dpo_register_new_type (dpo_ctx_vft, hicn_nodes);
+  vec_validate (hicn_dpo_vfts, dpo_type);
+  hicn_dpo_vfts[dpo_type] = hicn_dpo_vft;
+
+  vec_validate (hicn_strategy_vfts, dpo_type);
+  hicn_strategy_vfts[dpo_type] = hicn_strategy_vft;
+
+  vec_validate (strategies_id, hicn_strategies);
+  strategies_id[hicn_strategies] = dpo_type;
+  hicn_strategies++;
+
+  return dpo_type;
+}
+
+u32
+dpo_is_hicn (const dpo_id_t * dpo)
+{
+  for (int i = 0; i < hicn_strategies; i++)
+    {
+      if (hicn_dpo_vfts[strategies_id[i]]->hicn_dpo_is_type (dpo))
+       return 1;
+    }
+  return 0;
+}
+
+dpo_type_t
+hicn_dpo_get_vft_id (const dpo_id_t * dpo)
+{
+  return dpo->dpoi_type;
+}
+
+const hicn_dpo_vft_t *
+hicn_dpo_get_vft (dpo_type_t vfts_id)
+{
+  return hicn_dpo_vfts[vfts_id];
+}
+
+const hicn_dpo_vft_t *
+hicn_dpo_get_vft_from_id (u8 strategy_id)
+{
+  return hicn_dpo_vfts[strategies_id[strategy_id]];
+}
+
+const hicn_strategy_vft_t *
+hicn_dpo_get_strategy_vft (dpo_type_t vfts_id)
+{
+  return hicn_strategy_vfts[vfts_id];
+}
+
+const hicn_strategy_vft_t *
+hicn_dpo_get_strategy_vft_from_id (u8 vfts_id)
+{
+  return hicn_strategy_vfts[strategies_id[vfts_id]];
+}
+
+void
+hicn_dpos_init (void)
+{
+  hicn_dpo_strategy_mw_module_init ();
+
+  default_dpo.hicn_dpo_get_ctx = &hicn_strategy_mw_ctx_get;
+  default_dpo.hicn_dpo_is_type = &hicn_dpo_is_type_strategy_mw;
+  default_dpo.hicn_dpo_get_type = &hicn_dpo_strategy_mw_get_type;
+  default_dpo.hicn_dpo_module_init = &hicn_dpo_strategy_mw_module_init;
+  default_dpo.hicn_dpo_create = &hicn_strategy_mw_ctx_create;
+  default_dpo.hicn_dpo_add_update_nh = &hicn_strategy_mw_ctx_add_nh;
+  default_dpo.hicn_dpo_del_nh = &hicn_strategy_mw_ctx_del_nh;
+  default_dpo.hicn_dpo_lock_dpo_ctx = &hicn_strategy_mw_ctx_lock;
+  default_dpo.hicn_dpo_unlock_dpo_ctx = hicn_strategy_mw_ctx_unlock;
+  default_dpo.format_hicn_dpo = &format_hicn_strategy_mw_ctx;
+}
+
+u8 *
+format_hicn_strategy_list (u8 * s, int n, ...)
+{
+  va_list ap;
+  va_start (ap, n);
+  u32 indent = va_arg (ap, u32);
+  va_end (ap);
+
+  s = format (s, "Strategies:\n", indent);
+  indent += 4;
+  int i;
+  vec_foreach_index (i, strategies_id)
+  {
+    s = format (s, "(%d) ", i, indent);
+    s = hicn_dpo_vfts[strategies_id[i]]->format_hicn_dpo (s, &ap);
+  }
+
+  return (s);
+}
+
+u8
+hicn_dpo_strategy_id_is_valid (int strategy_id)
+{
+  return vec_len (strategies_id) > strategy_id ?
+    HICN_ERROR_NONE : HICN_ERROR_DPO_MGR_ID_NOT_VALID;
+}
+
+int
+hicn_strategy_get_all_available (void)
+{
+  return hicn_strategies;
+}
+
+/**
+ * @brief Registers a dpo by calling its module init function.
+ *
+ * This is typically called from the ctor for dpo's registered at compilation
+ * time.
+ */
+void
+hicn_dpo_register (const hicn_dpo_vft_t * hicn_dpo)
+{
+  hicn_dpo->hicn_dpo_module_init ();
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/strategy_dpo_manager.h b/hicn-plugin/src/strategy_dpo_manager.h
new file mode 100755 (executable)
index 0000000..686c2f8
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_STRATEGY_DPO_MANAGER_H__
+#define __HICN_STRATEGY_DPO_MANAGER_H__
+
+#include "strategy_dpo_ctx.h"
+#include "strategy.h"
+
+/**
+ * @brief Definition of the virtual function table for a hICN DPO.
+ *
+ * An hICN dpo is a combination of a dpo context (hicn_dpo_ctx or struct that
+ * extends a hicn_dpo_ctx) and a strategy node. The following virtual function table
+ * template that glues together the fuction to interact with the context and the
+ * creating the dpo
+ */
+typedef struct hicn_dpo_vft_s
+{
+  hicn_dpo_ctx_t *(*hicn_dpo_get_ctx) (index_t dpo_idx);       /**< Retrieve the dpo ctx*/
+  int (*hicn_dpo_is_type) (const dpo_id_t * dpo);
+       /**< Check if the type of the
+           hICN DPO is the expected */
+    dpo_type_t (*hicn_dpo_get_type) (void);
+       /**< Return the type of the hICN dpo */
+  void (*hicn_dpo_module_init) (void);                 /**< Initialize the hICN dpo */
+  int (*hicn_dpo_create) (dpo_proto_t proto, const dpo_id_t * nh, int nh_len, index_t * dpo_idx);                      /**< Create the context of the hICN dpo */
+  int (*hicn_dpo_add_update_nh) (const dpo_id_t * nh, index_t dpo_idx);                                /**< Add a next hop to the hICN dpo context */
+  int (*hicn_dpo_del_nh) (hicn_face_id_t face_id, index_t dpo_idx,
+                         fib_prefix_t * fib_pfx);
+       /**< Add a next hop to the hICN dpo context */
+  void (*hicn_dpo_lock_dpo_ctx) (dpo_id_t * dpo);
+  void (*hicn_dpo_unlock_dpo_ctx) (dpo_id_t * dpo);
+  u8 *(*format_hicn_dpo) (u8 * s, va_list * ap);
+       /**< Format an hICN dpo*/
+} hicn_dpo_vft_t;
+
+/*
+ * Default dpo to be used to create fib entry when a strategy is not
+ * specified
+ */
+extern hicn_dpo_vft_t default_dpo;
+
+/**
+ *  @brief Register a new hICN dpo to the manager.
+ *
+ *  An hICN DPO is a combination of:
+ *   - a hICN DPO ctx (context) that holds the structure containing the
+ *     information to choose the next hop,
+ *   - a strategy containing: (i) the vpp node that processes Interest packets
+ *     subjected to such strategy, (ii) the definition of the vft that defines
+ *     the hICN strategy functions
+ *  Registering a hICN DPO allows the plugin to be aware of the new dpo an be
+ *  able to apply it to the FIB entries.
+ *
+ * @param hicn_nodes A list of vpp to which pass an interest that matches with
+ * the FIB entry to which the hICN DPO is applied. This list must contain the
+ * name of the strategy node (or nodes in case of differentiation between IPv4
+ * and IPv6).
+ * @param hicn_dpo_vft The structure holding the virtual function table to
+ * interact with the hICN dpo and its context.
+ * @param hicn_strategy_vft The structure holding the virtual function table
+ * containing the hICN strategy functions.
+ * @return the dpo type registered in the VPP Data plane graph.
+ */
+dpo_type_t
+hicn_dpo_register_new_type (const char *const *const *hicn_nodes,
+                           const hicn_dpo_vft_t * hicn_dpo_vft,
+                           const hicn_strategy_vft_t *
+                           hicn_strategy_vft, const dpo_vft_t * dpo_ctx_vft);
+
+/**
+ * @brief Check if the type of the dpo is among the list of hicn dpo types
+ *
+ * Iterate through the list of dpo types registered in the hicn dpo manager.
+ *
+ * @param dpo The id of the dpo to which check the type
+ * @return 1 if there is a match, 0 otherwise.
+ */
+u32 dpo_is_hicn (const dpo_id_t * dpo);
+
+/**
+ * @brief Return the dpo_vtf and strategy_vtf identifier
+ *
+ * Iterate through the list of dpo types registered in the hicn dpo manager and
+ * retrieve the corresponding dpo_vtf/strategy_vtf identifier.
+ *
+ * @param dpo The id of the dpo to which check the type
+ * @return the dpo_vft/strategy_vft id or HICN_ERROR_DPO_NOT_FOUND in case the dpo is not an hICN dpo.
+ */
+u8 hicn_dpo_get_vft_id (const dpo_id_t * dpo);
+
+/**
+ * @brief Get the vft to manage the dpo context.
+ *
+ * @param The id of the hicn_dpo_vft to retrieve.
+ * @return The vft struct that contains the list of callbacks that allows to
+ * manage the dpo context.
+ */
+const hicn_dpo_vft_t *hicn_dpo_get_vft (dpo_type_t vfts_id);
+
+/**
+ * @brief Get the vft to manage the dpo context from the strategy id.
+ *
+ * @param The strategy id of the hicn_dpo_vft to retrieve.
+ * @return The vft struct that contains the list of callbacks that allows to
+ * manage the dpo context.
+ */
+const hicn_dpo_vft_t *hicn_dpo_get_vft_from_id (u8 strategy_id);
+
+/**
+ * @brief Get the vft with the hICN strategy functions.
+ *
+ * @param The id of the hicn_strategy_vft to retrieve.
+ * @return The vft struct that contains the list hICN strategy functions.
+ */
+const hicn_strategy_vft_t *hicn_dpo_get_strategy_vft (dpo_type_t vfts_id);
+
+/**
+ * @brief Get the vft with the hICN strategy functions from the strategy id.
+ *
+ * @param The id of the hicn_strategy_vft to retrieve.
+ * @return The vft struct that contains the list hICN strategy functions.
+ */
+const hicn_strategy_vft_t *hicn_dpo_get_strategy_vft_from_id (u8 vfts_id);
+
+/**
+ * @brief Initialize all the types hicn dpo registered
+ *
+ * Call the init functions of all the hicn dpo implemented.
+ * This init is called when the plugin bootstrap.
+ */
+void hicn_dpos_init (void);
+
+/**
+ * @brief Print the list of the registered hICN DPO
+ *
+ * @param s String to which to append the list of hICN DPO (strategies)
+ * @param n number of parameters to pass
+ *
+ * @result The string with the list of hICN DPO (strategies)
+ */
+u8 *format_hicn_strategy_list (u8 * s, int n, ...);
+
+/**
+ * @brief Check if a given id points to a strategy and the corresponding dpo ctx
+ *
+ * @param The id of the strategy to check.
+ *
+ * @result HICN_ERROR_NONE is the id is valid, otherwise EINVAL
+ */
+u8 hicn_dpo_strategy_id_is_valid (int strategy_id);
+
+/**
+ * @brief Return the number of available strategies. This number can be used to
+ * as an upperbond for valid vfts_id.
+ *
+ * @result Return the number of available strategies.
+ */
+int hicn_strategy_get_all_available (void);
+
+/**
+ * @brief Registers a module at compilation time to be initialized as part of
+ * the ctor.
+ */
+void hicn_dpo_register (const hicn_dpo_vft_t * hicn_dpo);
+
+#endif /* // __HICN_STRATEGY_DPO_MANAGER_H__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/utils.h b/hicn-plugin/src/utils.h
new file mode 100755 (executable)
index 0000000..ecad47e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_UTILS_H__
+#define __HICN_UTILS_H__
+
+#include "hicn.h"
+
+always_inline void
+hicn_print_name6 (hicn_name_t * name)
+{
+  u8 *s0;
+  s0 = format (0, "Source addr %U, seq_number %u", format_ip6_address,
+              (ip6_address_t *) name->ip6.prefix,
+              clib_net_to_host_u32 (name->ip6.suffix));
+
+  printf ("%s\n", s0);
+}
+
+always_inline void
+hicn_print6 (hicn_header_t * hicn0)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  u8 *s0;
+  s0 = format (0, "Source addr %U:%u, dest addr %U:%u", format_ip6_address,
+              &(hicn0->v6.ip.saddr),
+              clib_net_to_host_u32 (hicn0->v6.tcp.seq), format_ip6_address,
+              &(hicn0->v6.ip.daddr),
+              clib_net_to_host_u32 (hicn0->v6.tcp.seq));
+
+  vlib_cli_output (vm, "%s\n", s0);
+}
+
+always_inline void
+hicn_print4 (hicn_header_t * hicn0)
+{
+  u8 *s0;
+  s0 = format (0, "Source addr %U:%u, dest addr %U:%u", format_ip4_address,
+              &(hicn0->v4.ip.saddr),
+              clib_net_to_host_u32 (hicn0->v4.tcp.seq), format_ip4_address,
+              &(hicn0->v4.ip.daddr),
+              clib_net_to_host_u32 (hicn0->v4.tcp.seq));
+
+  printf ("%s\n", s0);
+}
+
+#endif /* // __HICN_UTILS_H__ */
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables: eval: (c-set-style "gnu") End:
+ */
diff --git a/hicn-plugin/src/vface_db.h b/hicn-plugin/src/vface_db.h
new file mode 100755 (executable)
index 0000000..b98a2f4
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2019 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 __HICN_FACE_DB_H__
+#define __HICN_FACE_DB_H__
+
+#include <vnet/dpo/dpo.h>
+#include "faces/face.h"
+
+/* Must be power of two*/
+#define HICN_FACE_DB_INLINE_FACES 4
+
+#define HICN_PIT_N_HOP_BITMAP_SIZE HICN_PARAM_PIT_ENTRY_PHOPS_MAX
+
+#define HICN_PIT_N_HOP_BUCKET (HICN_PARAM_PIT_ENTRY_PHOPS_MAX - HICN_FACE_DB_INLINE_FACES)
+
+STATIC_ASSERT ((HICN_PIT_N_HOP_BUCKET & (HICN_PIT_N_HOP_BUCKET - 1)) == 0,
+              "HICN_PARAM_PIT_ENTRY_PHOP_MAX must be a power of 2 + 4");
+
+/* Takes 2 cache lines */
+typedef struct __attribute__ ((packed)) hicn_face_bucket_s
+{
+  /* Array of indexes of virtual faces */
+  dpo_id_t faces[HICN_PIT_N_HOP_BUCKET];
+
+  CLIB_CACHE_LINE_ALIGN_MARK (cache_line1);
+
+  /* Used to check if interests are retransmission */
+  /* How much are we gaining (performance)/wasting (memory) wrt the linear */
+  /* search on the array of faces? */
+  u8 bitmap[HICN_PIT_N_HOP_BITMAP_SIZE];
+
+} hicn_face_bucket_t;
+
+extern hicn_face_bucket_t *hicn_face_bucket_pool;
+
+/*
+ * Virtual faces will be stored in a pool and when a virtual face is created and
+ * its index will be saved in the pit entry. In case of interest aggregation we
+ * have to look on all the virtual faces to understand if there is a duplicated
+ * interest
+ */
+typedef struct __attribute__ ((packed)) hicn_face_db_s
+{
+  /* 19B + 1B = 20B */
+  /* Equal to one or zero */
+  u8 is_overflow;
+
+  /* Number of faces in the last bucket */
+  /* Or next availabe entry for storing a dpo_id_t */
+  /* 20B + 4B = 24B */
+  u32 n_faces;
+
+  /* 24B + 32B (8*4) = 56B */
+  /* Array of indexes of virtual faces */
+  dpo_id_t inline_faces[HICN_FACE_DB_INLINE_FACES];
+
+  /* 56B + 4B = 60B */
+  u32 next_bucket;
+
+  /* 60B + 4B = 64B */
+  u32 align;                   //align back to 64
+
+} hicn_face_db_t;
+
+//STATIC_ASSERT(HICN_PIT_N_HOP_BITMAP_SIZE <= (HICN_PARAM_PIT_ENTRY_PHOPS_MAX/8));
+
+always_inline dpo_id_t *
+hicn_face_db_get_dpo_face (u32 index, hicn_face_db_t * face_db)
+{
+  ASSERT (index < face_db->n_faces);
+
+  return index < HICN_FACE_DB_INLINE_FACES ? &(face_db->inline_faces[index]) :
+    &(pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket)->faces
+      [(index - HICN_FACE_DB_INLINE_FACES) & (HICN_PIT_N_HOP_BUCKET - 1)]);
+}
+
+always_inline void
+hicn_face_db_init (int max_element)
+{
+  pool_init_fixed (hicn_face_bucket_pool, max_element);
+}
+
+always_inline hicn_face_bucket_t *
+hicn_face_db_get_bucket (u32 bucket_index)
+{
+  return pool_elt_at_index (hicn_face_bucket_pool, bucket_index);
+}
+
+always_inline void
+hicn_face_db_add_face_dpo (dpo_id_t * dpo, hicn_face_db_t * face_db)
+{
+  ASSERT (dpo->dpoi_index != ~0);
+
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+  dpo_id_t *face =
+    face_db->n_faces <
+    HICN_FACE_DB_INLINE_FACES ? &(face_db->inline_faces[face_db->n_faces]) :
+    &(faces_bkt->faces
+      [(face_db->n_faces -
+       HICN_FACE_DB_INLINE_FACES) & (HICN_PIT_N_HOP_BUCKET - 1)]);
+
+  clib_memcpy (face, dpo, sizeof (dpo_id_t));
+
+  /* This access the dpoi to increase the lock */
+  dpo_lock (dpo);
+
+  u32 bitmap_index = dpo->dpoi_index % HICN_PIT_N_HOP_BITMAP_SIZE;
+  faces_bkt->bitmap[bitmap_index] |= 0x01;
+  face_db->n_faces++;
+}
+
+always_inline u8
+hicn_face_search (dpo_id_t * dpo, hicn_face_db_t * face_db)
+{
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+  u32 bitmap_index = dpo->dpoi_index % HICN_PIT_N_HOP_BITMAP_SIZE;
+
+  return faces_bkt->bitmap[bitmap_index] & 0x01;
+}
+
+always_inline void
+hicn_faces_flush (hicn_face_db_t * face_db)
+{
+  hicn_face_bucket_t *faces_bkt =
+    pool_elt_at_index (hicn_face_bucket_pool, face_db->next_bucket);
+  clib_memset_u64 (&(faces_bkt->bitmap), 0, HICN_PIT_N_HOP_BITMAP_SIZE / 8);
+  face_db->n_faces = 0;
+  pool_put_index (hicn_face_bucket_pool, face_db->next_bucket);
+}
+
+
+#endif // __HICN_FACE_DB_H__
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1be5e67
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required (VERSION 3.5 FATAL_ERROR)
+project(Hicn C)
+include(CTest)
+
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+)
+
+if (NOT CMAKE_BUILD_TYPE)
+       message(STATUS "No build type selected, default to Release")
+       set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+       set(LIBHICN hicn)
+endif()
+
+set(CMAKE_VERSION_MAJOR 0)
+set(CMAKE_VERSION_MINOR 1)
+set(CMAKE_VERSION_PATCH 1)
+
+option(CMAKE_BUILD_TEST "Build unit tests" OFF)
+
+if (NOT CMAKE_BUILD_TYPE)
+       message(STATUS "No build type selected, default to Release")
+       set(CMAKE_BUILD_TYPE "Release")
+endif()
+
+set(CMAKE_C_FLAGS -Wall)
+
+if (ANDROID_API)
+       set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS} -std=c99")
+endif ()
+
+add_subdirectory (src)
diff --git a/lib/README.md b/lib/README.md
new file mode 100755 (executable)
index 0000000..6dac988
--- /dev/null
@@ -0,0 +1,114 @@
+# libhicn
+
+## Introduction
+
+libhicn provides a support library coded in C designed to help developers embed
+Hybrid ICN (hICN) functionalities in their applications (eg. forwarder, socket
+API, etc.). Its purpose is to follow the hICN specification for which it
+provides a reference implementation, abstracting the user from all internal
+mechanisms, and offering an API independent of the packet format (eg. IPv4 or
+IPv6). The library is designed to be portable across both desktop and
+mobile platforms, and we currently aim at supporting Linux, Android, OSX and
+iOS, by writing the necessary adapters to realize hICN functionality in
+userspace according to the available APIs and permissions that each system
+offers.
+
+The library consists in several layers:
+- the core library (hicn.h) provides a standard hICN packet format, as well as
+an API allowing manipulation of packet headers;
+- an hICN helper, allowing an hICN stack to be built in userspace in a portable
+way, based on TUN devices and accessible though file descriptors;
+- a network layer allow the sending an receiving of hICN packets on those file
+descriptors, implementing both source and destination address translation as
+required by the hICN mechanisms;
+- finally, a "transport" API allows the forging of dummy interest and data
+packets.
+
+A commandline interface (hicnc) is also provided that uses the library and can
+for instance be used as a test traffic generator. This interface can be run as
+either a consumer, a producer, or a simple forwarder.
+
+## Folder content
+
+CMakeLists.txt          CMkake global build file
+doc                     Package documentation
+README.md               This file
+src
+    base.h             Base definitions for hICN implementation
+    CMakeLists.txt      CMake library build file
+    common.{h,c}       Harmonization layer across supported platforms
+    compat.{h,c}       Compatibility layer for former API
+    error.{h,c}                Error management files
+    header.h           hICN header definitions
+    hicn.h             Master include file
+    mapme.{h,c}                MAP-Me : anchorless producer mobility mechanisms 
+    name.{h,c}         hICN naming conventions and name processing + IP helpers
+    ops.{h,c}          Protocol-independent hICN operations
+    protocol/*         Protocol headers + protocol-dependent implementations
+    protocol.h         Common file for protocols
+
+## Using libhicn
+
+### Platforms ###
+
+libhicn has been tested in:
+
+- Ubuntu 16.04 LTS (x86_64)
+- Ubuntu 18.04 LTS (x86_64)
+- Debian Stable/Testing
+- Red Hat Enterprise Linux 7
+- CentOS 7
+- Android 8
+- iOS 12
+- macOS 10.12
+- Windows 10
+
+Other platforms and architectures may work.
+
+### Dependencies
+
+Build dependencies:
+
+- c11 ( clang / gcc )
+- CMake 3.4
+
+Basic dependencies: None
+
+## Installation
+
+You can either use released packages, or compile libhicn from sources.
+
+### Release mode
+
+mkdir build
+cd build
+cmake ..
+make
+sudo make install
+
+### Debug mode
+
+mkdir debug
+cd debug
+cmake .. -DCMAKE_BUILD_TYPE=Debug
+make
+sudo make install
+
+## License
+
+This software is distributed under the following license:
+
+```
+Copyright (c) 2017-2019 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.
+```
diff --git a/lib/doc/CMakeLists.txt b/lib/doc/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..cf022dc
--- /dev/null
@@ -0,0 +1,23 @@
+# add a target to generate API documentation with Doxygen
+find_package(Doxygen)
+option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
+
+if(BUILD_DOCUMENTATION)
+    if(NOT DOXYGEN_FOUND)
+        message(FATAL_ERROR "Doxygen is needed to build the documentation.")
+    endif()
+
+    set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+    set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+    configure_file(${doxyfile_in} ${doxyfile} @ONLY)
+
+    add_custom_target(doc
+        COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+        COMMENT "Generating API documentation with Doxygen"
+        VERBATIM)
+
+# FIXME MS : wrong install path
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
+endif()
diff --git a/lib/doc/Doxyfile.in b/lib/doc/Doxyfile.in
new file mode 100755 (executable)
index 0000000..839de9f
--- /dev/null
@@ -0,0 +1,12 @@
+PROJECT_NAME           = "Hybrid ICN (hICN)"
+PROJECT_NUMBER         = v@CMAKE_VERSION_MAJOR@.@CMAKE_VERSION_MINOR@.@CMAKE_VERSION_PATCH@
+STRIP_FROM_PATH        = @PROJECT_SOURCE_DIR@ \
+                         @PROJECT_BINARY_DIR@
+INPUT                  = @doxy_main_page@ \
+                         @PROJECT_SOURCE_DIR@ \
+                         @PROJECT_BINARY_DIR@
+FILE_PATTERNS          = *.md \
+                         *.h \
+                         *.cc
+RECURSIVE              = YES
+USE_MDFILE_AS_MAINPAGE = ../README.md
diff --git a/lib/src/CMakeLists.txt b/lib/src/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0137a16
--- /dev/null
@@ -0,0 +1,81 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND LIBHICN_HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/base.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/common.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/compat.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/error.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/header.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/mapme.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/ops.h
+)
+
+list(APPEND LIBHICN_HEADER_FILES_PROTOCOL
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmprd.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/udp.h
+)
+
+list(APPEND LIBHICN_SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/compat.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/error.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/mapme.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/ops.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/common.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ah.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/icmp.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv4.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/ipv6.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol/tcp.c
+)
+
+set (COMPILER_DEFINITIONS "-DWITH_MAPME -DWITH_MAPME_FIXES")
+
+include(BuildMacros)
+build_library(${LIBHICN}
+  SHARED STATIC
+  SOURCES ${LIBHICN_SOURCE_FILES}
+  COMPONENT libhicn
+  INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/..
+  DEFINITIONS ${COMPILER_DEFINITIONS}
+  INSTALL_ROOT_DIR hicn
+  INSTALL_HEADERS ${LIBHICN_HEADER_FILES} ${LIBHICN_HEADER_FILES_PROTOCOL}
+)
+
+add_custom_command(TARGET hicn PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E remove_directory ${PROJECT_BINARY_DIR}/hicn
+)
+
+add_custom_command(TARGET hicn POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/hicn/
+  COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES} ${PROJECT_BINARY_DIR}/hicn/
+)
+
+add_custom_command(TARGET hicn POST_BUILD
+  COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/hicn/protocol
+  COMMAND ${CMAKE_COMMAND} -E copy ${LIBHICN_HEADER_FILES_PROTOCOL} ${PROJECT_BINARY_DIR}/hicn/protocol
+)
+
+# install(FILES ${LIBHICN_HEADER_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn COMPONENT libhicn)
+# install(FILES ${LIBHICN_HEADER_FILES_PROTOCOL} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/hicn/protocol COMPONENT libhicn)
diff --git a/lib/src/base.h b/lib/src/base.h
new file mode 100755 (executable)
index 0000000..c1bd23a
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file base.h
+ * @brief Base hICN definitions.
+ */
+
+#ifndef HICN_BASE_H
+#define HICN_BASE_H
+
+#include "common.h"
+
+/* Default header fields */
+#define HICN_DEFAULT_TTL 254
+
+typedef u32 hicn_faceid_t;
+typedef u8 hicn_pathlabel_t;
+typedef u32 hicn_lifetime_t;
+
+#define HICN_MAX_LIFETIME HICN_MAX_LIFETIME_SCALED << HICN_MAX_LIFETIME_MULTIPLIER
+#define HICN_MAX_LIFETIME_SCALED 0xFFFF
+#define HICN_MAX_LIFETIME_MULTIPLIER 0xF       /* 4 bits */
+
+/**
+ * @brief hICN packet format type
+ *
+ * The hICN type represents the sequence of protocols that we can find in packet
+ * headers. They are represented as a quartet of u8 values, correponding to
+ * IANA protocol assignment, and read from right to left. This is done to
+ * faciliate decapsulation of packet header by simple shift/mask operations.
+ *
+ * For instance, an IPv6/TCP packet will be identified as :
+ * [IPPROTO_NONE, IPPROTO_NONE, IPPROTO_TCP, IPPROTO_IPV6]
+ *
+ * We expect four elements to be sufficient for most uses, the max being
+ * currently used by an hypothetical signed MAP-Me update :
+ * [IPPROTO_ICMPRD, IPPROTO_AH, IPPROTO_ICMP, IPPROTO_IPV6]
+ */
+typedef union
+{
+    /** protocol layers representation */
+  struct
+  {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    u8 l1;     /**< First layer */
+    u8 l2;     /**< Second layer */
+    u8 l3;     /**< Third layer */
+    u8 l4;     /**< Fourth layer */
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    u8 l4;     /**< Fourth layer */
+    u8 l3;     /**< Third layer */
+    u8 l2;     /**< Second layer */
+    u8 l1;     /**< First layer */
+#else
+#error "Unsupported endianness"
+#endif
+  };
+    /** u32 representation */
+  u32 as_u32;
+} hicn_type_t;
+
+/* Common protocol layers */
+#define HICN_TYPE_IPV4_TCP   (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_TCP,    .l1 = IPPROTO_IP }}
+#define HICN_TYPE_IPV4_ICMP  (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_ICMP,   .l1 = IPPROTO_IP }}
+#define HICN_TYPE_IPV6_TCP   (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_TCP,    .l1 = IPPROTO_IPV6 }}
+#define HICN_TYPE_IPV6_ICMP  (hicn_type_t) {{ .l4 = IPPROTO_NONE, .l3 = IPPROTO_NONE, .l2 = IPPROTO_ICMPV6, .l1 = IPPROTO_IPV6 }}
+
+
+/**
+ * @brief hICN Payload type
+ *
+ * This type distinguishes several types of data packet, which can either carry
+ * content data, or Manifest
+ */
+typedef enum
+{
+  HPT_DATA = 0,
+  HPT_MANIFEST = 1,
+  HPT_UNSPEC = 999
+} hicn_payload_type_t;
+
+/**
+ * @brief Path label computations
+ *
+ * Path label is computed by accumulating the identifiers of successive output
+ * faces as a Data packet is traveling from its producer back to the consumer
+ * originating the Interest.
+ *
+ * NOTE: this computation is not (yet) part of the hICN specification.
+ */
+
+#define HICN_PATH_LABEL_MASK 0xF000    /* 1000 0000 0000 0000 */
+#define HICN_PATH_LABEL_SIZE 8
+
+/**
+ * @brief Path label update
+ * @param [in] current_label Current pathlabel
+ * @param [in] face_id The face identifier to combine into the path label
+ * @param [out] new_label Computed pathlabel
+ *
+ * This function updates the current_label based on the new face_id, and returns
+ */
+always_inline void
+update_pathlabel (hicn_pathlabel_t current_label, hicn_faceid_t face_id,
+                 hicn_pathlabel_t * new_label)
+{
+  hicn_pathlabel_t pl_face_id =
+    (hicn_pathlabel_t) ((face_id & HICN_PATH_LABEL_MASK) >>
+                       (16 - HICN_PATH_LABEL_SIZE));
+  *new_label =
+    ((current_label << 1) | (current_label >> (HICN_PATH_LABEL_SIZE - 1))) ^
+    pl_face_id;
+}
+
+#endif /* HICN_BASE_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/common.c b/lib/src/common.c
new file mode 100755 (executable)
index 0000000..4b7c4a2
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file common.c
+ * @brief Implementation of common interfaces abstracting low-level platform.
+ * details.
+ */
+
+#include <stdlib.h>
+#include <string.h>            // memset
+#include <sys/types.h>         // getaddrinfo
+#include <sys/socket.h>                // ''
+#include <netdb.h>             // ''
+#include <stdio.h>
+
+#include "common.h"
+
+
+int
+get_addr_family (const char *ip_address)
+{
+  struct addrinfo hint, *res = NULL;
+  int rc;
+
+  memset (&hint, '\0', sizeof hint);
+
+  hint.ai_family = PF_UNSPEC;
+  hint.ai_flags = AI_NUMERICHOST;
+
+  rc = getaddrinfo (ip_address, NULL, &hint, &res);
+  if (rc)
+    {
+      return -1;
+    }
+  rc = res->ai_family;
+  freeaddrinfo (res);
+  return rc;
+}
+
+/* hashes */
+
+u32
+cumulative_hash32 (const void *data, size_t len, u32 lastValue)
+{
+  // Standard FNV 32-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+  const u32 fnv1a_prime = 0x01000193;
+  u32 hash = lastValue;
+  size_t i;
+
+  const char *chardata = data;
+
+  for (i = 0; i < len; i++)
+    {
+      hash = hash ^ chardata[i];
+      hash = hash * fnv1a_prime;
+    }
+
+  return hash;
+}
+
+u32
+hash32 (const void *data, size_t len)
+{
+  // Standard FNV 32-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+  const u32 fnv1a_offset = 0x811C9DC5;
+  return cumulative_hash32 (data, len, fnv1a_offset);
+}
+
+u64
+cumulative_hash64 (const void *data, size_t len, u64 lastValue)
+{
+  // Standard FNV 64-bit prime: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+  const u64 fnv1a_prime = 0x00000100000001B3ULL;
+  u64 hash = lastValue;
+  const char *chardata = data;
+  size_t i;
+
+  for (i = 0; i < len; i++)
+    {
+      hash = hash ^ chardata[i];
+      hash = hash * fnv1a_prime;
+    }
+
+  return hash;
+}
+
+u64
+hash64 (const void *data, size_t len)
+{
+  // Standard FNV 64-bit offset: see http://www.isthe.com/chongo/tech/comp/fnv/#FNV-param
+  const u64 fnv1a_offset = 0xCBF29CE484222325ULL;
+  return cumulative_hash64 (data, len, fnv1a_offset);
+}
+
+void
+hicn_packet_dump (uint8_t * buffer, size_t len)
+{
+  int i;
+  unsigned char buff[17];
+  unsigned char *pc = (unsigned char *) buffer;
+
+  // Output description if given.
+  if (len == 0)
+    {
+      printf ("  ZERO LENGTH\n");
+      return;
+    }
+
+  // Process every byte in the data.
+  for (i = 0; i < len; i++)
+    {
+      // Multiple of 16 means new line (with line offset).
+
+      if ((i % 16) == 0)
+       {
+         // Just don't print ASCII for the zeroth line.
+         if (i != 0)
+           printf ("  %s\n", buff);
+
+         // Output the offset.
+         printf ("  %04x ", i);
+       }
+
+      // Now the hex code for the specific character.
+      printf (" %02x", pc[i]);
+
+      // And store a printable ASCII character for later.
+      if ((pc[i] < 0x20) || (pc[i] > 0x7e))
+       buff[i % 16] = '.';
+      else
+       buff[i % 16] = pc[i];
+      buff[(i % 16) + 1] = '\0';
+    }
+
+  // Pad out last line if not exactly 16 characters.
+  while ((i % 16) != 0)
+    {
+      printf ("   ");
+      i++;
+    }
+
+  // And print the final ASCII bit.
+  printf ("  %s\n", buff);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/common.h b/lib/src/common.h
new file mode 100755 (executable)
index 0000000..9ddbdeb
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file common.c
+ * @brief Common interfaces abstracting low-level platform.
+ * details.
+ *
+ * The role of this header file is to provide an uniform interface to the
+ * different platform on top of which we build the hICN interface:
+ *  - syntax helpers
+ *  - IP address management
+ *  - protocol definition
+ *  - ...
+ *
+ * The rationale is to leverage as much as possible platform-specific code,
+ * however some level of harmonization is needed to build code on top. Whenever
+ * possible, we align to VPP structure and naming.
+ */
+
+#ifndef HICN_COMMON_H
+#define HICN_COMMON_H
+
+#include <stdint.h>
+#include <assert.h>
+
+/* Concise type definitions */
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+/*
+ * Code annotations
+ *
+ * NOTE: these are defined by default in VPP.
+ */
+
+#ifndef HICN_VPP_PLUGIN
+
+#define PREDICT_FALSE(x) (x)
+#define PREDICT_TRUE(x) (x)
+#define always_inline static inline
+#define static_always_inline static inline
+#define STRUCT_SIZE_OF(type, member) sizeof(((type *)0)->member)
+#define ASSERT
+
+#define STATIC_ASSERT(x)
+
+#endif /* ! HICN_VPP_PLUGIN */
+
+/*
+ * IP address types
+ */
+
+#ifdef HICN_VPP_PLUGIN
+
+#include <vnet/ip/ip4_packet.h>        // ip4_address_t
+#include <vnet/ip/ip6_packet.h>        // ip6_address_t
+
+#else
+
+#include <netinet/in.h>
+
+typedef union
+{
+  u32 as_u32;
+  struct in_addr as_inaddr;
+} ip4_address_t;
+
+typedef union
+{
+  u64 as_u64[2];
+  u32 as_u32[4];
+  u8 as_u8[16];
+  struct in6_addr as_in6addr;
+} ip6_address_t;
+
+typedef union
+{
+  struct
+  {
+    u32 pad[3];
+    ip4_address_t ip4;
+  };
+  ip6_address_t ip6;
+} ip46_address_t;
+
+#define ip46_address_is_ip4(ip46)       (((ip46)->pad[0] | (ip46)->pad[1] | (ip46)->pad[2]) == 0)
+
+#endif /* ! HICN_VPP_PLUGIN */
+
+/**
+ * @brief Returns the family of an IP address
+ * @param [in] ip_address - IP address in presentation format
+ * @return AF_INET or AF_INET6 if successful, -1 otherwise
+ */
+int get_addr_family (const char *ip_address);
+
+/*
+ * Checksum computation
+ *
+ * NOTE: VPP provides efficient (incremental) checksum computations
+ * that we reuse, and provide alternative implementation otherwise.
+ */
+
+#ifndef HICN_VPP_PLUGIN
+
+typedef u16 ip_csum_t;
+
+/*
+ * Checksum update (incremental and non-incremental)
+ *
+ * Those functions are already defined in VPP in vnet/ip/ip_packet.h, and we
+ * borrow this code here.
+ */
+
+static_always_inline u16
+ip_csum_fold (ip_csum_t c)
+{
+  /* Reduce to 16 bits. */
+#if 0                          // uword_bits == 64
+  c = (c & (ip_csum_t) 0xffffffff) + (c >> (ip_csum_t) 32);
+  c = (c & 0xffff) + (c >> 16);
+#endif
+
+  c = (c & 0xffff) + (c >> 16);
+  c = (c & 0xffff) + (c >> 16);
+
+  return c;
+}
+
+static_always_inline ip_csum_t
+ip_csum_with_carry (ip_csum_t sum, ip_csum_t x)
+{
+  ip_csum_t t = sum + x;
+  return t + (t < x);
+}
+
+/* Update checksum changing field at even byte offset from x -> 0. */
+static_always_inline ip_csum_t
+ip_csum_add_even (ip_csum_t c, ip_csum_t x)
+{
+  ip_csum_t d;
+
+  d = c - x;
+
+  /* Fold in carry from high bit. */
+  d -= d > c;
+
+  return d;
+}
+
+/* Update checksum changing field at even byte offset from 0 -> x. */
+static_always_inline ip_csum_t
+ip_csum_sub_even (ip_csum_t c, ip_csum_t x)
+{
+  return ip_csum_with_carry (c, x);
+}
+
+u32 cumulative_hash32 (const void *data, size_t len, u32 lastValue);
+u32 hash32 (const void *data, size_t len);
+u64 cumulative_hash64 (const void *data, size_t len, u64 lastValue);
+u64 hash64 (const void *data, size_t len);
+void hicn_packet_dump (uint8_t * buffer, size_t len);
+
+#endif /* ! HICN_VPP_PLUGIN */
+
+/**
+ * @brief Computes buffer checksum
+ * @param [in] addr - Pointer to buffer start
+ * @param [in] size - Size of buffer
+ * @param [in] init - Checksum initial value
+ * @return Checksum of specified buffer
+ */
+always_inline u16
+csum (const void *addr, size_t size, u16 init)
+{
+  u32 sum = init;
+  const u16 *bytes = (u16 *) addr;
+
+  while (size > 1)
+    {
+      sum += *bytes++;
+      size -= sizeof (u16);
+    }
+  if (size)
+    {
+      sum += *(const u8 *) bytes;
+    }
+  sum = (sum >> 16) + (sum & 0xffff);
+  sum += (sum >> 16);
+
+  return (u16) ~ sum;
+}
+
+/*
+ * Useful aliases
+ */
+
+/* Symmetry with IPPROTO_ICMPV6 */
+#define IPPROTO_ICMPV4 IPPROTO_ICMP
+
+/*
+ * Query IP version from packet (either 4 or 6)
+ * (version is located as same offsets in both protocol headers)
+ */
+#define HICN_IP_VERSION(packet) ((hicn_header_t *)packet)->v4.ip.version
+
+#endif /* HICN_COMMON_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/compat.c b/lib/src/compat.c
new file mode 100755 (executable)
index 0000000..7d9eef0
--- /dev/null
@@ -0,0 +1,1177 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file compat.c
+ * @brief Implementation of the compatibility layer.
+ */
+
+#include <netinet/in.h>
+#include <string.h>            // memset
+#include <stddef.h>            // offsetof
+
+#include "common.h"
+#include "compat.h"
+#include "error.h"
+#include "header.h"
+#include "name.h"
+#include "ops.h"
+
+#define member_size(type, member) sizeof(((type *)0)->member)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+#define HICN_NAME_COMPONENT_SIZE 2
+
+int
+hicn_packet_get_format (const hicn_header_t * h, hicn_format_t * format)
+{
+  *format = HF_UNSPEC;
+
+  switch (HICN_IP_VERSION (h))
+    {
+    case 4:
+      switch (h->v4.ip.protocol)
+       {
+       case IPPROTO_TCP:
+         if (h->v4.tcp.flags & AH_FLAG)
+           *format = HF_INET_TCP_AH;
+         else
+           *format = HF_INET_TCP;
+         break;
+       case IPPROTO_ICMP:
+         *format = HF_INET_ICMP;
+         break;
+       default:
+         return HICN_LIB_ERROR_NOT_HICN;
+       }
+      break;
+    case 6:
+      switch (h->v6.ip.nxt)
+       {
+       case IPPROTO_TCP:
+         if (h->v6.tcp.flags & AH_FLAG)
+           *format = HF_INET6_TCP_AH;
+         else
+           *format = HF_INET6_TCP;
+         break;
+       case IPPROTO_ICMPV6:
+         *format = HF_INET6_ICMP;
+         break;
+       default:
+         return HICN_LIB_ERROR_NOT_HICN;
+       }
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_HICN;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+/**
+ * @brief Convert (former) hICN format into (newer) hICN type
+ * @param [in] format - hICN format
+ * @return hICN type, all zero'ed if type is unknown
+ */
+hicn_type_t
+hicn_format_to_type (hicn_format_t format)
+{
+  switch (format)
+    {
+    case HF_INET_TCP:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_TCP,.l1 =
+         IPPROTO_IP};
+    case HF_INET6_TCP:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_TCP,.l1 =
+         IPPROTO_IPV6};
+    case HF_INET_ICMP:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_ICMP,.l1 =
+         IPPROTO_IP};
+    case HF_INET6_ICMP:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_NONE,.l2 = IPPROTO_ICMPV6,.l1 =
+         IPPROTO_IPV6};
+    case HF_INET_TCP_AH:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_TCP,.l1 = IPPROTO_IP};
+    case HF_INET6_TCP_AH:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_TCP,.l1 =
+         IPPROTO_IPV6};
+    case HF_INET_ICMP_AH:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_ICMP,.l1 =
+         IPPROTO_IP};
+    case HF_INET6_ICMP_AH:
+      return (hicn_type_t)
+      {
+      .l4 = IPPROTO_NONE,.l3 = IPPROTO_AH,.l2 = IPPROTO_ICMPV6,.l1 =
+         IPPROTO_IPV6};
+    default:
+      break;
+    }
+  return (hicn_type_t)
+  {
+    {
+    IPPROTO_NONE}
+  };
+}
+
+/**
+ * @brief Parse hICN header and return hICN type
+ * @param [in] h - hICN header
+ * @param [out] format - hICN type
+ * @return hICN error code
+ *
+ * This function is used to wrap old API calls to new ones
+ */
+hicn_type_t
+hicn_header_to_type (const hicn_header_t * h)
+{
+  hicn_format_t format;
+  hicn_packet_get_format (h, &format);
+  return hicn_format_to_type (format);
+}
+
+int
+hicn_packet_init_header (hicn_format_t format, hicn_header_t * packet)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->init_packet_header (type, &packet->protocol);
+}
+
+int
+hicn_packet_compute_checksum (hicn_format_t format, hicn_header_t * h)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->update_checksums (type, &h->protocol, 0, 0);
+}
+
+int
+hicn_packet_compute_header_checksum (hicn_format_t format, hicn_header_t * h,
+                                    u16 init_sum)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  /* payload_length == ~0: ignore payload */
+  return hicn_ops_vft[type.l1]->update_checksums (type, &h->protocol,
+                                                 init_sum, ~0);
+}
+
+int
+hicn_packet_check_integrity (hicn_format_t format, hicn_header_t * h)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->verify_checksums (type, &h->protocol, 0, 0);
+}
+
+int
+hicn_packet_get_header_length_from_format (hicn_format_t format,
+                                          size_t * header_length)
+{
+  *header_length = _is_ipv4 (format) * IPV4_HDRLEN;
+  *header_length += _is_ipv6 (format) * IPV6_HDRLEN;
+  *header_length += _is_icmp (format) * ICMP_HDRLEN;
+  *header_length += _is_tcp (format) * TCP_HDRLEN;
+  *header_length += _is_ah (format) * AH_HDRLEN;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_header_length (hicn_format_t format, const hicn_header_t * h,
+                              size_t * header_length)
+{
+  hicn_packet_get_header_length_from_format (format, header_length);
+  int is_ah = _is_ah (format);
+  int is_ipv4 = _is_ipv4 (format);
+  int is_ipv6 = _is_ipv6 (format);
+  // The signature payload is expressed as number of 32 bits words
+  *header_length += (is_ah * is_ipv4) * (h->v4ah.ah.payloadlen) << 2;
+  *header_length += (is_ah * is_ipv6) * (h->v6ah.ah.payloadlen) << 2;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_payload_length (hicn_format_t format, const hicn_header_t * h,
+                               size_t * payload_length)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->get_payload_length (type, &h->protocol,
+                                                   payload_length);
+}
+
+int
+hicn_packet_set_payload_length (hicn_format_t format, hicn_header_t * h,
+                               size_t payload_length)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->set_payload_length (type, &h->protocol,
+                                                   payload_length);
+}
+
+int
+hicn_packet_compare (const hicn_header_t * packet1,
+                    const hicn_header_t * packet2)
+{
+  hicn_type_t type1 = hicn_header_to_type (packet1);
+  hicn_type_t type2 = hicn_header_to_type (packet2);
+
+  size_t len1, len2;
+  int rc;
+
+  if (type1.as_u32 != type2.as_u32)
+    return HICN_LIB_ERROR_UNEXPECTED;
+
+  rc = hicn_ops_vft[type1.l1]->get_length (type1, &packet1->protocol, &len1);
+  if (PREDICT_FALSE (rc < 0))
+    return HICN_LIB_ERROR_UNEXPECTED;
+
+  rc = hicn_ops_vft[type2.l1]->get_length (type2, &packet2->protocol, &len2);
+  if (PREDICT_FALSE (rc < 0))
+    return HICN_LIB_ERROR_UNEXPECTED;
+
+  if (len1 != len2)
+    return HICN_LIB_ERROR_UNEXPECTED;
+
+  return memcmp ((u8 *) packet1, (u8 *) packet2, len1);
+
+}
+
+int
+hicn_packet_get_name (hicn_format_t format, const hicn_header_t * h,
+                     hicn_name_t * name, u8 is_interest)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+
+  if (is_interest)
+    return hicn_ops_vft[type.l1]->get_interest_name (type, &h->protocol,
+                                                    name);
+  else
+    return hicn_ops_vft[type.l1]->get_data_name (type, &h->protocol, name);
+}
+
+int
+hicn_packet_set_name (hicn_format_t format, hicn_header_t * h,
+                     const hicn_name_t * name, u8 is_interest)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+
+#ifndef HICN_VPP_PLUGIN
+  if (name->type & HNT_IOV)
+    return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+#endif /* HICN_VPP_PLUGIN */
+
+  if (is_interest)
+    return hicn_ops_vft[type.l1]->set_interest_name (type, &h->protocol,
+                                                    name);
+  else
+    return hicn_ops_vft[type.l1]->set_data_name (type, &h->protocol, name);
+}
+
+int
+hicn_packet_set_payload (hicn_format_t format, hicn_header_t * h,
+                        const u8 * payload, u16 payload_length)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  size_t header_length;
+  int rc;
+
+  rc =
+    hicn_ops_vft[type.l1]->get_header_length (type, &h->protocol,
+                                             &header_length);
+  if (rc < 0)
+    return rc;
+
+  memcpy ((u8 *) h + header_length, payload, payload_length);
+
+  return hicn_ops_vft[type.l1]->set_payload_length (type, &h->protocol,
+                                                   payload_length);
+}
+
+int
+hicn_packet_get_payload (hicn_format_t format, const hicn_header_t * h,
+                        u8 ** payload, size_t * payload_size, bool hard_copy)
+{
+  size_t header_length, payload_length;
+  int rc;
+  hicn_type_t type = hicn_format_to_type (format);
+
+  rc =
+    hicn_ops_vft[type.l1]->get_header_length (type, &h->protocol,
+                                             &header_length);
+  if (rc < 0)
+    return rc;
+
+  rc =
+    hicn_ops_vft[type.l1]->get_payload_length (type, &h->protocol,
+                                              &payload_length);
+  if (rc < 0)
+    return rc;
+
+  if (hard_copy)
+    {
+      memcpy (payload, (u8 *) h + header_length, payload_length);
+    }
+  else
+    {
+      *payload = (u8 *) h + header_length;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_locator (hicn_format_t format, const hicn_header_t * h,
+                        ip_address_t * ip_address, bool is_interest)
+{
+  const void *locator;
+  int is_ipv4 = (format & HFO_INET);
+  int is_ipv6 = (format & HFO_INET6) >> 1;
+
+  if (is_ipv4)
+    {
+      locator = is_interest ? &h->v4.ip.saddr : &h->v4.ip.daddr;
+      ip_address->family = AF_INET;
+      ip_address->prefix_len = IPV4_ADDR_LEN_BITS;
+    }
+  else if (is_ipv6)
+    {
+      locator = is_interest ? &h->v6.ip.saddr : &h->v6.ip.daddr;
+      ip_address->family = AF_INET6;
+      ip_address->prefix_len = IPV6_ADDR_LEN_BITS;
+    }
+  else
+    {
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  memcpy (ip_address->buffer, locator, ip_address_len (ip_address));
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_locator (hicn_format_t format, hicn_header_t * h,
+                        const ip_address_t * ip_address, bool is_interest)
+{
+  void *locator;
+  int is_ipv4 = (format & HFO_INET);
+  int is_ipv6 = (format & HFO_INET6) >> 1;
+
+  if (is_ipv6)
+    {
+      locator = is_interest ? &h->v6.ip.saddr : &h->v6.ip.daddr;
+    }
+  else if (is_ipv4)
+    {
+      locator = is_interest ? &h->v4.ip.saddr : &h->v4.ip.daddr;
+    }
+  else
+    {
+      return HICN_LIB_ERROR_INVALID_PARAMETER;
+    }
+
+  memcpy (locator, ip_address->buffer, ip_address_len (ip_address));
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_signature_size (hicn_format_t format, const hicn_header_t * h,
+                               size_t * bytes)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->get_signature_size (type, &h->protocol,
+                                                   bytes);
+}
+
+int
+hicn_packet_set_signature_size (hicn_format_t format, hicn_header_t * h,
+                               size_t bytes)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->set_signature_size (type, &h->protocol,
+                                                   bytes);
+}
+
+int
+hicn_packet_set_signature_timestamp (hicn_format_t format, hicn_header_t * h,
+                               uint64_t signature_timestamp)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->set_signature_timestamp (type, &h->protocol,
+                                                   signature_timestamp);
+}
+
+int
+hicn_packet_get_signature_timestamp (hicn_format_t format, const hicn_header_t * h,
+                               uint64_t *signature_timestamp)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->get_signature_timestamp (type, &h->protocol,
+                                                   signature_timestamp);
+}
+
+int
+hicn_packet_set_validation_algorithm (hicn_format_t format, hicn_header_t * h,
+                               uint8_t validation_algorithm)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->set_validation_algorithm (type, &h->protocol,
+                                                   validation_algorithm);
+}
+
+int
+hicn_packet_get_validation_algorithm (hicn_format_t format, const hicn_header_t * h,
+                               uint8_t * validation_algorithm)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->get_validation_algorithm (type, &h->protocol,
+                                                   validation_algorithm);
+}
+
+int
+hicn_packet_set_key_id (hicn_format_t format, hicn_header_t * h,
+                               uint8_t *key_id)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->set_key_id (type, &h->protocol,
+                                                   key_id);
+}
+
+int
+hicn_packet_get_key_id (hicn_format_t format, hicn_header_t * h,
+                               uint8_t ** key_id, uint8_t *key_id_length)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->get_key_id (type, &h->protocol,
+                                                   key_id, key_id_length);
+}
+
+int
+hicn_packet_get_hoplimit (const hicn_header_t * h, u8 * hops)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *hops = h->v6.ip.hlim;
+      break;
+    case 4:
+      *hops = h->v4.ip.ttl;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_hoplimit (hicn_header_t * h, u8 hops)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.ip.hlim = hops;
+      break;
+    case 4:
+      h->v4.ip.ttl = hops;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+
+int
+hicn_packet_get_lifetime (const hicn_header_t * h, u32 * lifetime)
+{
+  hicn_type_t type = hicn_header_to_type (h);
+  return hicn_ops_vft[type.l1]->get_lifetime (type, &h->protocol,
+                                             (hicn_lifetime_t *) lifetime);
+}
+
+int
+hicn_packet_set_lifetime (hicn_header_t * h, u32 lifetime)
+{
+  hicn_type_t type = hicn_header_to_type (h);
+  return hicn_ops_vft[type.l1]->set_lifetime (type, &h->protocol,
+                                             (hicn_lifetime_t) lifetime);
+}
+
+int
+hicn_packet_get_reserved_bits (const hicn_header_t * h, u8 * reserved_bits)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *reserved_bits = h->v6.tcp.reserved;
+      break;
+    case 4:
+      *reserved_bits = h->v4.tcp.reserved;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_reserved_bits (hicn_header_t * h, u8 reserved_bits)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.reserved = reserved_bits;
+      break;
+    case 4:
+      h->v4.tcp.reserved = reserved_bits;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_payload_type (const hicn_header_t * h,
+                             hicn_payload_type_t * payload_type)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *payload_type = ((h->v6.tcp.flags & TCP_FLAG_URG) == TCP_FLAG_URG);
+      break;
+    case 4:
+      *payload_type = ((h->v4.tcp.flags & TCP_FLAG_URG) == TCP_FLAG_URG);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  if (*payload_type == HPT_UNSPEC)
+    {
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_payload_type (hicn_header_t * h,
+                             hicn_payload_type_t payload_type)
+{
+  if (payload_type != HPT_DATA && payload_type != HPT_MANIFEST)
+    {
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      if (payload_type)
+       h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_URG;
+      else
+       h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_URG;
+      break;
+    case 4:
+      if (payload_type)
+       h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_URG;
+      else
+       h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_URG;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_syn (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_SYN;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_SYN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_reset_syn (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_SYN;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_SYN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_test_syn (const hicn_header_t * h, bool * flag)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *flag = h->v6.tcp.flags & TCP_FLAG_SYN;
+      break;
+    case 4:
+      *flag = h->v4.tcp.flags & TCP_FLAG_SYN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_ack (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_ACK;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_ACK;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_reset_ack (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_ACK;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_ACK;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_test_ack (const hicn_header_t * h, bool * flag)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *flag = h->v6.tcp.flags & TCP_FLAG_ACK;
+      break;
+    case 4:
+      *flag = h->v4.tcp.flags & TCP_FLAG_ACK;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_rst (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_RST;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_RST;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_reset_rst (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_RST;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_RST;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_test_rst (const hicn_header_t * h, bool * flag)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *flag = h->v6.tcp.flags & TCP_FLAG_RST;
+      break;
+    case 4:
+      *flag = h->v4.tcp.flags & TCP_FLAG_RST;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_fin (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_FIN;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_FIN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_reset_fin (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_FIN;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_FIN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_test_fin (const hicn_header_t * h, bool * flag)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *flag = h->v6.tcp.flags & TCP_FLAG_FIN;
+      break;
+    case 4:
+      *flag = h->v4.tcp.flags & TCP_FLAG_FIN;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_ece (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags | TCP_FLAG_ECE;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags | TCP_FLAG_ECE;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_reset_ece (hicn_header_t * h)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.flags = h->v6.tcp.flags & ~TCP_FLAG_ECE;
+      break;
+    case 4:
+      h->v4.tcp.flags = h->v4.tcp.flags & ~TCP_FLAG_ECE;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_test_ece (const hicn_header_t * h, bool * flag)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *flag = h->v6.tcp.flags & TCP_FLAG_ECE;
+      break;
+    case 4:
+      *flag = h->v4.tcp.flags & TCP_FLAG_ECE;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_src_port (hicn_header_t * h, u16 src_port)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.sport = htons (src_port);
+      break;
+    case 4:
+      h->v4.tcp.sport = htons (src_port);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_src_port (const hicn_header_t * h, u16 * src_port)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *src_port = ntohs (h->v6.tcp.sport);
+      break;
+    case 4:
+      *src_port = ntohs (h->v4.tcp.sport);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_set_dst_port (hicn_header_t * h, u16 dst_port)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      h->v6.tcp.dport = htons (dst_port);
+      break;
+    case 4:
+      h->v4.tcp.dport = htons (dst_port);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_get_dst_port (const hicn_header_t * h, u16 * dst_port)
+{
+  switch (HICN_IP_VERSION (h))
+    {
+    case 6:
+      *dst_port = ntohs (h->v6.tcp.dport);
+      break;
+    case 4:
+      *dst_port = ntohs (h->v4.tcp.dport);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_packet_copy_header (hicn_format_t format, const hicn_header_t * packet,
+                        hicn_header_t * destination, bool copy_ah)
+{
+  size_t header_length = _is_ipv4 (format) * IPV4_HDRLEN;
+  header_length += _is_ipv6 (format) * IPV6_HDRLEN;
+  header_length += _is_icmp (format) * ICMP_HDRLEN;
+  header_length += _is_tcp (format) * TCP_HDRLEN;
+  header_length += _is_ah (format) * copy_ah * AH_HDRLEN;
+
+  memcpy (destination, packet, header_length);
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+#define _INTEREST 1
+#define _DATA     0
+
+/* Interest */
+
+int
+hicn_interest_get_name (hicn_format_t format, const hicn_header_t * interest,
+                       hicn_name_t * name)
+{
+  return hicn_packet_get_name (format, interest, name, _INTEREST);
+}
+
+int
+hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest,
+                       const hicn_name_t * name)
+{
+  int ret_err = hicn_packet_reset_ece (interest);      //interest packet -> ece flag unset
+  if (ret_err < 0)
+    return HICN_LIB_ERROR_UNEXPECTED;
+  return hicn_packet_set_name (format, interest, name, _INTEREST);
+}
+
+int
+hicn_interest_get_locator (hicn_format_t format,
+                          const hicn_header_t * interest,
+                          ip_address_t * ip_address)
+{
+  return hicn_packet_get_locator (format, interest, ip_address, _INTEREST);
+}
+
+int
+hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest,
+                          const ip_address_t * ip_address)
+{
+  return hicn_packet_set_locator (format, interest, ip_address, _INTEREST);
+}
+
+int
+hicn_interest_compare (const hicn_header_t * interest_1,
+                      const hicn_header_t * interest_2)
+{
+  return hicn_packet_compare (interest_1, interest_2);
+}
+
+int
+hicn_interest_get_lifetime (const hicn_header_t * interest, u32 * lifetime)
+{
+  return hicn_packet_get_lifetime (interest, lifetime);
+}
+
+int
+hicn_interest_set_lifetime (hicn_header_t * interest, u32 lifetime)
+{
+  return hicn_packet_set_lifetime (interest, lifetime);
+}
+
+int
+hicn_interest_get_header_length (hicn_format_t format,
+                                const hicn_header_t * interest,
+                                size_t * header_length)
+{
+  return hicn_packet_get_header_length (format, interest, header_length);
+}
+
+int
+hicn_interest_get_payload_length (hicn_format_t format,
+                                 const hicn_header_t * interest,
+                                 size_t * payload_length)
+{
+  return hicn_packet_get_payload_length (format, interest, payload_length);
+}
+
+int
+hicn_interest_get_payload (hicn_format_t format,
+                          const hicn_header_t * interest, u8 ** payload,
+                          size_t * payload_size, bool hard_copy)
+{
+  return hicn_packet_get_payload (format, interest, payload, payload_size,
+                                 hard_copy);
+}
+
+int
+hicn_interest_set_payload (hicn_format_t format, hicn_header_t * interest,
+                          const u8 * payload, size_t payload_length)
+{
+  return hicn_packet_set_payload (format, interest, payload, payload_length);
+}
+
+int
+hicn_interest_reset_for_hash (hicn_format_t format, hicn_header_t * packet)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->reset_interest_for_hash (type,
+                                                        &packet->protocol);
+}
+
+/* Data */
+
+int
+hicn_data_get_name (hicn_format_t format, const hicn_header_t * data,
+                   hicn_name_t * name)
+{
+  return hicn_packet_get_name (format, data, name, _DATA);
+}
+
+int
+hicn_data_set_name (hicn_format_t format, hicn_header_t * data,
+                   hicn_name_t * name)
+{
+  int ret_err = hicn_packet_set_ece (data);    //data packet -> ece flag set
+  if (ret_err < 0)
+    return HICN_LIB_ERROR_UNEXPECTED;
+  return hicn_packet_set_name (format, data, name, _DATA);
+}
+
+int
+hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data,
+                      ip_address_t * ip_address)
+{
+  return hicn_packet_get_locator (format, data, ip_address, _DATA);
+}
+
+int
+hicn_data_set_locator (hicn_format_t format, hicn_header_t * data,
+                      const ip_address_t * ip_address)
+{
+  return hicn_packet_set_locator (format, data, ip_address, _DATA);
+}
+
+int
+hicn_data_compare (const hicn_header_t * data_1, const hicn_header_t * data_2)
+{
+  return hicn_packet_compare (data_1, data_2);
+}
+
+int
+hicn_data_get_expiry_time (const hicn_header_t * data, u32 * expiry_time)
+{
+  return hicn_packet_get_lifetime (data, expiry_time);
+}
+
+int
+hicn_data_set_expiry_time (hicn_header_t * data, u32 expiry_time)
+{
+  return hicn_packet_set_lifetime (data, (hicn_lifetime_t) expiry_time);
+}
+
+int
+hicn_data_get_header_length (hicn_format_t format, hicn_header_t * data,
+                            size_t * header_length)
+{
+  return hicn_packet_get_header_length (format, data, header_length);
+}
+
+int
+hicn_data_get_payload_length (hicn_format_t format,
+                             const hicn_header_t * data,
+                             size_t * payload_length)
+{
+  return hicn_packet_get_payload_length (format, data, payload_length);
+}
+
+int
+hicn_data_set_payload_type (hicn_header_t * data,
+                           hicn_payload_type_t payload_type)
+{
+  return hicn_packet_set_payload_type (data, payload_type);
+}
+
+int
+hicn_data_get_payload_type (const hicn_header_t * data,
+                           hicn_payload_type_t * payload_type)
+{
+  return hicn_packet_get_payload_type (data, payload_type);
+}
+
+int
+hicn_data_get_path_label (const hicn_header_t * data, u32 * path_label)
+{
+  hicn_type_t type = hicn_header_to_type (data);
+  return hicn_ops_vft[type.l1]->get_data_pathlabel (type, &data->protocol,
+                                                   path_label);
+}
+
+int
+hicn_data_set_path_label (hicn_header_t * data, u32 path_label)
+{
+  hicn_type_t type = hicn_header_to_type (data);
+  return hicn_ops_vft[type.l1]->set_data_pathlabel (type, &data->protocol,
+                                                   path_label);
+}
+
+int
+hicn_data_set_payload (hicn_format_t format, hicn_header_t * data,
+                      const u8 * payload, size_t payload_length)
+{
+  return hicn_packet_set_payload (format, data, payload, payload_length);
+}
+
+int
+hicn_data_get_payload (hicn_format_t format, const hicn_header_t * data,
+                      u8 ** payload, size_t * payload_size, bool hard_copy)
+{
+  return hicn_packet_get_payload (format, data, payload, payload_size,
+                                 hard_copy);
+}
+
+int
+hicn_data_reset_for_hash (hicn_format_t format, hicn_header_t * packet)
+{
+  hicn_type_t type = hicn_format_to_type (format);
+  return hicn_ops_vft[type.l1]->reset_interest_for_hash (type,
+                                                        &packet->protocol);
+
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/compat.h b/lib/src/compat.h
new file mode 100755 (executable)
index 0000000..1a1743d
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file compat.h
+ * @brief Implementation of the compatibility layer.
+ *
+ * The structure of the core API has evolved to support operations of a variety
+ * of packet formats in addition to IPv4/TCP and IPv6/TCP, namely with the use
+ * of ICMP for signalization and AH headers for integrity. The new API format
+ * has been designed to scale better with the multiplicity of packet formats,
+ * and provide a unified interface on top. We maintain an interface for the
+ * former API in this file, which mainly acts as a wrapper on top of new calls.
+ */
+#ifndef HICN_COMPAT_H
+#define HICN_COMPAT_H
+
+#include "common.h"
+#include "header.h"
+#include "name.h"
+
+/* HICN format options */
+#define HFO_INET  1 << 0
+#define HFO_INET6 1 << 1
+#define HFO_TCP   1 << 2
+#define HFO_ICMP  1 << 3
+#define HFO_AH    1 << 4
+
+#define _is_ipv4(format) ((format & HFO_INET))
+#define _is_ipv6(format) ((format & HFO_INET6) >> 1)
+#define _is_tcp(format)  ((format & HFO_TCP)   >> 2)
+#define _is_icmp(format) ((format & HFO_ICMP)  >> 3)
+#define _is_ah(format)   ((format & HFO_AH)    >> 4)
+
+typedef enum
+{
+  HF_UNSPEC = 0,
+  HF_INET_TCP = HFO_INET | HFO_TCP,
+  HF_INET6_TCP = HFO_INET6 | HFO_TCP,
+  HF_INET_ICMP = HFO_INET | HFO_ICMP,
+  HF_INET6_ICMP = HFO_INET6 | HFO_ICMP,
+  HF_INET_TCP_AH = HFO_INET | HFO_TCP | HFO_AH,
+  HF_INET6_TCP_AH = HFO_INET6 | HFO_TCP | HFO_AH,
+  HF_INET_ICMP_AH = HFO_INET | HFO_ICMP | HFO_AH,
+  HF_INET6_ICMP_AH = HFO_INET6 | HFO_ICMP | HFO_AH
+} hicn_format_t;
+
+/**
+ * Maximum Size of the hICN header (the effective size will depend on the
+ * underlying IP version)
+ */
+#define HICN_HDR_LEN sizeof(hicn_header_t)
+
+/**
+ * Minimum required header length to determine the type and length of a supposed
+ * hICN packet.
+ * This should be equal to the maximum value over all possible hICN packet
+ * formats, and less than the minimum possible IP packet size.
+ */
+#define HICN_V6_MIN_HDR_LEN 6  /* bytes */
+#define HICN_V4_MIN_HDR_LEN 4  /* bytes */
+
+// #define HICN_MIN_HDR_LEN ((HICN_V6_MIN_HDR_LEN > HICN_V4_MIN_HDR_LEN) ? HICN_V6_MIN_HDR_LEN : HICN_V4_MIN_HDR_LEN)
+#define HICN_MIN_HDR_LEN HICN_V6_MIN_HDR_LEN
+
+/**
+ * @brief Parse packet headers and return hICN format
+ * @param [in] format - hICN Format
+ * @param [in, out] packet - Buffer containing the hICN header to be initialized
+ * @return hICN error code
+ */
+int hicn_packet_init_header (hicn_format_t format, hicn_header_t * packet);
+
+/**
+ * @brief Parse packet headers and return hICN format
+ * @param [in] h - hICN header
+ * @param [out] format - hICN format
+ * @return hICN error code
+ */
+int hicn_packet_get_format (const hicn_header_t * packet,
+                           hicn_format_t * format);
+
+/**
+ * @brief Update checksums in packet headers
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @return hICN error code
+ */
+int hicn_packet_compute_checksum (hicn_format_t format,
+                                 hicn_header_t * packet);
+
+/**
+ * @brief compute the checksum of the packet header, adding init_sum to the final value
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @param [in] init_sum - value to add to the final checksum
+ * @return hICN error code
+ */
+int hicn_packet_compute_header_checksum (hicn_format_t format,
+                                        hicn_header_t * packet,
+                                        u16 init_sum);
+
+/**
+ * @brief Verify checksums in packet headers
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @return hICN error code
+ */
+int hicn_packet_check_integrity (hicn_format_t format,
+                                hicn_header_t * packet);
+
+// this is not accounted here
+/**
+ * @brief Return total length of hicn headers (but signature payload)
+ * @param [in] format - hICN format
+ * @param [out] header_length - Total length of headers
+ * @return hICN error code
+ */
+int hicn_packet_get_header_length_from_format (hicn_format_t format,
+                                              size_t * header_length);
+
+/**
+ * @brief Return total length of hicn headers (before payload)
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] header_length - Total length of headers
+ * @return hICN error code
+ */
+int hicn_packet_get_header_length (hicn_format_t format,
+                                  const hicn_header_t * packet,
+                                  size_t * header_length);
+
+/**
+ * @brief Return payload length
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] payload_length - payload length
+ * @return hICN error code
+ */
+int hicn_packet_get_payload_length (hicn_format_t format,
+                                   const hicn_header_t * packet,
+                                   size_t * payload_length);
+
+/**
+ * @brief Sets payload length
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @param [in] payload_length - payload length
+ * @return hICN error code
+ */
+int hicn_packet_set_payload_length (hicn_format_t format,
+                                   hicn_header_t * packet,
+                                   const size_t payload_length);
+
+/**
+ * @brief Compare two hICN packets
+ * @param [in] packet_1 - First packet
+ * @param [in] packet_2 - Second packet
+ * @return 0 if both packets are considered equal, any other value otherwise.
+ */
+int hicn_packet_compare (const hicn_header_t * packet1,
+                        const hicn_header_t * packet2);
+
+/**
+ * @brief Retrieve the name of an interest/data packet
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] name - name holding the result
+ * @param [in] is_interest - Flag to determine whether it is an interest (1) or
+ * data packet (0)
+ * @return hICN error code
+ */
+int hicn_packet_get_name (hicn_format_t format, const hicn_header_t * packet,
+                         hicn_name_t * name, u8 is_interest);
+
+/**
+ * @brief Sets the name of an interest/data packet
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @param [in] name - name to set into packet
+ * @param [in] is_interest - Flag to determine whether it is an interest (1) or
+ * data packet (0)
+ * @return hICN error code
+ */
+int hicn_packet_set_name (hicn_format_t format, hicn_header_t * packet,
+                         const hicn_name_t * name, u8 is_interest);
+
+/**
+ * @brief Sets the payload of a packet
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @param [in] payload - payload to set
+ * @param [in] payload_length - size of the payload to set
+ * @return hICN error code
+ *
+ * NOTE:
+ *  - The buffer holding payload is assumed sufficiently large
+ *  - This function updates header fields with the new length, but no checksum.
+ */
+int hicn_packet_set_payload (hicn_format_t format, hicn_header_t * packet,
+                            const u8 * payload, u16 payload_length);
+
+/**
+ * @brief Retrieves the payload of a packet
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] payload - pointer to buffer for storing the result
+ * @param [out] payload_length - size of the retreived payload
+ * @param [in] hard_copy - Flag : if true (eg. 1), a copy of the payload is made
+ * into the payload buffer, otherwise (0) the pointer is changed to point to the payload offset in the packet.
+ * @return hICN error code
+ *
+ * NOTE:
+ *  - The buffer holding payload is assumed sufficiently large
+ */
+int hicn_packet_get_payload (hicn_format_t format,
+                            const hicn_header_t * packet, u8 ** payload,
+                            size_t * payload_size, bool hard_copy);
+
+/**
+ * @brief Retrieve the locator of an interest / data packet
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] ip_address - retrieved locator
+ * @param [in] is_interest - Flag to determine whether it is an interest (1) or
+ * data packet (0)
+ * @return hICN error code
+ */
+int hicn_packet_get_locator (hicn_format_t format,
+                            const hicn_header_t * packet,
+                            ip_address_t * ip_address, bool is_interest);
+
+/**
+ * @brief Sets the locator of an interest / data packet
+ * @param [in] format - hICN format
+ * @param [in,out] packet - packet header
+ * @param [out] ip_address - retrieved locator
+ * @param [in] is_interest - Flag to determine whether it is an interest (1) or
+ * data packet (0)
+ * @return hICN error code
+ */
+int hicn_packet_set_locator (hicn_format_t format, hicn_header_t * packet,
+                            const ip_address_t * ip_address,
+                            bool is_interest);
+
+/**
+ * @brief Retrieves the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] bytes - Retrieved signature size
+ * @return hICN error code
+ */
+int hicn_packet_get_signature_size (hicn_format_t format,
+                                   const hicn_header_t * packet,
+                                   size_t * bytes);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [in] bytes - Retrieved signature size
+ * @return hICN error code
+ */
+int hicn_packet_set_signature_size (hicn_format_t format,
+                                   hicn_header_t * packet, size_t bytes);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [in] signature_timestamp - Signature timestamp to set
+ * @return hICN error code
+ */
+int hicn_packet_set_signature_timestamp (hicn_format_t format, hicn_header_t * h,
+                               uint64_t signature_timestamp);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] signature_timestamp - Retrieved signature timestamp
+ * @return hICN error code
+ */
+int hicn_packet_get_signature_timestamp (hicn_format_t format, const hicn_header_t * h,
+                               uint64_t *signature_timestamp);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [in] validation_algorithm - Validation algorithm to set
+ * @return hICN error code
+ */
+int hicn_packet_set_validation_algorithm (hicn_format_t format, hicn_header_t * h,
+                               uint8_t validation_algorithm);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] validation_algorithm - Retrieved validation algorithm
+ * @return hICN error code
+ */
+int hicn_packet_get_validation_algorithm (hicn_format_t format, const hicn_header_t * h,
+                               uint8_t * validation_algorithm);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [in] key_id - Key id to set
+ * @return hICN error code
+ */
+int hicn_packet_set_key_id (hicn_format_t format, hicn_header_t * h,
+                               uint8_t *key_id);
+
+/**
+ * @brief Sets the signature size
+ * @param [in] format - hICN format
+ * @param [in] packet - packet header
+ * @param [out] key_id - Retrieved key id
+ * @return hICN error code
+ */
+int hicn_packet_get_key_id (hicn_format_t format, hicn_header_t * h,
+                               uint8_t ** key_id, uint8_t *key_id_length);
+
+/**
+ * @brief Retrieves the packet hop limit
+ * @param [in] packet - packet header
+ * @param [out] hops - Retrieved hop limit
+ * @return hICN error code
+ */
+int hicn_packet_get_hoplimit (const hicn_header_t * packet, u8 * hops);
+
+/**
+ * @brief Sets the packet hop limit
+ * @param [in] packet - packet header
+ * @param [in] hops - Hop limit to set
+ * @return hICN error code
+ */
+int hicn_packet_set_hoplimit (hicn_header_t * packet, u8 hops);
+
+int hicn_packet_copy_header (hicn_format_t format,
+                            const hicn_header_t * packet,
+                            hicn_header_t * destination, bool copy_ah);
+
+int hicn_packet_get_lifetime (const hicn_header_t * packet, u32 * lifetime);
+int hicn_packet_set_lifetime (hicn_header_t * packet, u32 lifetime);
+int hicn_packet_get_reserved_bits (const hicn_header_t * packet,
+                                  u8 * reserved_bits);
+int hicn_packet_set_reserved_bits (hicn_header_t * packet,
+                                  const u8 reserved_bits);
+int hicn_packet_get_payload_type (const hicn_header_t * packet,
+                                 hicn_payload_type_t * payload_type);
+int hicn_packet_set_payload_type (hicn_header_t * packet,
+                                 const hicn_payload_type_t payload_type);
+
+int hicn_packet_set_syn (hicn_header_t * packet);
+int hicn_packet_reset_syn (hicn_header_t * packet);
+int hicn_packet_test_syn (const hicn_header_t * packet, bool * flag);
+int hicn_packet_set_ack (hicn_header_t * packet);
+int hicn_packet_reset_ack (hicn_header_t * packet);
+int hicn_packet_test_ack (const hicn_header_t * packet, bool * flag);
+int hicn_packet_set_rst (hicn_header_t * packet);
+int hicn_packet_reset_rst (hicn_header_t * packet);
+int hicn_packet_test_rst (const hicn_header_t * packet, bool * flag);
+int hicn_packet_set_fin (hicn_header_t * packet);
+int hicn_packet_reset_fin (hicn_header_t * packet);
+int hicn_packet_test_fin (const hicn_header_t * packet, bool * flag);
+int hicn_packet_set_ece (hicn_header_t * packet);
+int hicn_packet_reset_ece (hicn_header_t * packet);
+int hicn_packet_test_ece (const hicn_header_t * packet, bool * flag);
+
+int hicn_packet_set_src_port (hicn_header_t * packet, u16 src_port);
+int hicn_packet_get_src_port (const hicn_header_t * packet, u16 * src_port);
+int hicn_packet_set_dst_port (hicn_header_t * packet, u16 dst_port);
+int hicn_packet_get_dst_port (const hicn_header_t * packet, u16 * dst_port);
+
+/* Interest */
+
+int hicn_interest_get_name (hicn_format_t format,
+                           const hicn_header_t * interest,
+                           hicn_name_t * name);
+int hicn_interest_set_name (hicn_format_t format, hicn_header_t * interest,
+                           const hicn_name_t * name);
+int hicn_interest_get_locator (hicn_format_t format,
+                              const hicn_header_t * interest,
+                              ip_address_t * ip_address);
+int hicn_interest_set_locator (hicn_format_t format, hicn_header_t * interest,
+                              const ip_address_t * ip_address);
+int hicn_interest_compare (const hicn_header_t * interest_1,
+                          const hicn_header_t * interest_2);
+int hicn_interest_set_lifetime (hicn_header_t * interest, u32 lifetime);
+int hicn_interest_get_lifetime (const hicn_header_t * interest,
+                               u32 * lifetime);
+int hicn_interest_get_header_length (hicn_format_t format,
+                                    const hicn_header_t * interest,
+                                    size_t * header_length);
+int hicn_interest_get_payload_length (hicn_format_t format,
+                                     const hicn_header_t * interest,
+                                     size_t * payload_length);
+int hicn_interest_set_payload (hicn_format_t format, hicn_header_t * interest,
+                              const u8 * payload, size_t payload_length);
+int hicn_interest_get_payload (hicn_format_t format,
+                              const hicn_header_t * interest, u8 ** payload,
+                              size_t * payload_size, bool hard_copy);
+int hicn_interest_reset_for_hash (hicn_format_t format,
+                                 hicn_header_t * packet);
+
+/* Data */
+
+int hicn_data_get_name (hicn_format_t format, const hicn_header_t * data,
+                       hicn_name_t * name);
+int hicn_data_set_name (hicn_format_t format, hicn_header_t * data,
+                       hicn_name_t * name);
+int hicn_data_get_locator (hicn_format_t format, const hicn_header_t * data,
+                          ip_address_t * ip_address);
+int hicn_data_set_locator (hicn_format_t format, hicn_header_t * data,
+                          const ip_address_t * ip_address);
+int hicn_data_compare (const hicn_header_t * data_1,
+                      const hicn_header_t * data_2);
+int hicn_data_get_expiry_time (const hicn_header_t * data, u32 * expiry_time);
+int hicn_data_set_expiry_time (hicn_header_t * data, u32 expiry_time);
+int hicn_data_get_header_length (hicn_format_t format, hicn_header_t * data,
+                                size_t * header_length);
+int hicn_data_get_payload_length (hicn_format_t format,
+                                 const hicn_header_t * data,
+                                 size_t * payload_length);
+int hicn_data_get_path_label (const hicn_header_t * data, u32 * path_label);
+int hicn_data_set_path_label (hicn_header_t * data, u32 path_label);
+int hicn_data_get_payload (hicn_format_t format, const hicn_header_t * data,
+                          u8 ** payload, size_t * payload_size,
+                          bool hard_copy);
+int hicn_data_set_payload (hicn_format_t format, hicn_header_t * data,
+                          const u8 * payload, size_t payload_length);
+int hicn_data_get_payload_type (const hicn_header_t * data,
+                               hicn_payload_type_t * payload_type);
+int hicn_data_set_payload_type (hicn_header_t * data,
+                               hicn_payload_type_t payload_type);
+int hicn_data_reset_for_hash (hicn_format_t format, hicn_header_t * packet);
+
+#endif /* HICN_COMPAT_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/error.c b/lib/src/error.c
new file mode 100755 (executable)
index 0000000..865e2b4
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file error.c
+ * @brief Implementation of error management functions.
+ */
+
+#include "error.h"
+
+const char *HICN_LIB_ERROR_STRING[] = {
+#define _(a,b,c) [b] = c,
+  foreach_libhicn_error
+#undef _
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/error.h b/lib/src/error.h
new file mode 100755 (executable)
index 0000000..3e027c4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file error.h
+ * @brief Error management functions.
+ */
+#ifndef HICN_ERROR_H
+#define HICN_ERROR_H
+
+/******************************************************************************
+ * Error definitions
+ ******************************************************************************/
+
+#define foreach_libhicn_error                                                   \
+_(NONE,                 0,      "OK")                                           \
+_(UNSPECIFIED,          128,    "Unspecified Error")                            \
+_(NOT_IMPLEMENTED,      180,    "Function not yet implemented")                 \
+_(NOT_HICN,             202,    "Non hICN packet")                              \
+_(UNKNOWN_ADDRESS,      210,    "Unknown address")                              \
+_(INVALID_PARAMETER,    220,    "Invalid parameter")                            \
+_(INVALID_IP_ADDRESS,   221,    "Invalid IP address")                           \
+_(CORRUPTED_PACKET,     222,    "Corrupted packet ")                            \
+_(UNEXPECTED,           298,    "Unexpected error")
+
+typedef enum
+{
+#define _(a,b,c) HICN_LIB_ERROR_##a = (-b),
+  foreach_libhicn_error
+#undef _
+    HICN_LIB_N_ERROR,
+} hicn_lib_error_t;
+
+extern const char *HICN_LIB_ERROR_STRING[];
+
+#define hicn_strerror(errno) (char *)(HICN_LIB_ERROR_STRING[-errno])
+
+#endif /* HICN_ERROR_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/header.h b/lib/src/header.h
new file mode 100755 (executable)
index 0000000..3864064
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file header.h
+ * @brief hICN header data structures.
+ * details.
+ */
+#ifndef HICN_HEADER_H
+#define HICN_HEADER_H
+
+#include "common.h"
+#include "protocol.h"
+
+
+typedef struct
+{
+  _ipv6_header_t ip;
+  union
+  {
+    _tcp_header_t tcp;
+    _icmp_header_t icmp;
+    _icmp_wldr_header_t wldr;
+  };
+} hicn_v6_hdr_t;
+
+typedef struct
+{
+  _ipv6_header_t ip;
+  union
+  {
+    struct
+    {
+      _tcp_header_t tcp;
+      _ah_header_t ah;
+    };
+    struct
+    {
+      _icmp_header_t icmp;
+      _ah_header_t icmp_ah;
+    };
+  };
+} hicn_v6ah_hdr_t;
+
+typedef struct
+{
+  _ipv4_header_t ip;
+  union
+  {
+    _tcp_header_t tcp;
+    _icmp_header_t icmp;
+    _icmp_wldr_header_t wldr;
+  };
+} hicn_v4_hdr_t;
+
+typedef struct
+{
+  _ipv4_header_t ip;
+  union
+  {
+    struct
+    {
+      _tcp_header_t tcp;
+      _ah_header_t ah;
+    };
+    struct
+    {
+      _icmp_header_t icmp;
+      _ah_header_t icmp_ah;
+    };
+  };
+} hicn_v4ah_hdr_t;
+
+typedef union
+{
+  /* To deprecate as redundant with hicn_type_t */
+  hicn_v6_hdr_t v6;
+  hicn_v6ah_hdr_t v6ah;
+  hicn_v4_hdr_t v4;
+  hicn_v4ah_hdr_t v4ah;
+
+  hicn_protocol_t protocol;
+} hicn_header_t;
+
+#endif /* HICN_HEADER_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/hicn.h b/lib/src/hicn.h
new file mode 100755 (executable)
index 0000000..749fd42
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file hicn.h
+ * @brief hICN master include file.
+ *
+ * Reference: https://tools.ietf.org/html/draft-muscariello-intarea-hicn
+ *
+ * This file is the entry point for projects to libhicn, which provides a
+ * reference implementation for hICN specifications [1], including:
+ *  - naming
+ *  - packet headers
+ *  - protocol mappings (IPv4, IPv6, TCP, ICMP, AH)
+ *  - protocol independent packet operations
+ *  - helpers for additional features such as Wireless Loss Detection and
+ *    Recovery (WLDR) [2], Anchorless Mobility Management (hICN-AMM) [3],
+ *    including MAP-Me producer mobility mechanisms [4].
+ *
+ *  [1] Hybrid Information-Centric Networking
+ *      L. Muscariello, G. Carofiglio, J. Augé, M. Papalini
+ *      IETF draft (intarea) @ https://tools.ietf.org/html/draft-muscariello-intarea-hicn
+ *
+ *  [2] Leveraging ICN in-network control for loss detection and recovery in wireless mobile networks
+ *      G. Carofiglio, L. Muscariello, M. Papalini, N. Rozhnova, X. Zeng
+ *      In proc. ICN'2016, Kyoto, JP
+ *
+ *  [3] Anchorless mobility through hICN
+ *      J. Augé, G. Carofiglio, L. Muscariello, M. Papalini
+ *      IETF draft (DMM) @ https://tools.ietf.org/html/draft-auge-dmm-hicn-mobility
+ *
+ *
+ *  [4] MAP-Me : Managing Anchorless Mobility in Content Centric Networking
+ *      J. Augé, G. Carofiglio, L. Muscariello, M. Papalini
+ *      IRTF draft (ICNRG) @ https://tools.ietf.org/html/draft-irtf-icnrg-mapme
+ */
+
+#ifndef HICN__H
+#define HICN__H
+
+#ifdef HICN_VPP_PLUGIN
+
+#include <hicn/header.h>
+#include <hicn/name.h>
+#include <hicn/ops.h>
+#include <hicn/mapme.h>
+
+#else
+
+#include <hicn/error.h>
+#include <hicn/header.h>
+#include <hicn/name.h>
+#include <hicn/ops.h>
+#include <hicn/mapme.h>
+#include <hicn/compat.h>
+
+#endif
+
+#endif /* HICN__H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/mapme.c b/lib/src/mapme.c
new file mode 100755 (executable)
index 0000000..e4c5ee1
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file mapme.c
+ * @brief Implementation  of MAP-Me anchorless producer mobility management.
+ */
+
+#include "mapme.h"
+#include "common.h"
+#include "error.h"
+
+#include "protocol/ipv4.h"
+#include "protocol/ipv6.h"
+
+size_t
+hicn_mapme_v4_create_packet (u8 * buf, const hicn_prefix_t * prefix,
+                            const mapme_params_t * params)
+{
+  hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) buf;
+  /* *INDENT-OFF* */
+  *mh = (hicn_mapme_v4_header_t) {
+    .ip = {
+      .version_ihl = (IPV4_DEFAULT_VERSION << 4) | (0x0f & IPV4_DEFAULT_IHL),
+      .tos = IPV4_DEFAULT_TOS,
+      .len = HICN_MAPME_V4_HDRLEN,
+      .id = htons(IPV4_DEFAULT_ID),
+      .frag_off = htons(IPV4_DEFAULT_FRAG_OFF),
+      .ttl = HICN_MAPME_TTL,
+      .protocol = IPPROTO_ICMP,
+      .csum = 0,
+      .saddr.as_u32 = 0,
+      .daddr = prefix->name.ip4,
+     },
+    .icmp = {
+      .type = ((params->type == UPDATE) || (params->type == NOTIFICATION))
+               ? HICN_MAPME_ICMP_TYPE_IPV4
+               : HICN_MAPME_ICMP_TYPE_ACK_IPV4,
+      .code = HICN_MAPME_ICMP_CODE,
+      .csum = 0,
+    },
+    .icmp_rd = {
+      .ip = prefix->name.ip4,
+    },
+    .seq = htonl(params->seq),
+    .len = prefix->len,
+  };
+  /* *INDENT-ON* */
+
+  return HICN_MAPME_V4_HDRLEN;
+}
+
+size_t
+hicn_mapme_v6_create_packet (u8 * buf, const hicn_prefix_t * prefix,
+                            const mapme_params_t * params)
+{
+  hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) buf;
+  /* *INDENT-OFF* */
+  *mh = (hicn_mapme_v6_header_t) {
+    .ip = {
+      .saddr = {{0}},
+      .daddr = prefix->name.ip6,
+      .version_class_flow = htonl(
+          (IPV6_DEFAULT_VERSION       << 28) |
+          (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+          (IPV6_DEFAULT_FLOW_LABEL     & 0xfffff)),
+      .len = htons(HICN_MAPME_V6_HDRLEN - IPV6_HDRLEN),
+      .nxt = IPPROTO_ICMPV6,
+      .hlim = HICN_MAPME_TTL,
+     },
+    .icmp = {
+      .type = ((params->type == UPDATE) || (params->type == NOTIFICATION))
+               ? HICN_MAPME_ICMP_TYPE_IPV6
+               : HICN_MAPME_ICMP_TYPE_ACK_IPV6,
+      .code = HICN_MAPME_ICMP_CODE,
+      .csum = 0,
+    },
+    .icmp_rd = {
+      .res = 0,
+      .tgt = prefix->name.ip6,
+      .dst = prefix->name.ip6,
+    },
+    .seq = htonl(params->seq),
+    .len = prefix->len,
+  };
+  /* *INDENT-ON* */
+  return HICN_MAPME_V6_HDRLEN;
+}
+
+size_t
+hicn_mapme_create_packet (u8 * buf, const hicn_prefix_t * prefix,
+                         const mapme_params_t * params)
+{
+  /* We currently ignore subsequent protocol definitions */
+  if (PREDICT_TRUE (params->protocol == IPPROTO_IPV6))
+    return hicn_mapme_v6_create_packet (buf, prefix, params);
+  else
+    return hicn_mapme_v4_create_packet (buf, prefix, params);
+}
+
+size_t
+hicn_mapme_v4_create_ack (u8 * buf, const mapme_params_t * params)
+{
+  ip4_address_t tmp;           // tmp storage for swapping IP addresses for ACK
+
+  hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) buf;
+  tmp = mh->ip.daddr;
+  mh->ip.daddr = mh->ip.saddr;
+  mh->ip.saddr = tmp;
+  mh->ip.ttl = HICN_MAPME_TTL;
+  mh->icmp.type = (params->type == UPDATE) ? UPDATE_ACK : NOTIFICATION_ACK;
+  mh->icmp.csum = 0;
+
+  return HICN_MAPME_V4_HDRLEN;
+}
+
+size_t
+hicn_mapme_v6_create_ack (u8 * buf, const mapme_params_t * params)
+{
+  ip6_address_t tmp;           // tmp storage for swapping IP addresses for ACK
+
+  hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) buf;
+  tmp = mh->ip.daddr;
+  mh->ip.daddr = mh->ip.saddr;
+  mh->ip.saddr = tmp;
+  mh->ip.hlim = HICN_MAPME_TTL;
+  mh->icmp.type = (params->type == UPDATE) ? UPDATE_ACK : NOTIFICATION_ACK;
+  mh->icmp.csum = 0;
+
+  return HICN_MAPME_V6_HDRLEN;
+}
+
+size_t
+hicn_mapme_create_ack (u8 * buf, const mapme_params_t * params)
+{
+  /* We currently ignore subsequent protocol definitions */
+  if (PREDICT_TRUE (params->protocol == IPPROTO_IPV6))
+    return hicn_mapme_v6_create_ack (buf, params);
+  else
+    return hicn_mapme_v4_create_ack (buf, params);
+}
+
+int
+hicn_mapme_v4_parse_packet (const u8 * packet, hicn_prefix_t * prefix,
+                           mapme_params_t * params)
+{
+  hicn_mapme_v4_header_t *mh = (hicn_mapme_v4_header_t *) packet;
+
+  /* *INDENT-OFF* */
+  *prefix = (hicn_prefix_t) {
+    .name = {
+      .ip4 = HICN_MAPME_TYPE_IS_IU (mh->icmp.type) ? mh->ip.daddr : mh->ip.saddr,
+    },
+    .len = mh->len,
+  };
+
+  *params = (mapme_params_t) {
+    .protocol = IPPROTO_IP,
+    .type = (mh->icmp.type == HICN_MAPME_ICMP_TYPE_IPV4) ? UPDATE : UPDATE_ACK,
+    .seq = ntohl (mh->seq),
+  };
+  /* *INDENT-ON* */
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_mapme_v6_parse_packet (const u8 * packet, hicn_prefix_t * prefix,
+                           mapme_params_t * params)
+{
+  hicn_mapme_v6_header_t *mh = (hicn_mapme_v6_header_t *) packet;
+
+  /* *INDENT-OFF* */
+  *prefix = (hicn_prefix_t) {
+    .name = {
+      .ip6 = HICN_MAPME_TYPE_IS_IU (mh->icmp.type) ? mh->ip.daddr : mh->ip.saddr,
+    },
+    .len = mh->len,
+  };
+
+  *params = (mapme_params_t) {
+    .protocol = IPPROTO_IPV6,
+    .type = (mh->icmp.type == HICN_MAPME_ICMP_TYPE_IPV6) ? UPDATE : UPDATE_ACK,
+    .seq = ntohl (mh->seq),
+  };
+  /* *INDENT-ON* */
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_mapme_parse_packet (const u8 * packet, hicn_prefix_t * prefix,
+                        mapme_params_t * params)
+{
+  switch (HICN_IP_VERSION (packet))
+    {
+    case 4:
+      return hicn_mapme_v4_parse_packet (packet, prefix, params);
+    case 6:
+      return hicn_mapme_v6_parse_packet (packet, prefix, params);
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/mapme.h b/lib/src/mapme.h
new file mode 100755 (executable)
index 0000000..460c152
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file mapme.h
+ * @brief MAP-Me anchorless producer mobility management.
+ */
+#ifndef HICN_MAPME_H
+#define HICN_MAPME_H
+
+#include <stdint.h>            // u32
+#include <stdbool.h>
+
+#include "common.h"
+#include "protocol.h"
+#include "ops.h"
+
+/**
+ * @brief MAP-Me configuration options
+ */
+typedef struct
+{
+    /** MAP-Me enabled flag (default: false) */
+  bool enabled;
+    /** timescale (T_U parameter) in ms (default: 0 for no notifications) */
+  u32 timescale;
+    /** retransmission timer in ms (default: 50) */
+  u32 retx;
+    /**
+     * Discovery enabled flag (default: true, should be true if mandatory is
+     * notifications are enabled)
+     */
+  bool discovery;
+} hicn_mapme_conf_t;
+
+/** @brief Default MAP-Me configuration */
+static const hicn_mapme_conf_t hicn_mapme_conf = {
+  .enabled = false,
+  .timescale = 0,
+  .retx = 50,
+  .discovery = true,
+};
+
+/** @brief MAP-Me update sequence number */
+typedef u32 seq_t;
+
+/** @brief MAP-Me packet types */
+typedef enum
+{
+  UNKNOWN,
+  UPDATE,
+  UPDATE_ACK,
+  NOTIFICATION,
+  NOTIFICATION_ACK,
+} hicn_mapme_type_t;
+
+/** @brief MAP-Me parameters (excluding those contained in * hicn_prefix_t) */
+typedef struct
+{
+  int protocol;
+  hicn_mapme_type_t type;
+  seq_t seq;
+} mapme_params_t;
+
+
+/* MAP-Me API */
+size_t hicn_mapme_create_packet (u8 * buf, const hicn_prefix_t * prefix,
+                                const mapme_params_t * params);
+size_t hicn_mapme_create_ack (u8 * buf, const mapme_params_t * params);
+int hicn_mapme_parse_packet (const u8 * packet, hicn_prefix_t * prefix,
+                            mapme_params_t * params);
+
+/* Implementation & parsing : ICMP Redirect */
+
+#define HEADER_TYPE_MAPME4 (hicn_type_t) {0, IPPROTO_ICMPRD, IPPROTO_ICMP, IPPROTO_IP}
+#define HEADER_TYPE_MAPME6 (hicn_type_t) {0, IPPROTO_ICMPRD, IPPROTO_ICMP, IPPROTO_IPV6}
+
+#define HICN_MAPME_ACK_FLAG (0x20 | 0x60)
+
+#define HICN_MAPME_ICMP_TYPE_IPV4     5
+#define HICN_MAPME_ICMP_TYPE_IPV6     137
+#define HICN_MAPME_ICMP_TYPE_ACK_IPV4 (HICN_MAPME_ICMP_TYPE_IPV4 | HICN_MAPME_ACK_FLAG)
+#define HICN_MAPME_ICMP_TYPE_ACK_IPV6 (HICN_MAPME_ICMP_TYPE_IPV6 | HICN_MAPME_ACK_FLAG)
+#define HICN_MAPME_ICMP_CODE 0 /* Redirect Datagrams for the Network (or subnet) */
+
+#define HICN_MAPME_TYPE_IS_IU(type)     ((type == HICN_MAPME_ICMP_TYPE_IPV4)     || (type == HICN_MAPME_ICMP_TYPE_IPV6))
+#define HICN_MAPME_TYPE_IS_IU_ACK(type) ((type == HICN_MAPME_ICMP_TYPE_ACK_IPV4) || (type == HICN_MAPME_ICMP_TYPE_ACK_IPV6))
+
+#define HICN_MAPME_IS_IU(type, code) (HICN_MAPME_TYPE_IS_IU(type) && (code == HICN_MAPME_ICMP_CODE))
+#define HICN_MAPME_IS_ACK(type, code) (HICN_MAPME_TYPE_IS_IU_ACK(type) && (code == HICN_MAPME_ICMP_CODE))
+
+#define HICN_IS_MAPME(type, code) (HICN_MAPME_IS_IU(type, code) || HICN_MAPME_IS_ACK(type, code))
+
+/* Fast check for ACK flag */
+#define HICN_MAPME_IS_ACK_FAST(icmp_type) (icmp_type & HICN_MAPME_ACK_FLAG)
+
+/* Default TTL */
+#define HICN_MAPME_TTL 255     // typical for redirect (ref?)
+
+/** @brief MAP-Me packet header for IPv4 */
+typedef struct __attribute__ ((packed))
+{
+  _ipv4_header_t ip;
+  _icmp_header_t icmp;
+  _icmprd4_header_t icmp_rd;
+  seq_t seq;
+  u8 len;
+  u8 _pad[3];
+} hicn_mapme_v4_header_t;
+
+/** @brief MAP-Me packet header for IPv6 */
+typedef struct __attribute__ ((packed))
+{
+  _ipv6_header_t ip;
+  _icmp_header_t icmp;
+  _icmprd_header_t icmp_rd;
+  seq_t seq;
+  u8 len;
+  u8 _pad[3];
+} hicn_mapme_v6_header_t;
+
+/** @brief MAP-Me packet header (IP version agnostic) */
+typedef union
+{
+  hicn_mapme_v4_header_t v4;
+  hicn_mapme_v6_header_t v6;
+} hicn_mapme_header_t;
+
+#define HICN_MAPME_V4_HDRLEN sizeof(hicn_mapme_v4_header_t)
+#define HICN_MAPME_V6_HDRLEN sizeof(hicn_mapme_v6_header_t)
+
+#endif /* HICN_MAPME_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/name.c b/lib/src/name.c
new file mode 100755 (executable)
index 0000000..6e57112
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file name.c
+ * @brief Implementation of hICN name helpers.
+ */
+
+#include <arpa/inet.h>         // inet_ptin
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>            // strtoul
+#include <string.h>            // memcpy
+
+#include "common.h"
+#include "error.h"
+#include "name.h"
+
+#define DUMMY_PORT ntohs(1234)
+
+#if ! HICN_VPP_PLUGIN
+int
+hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name)
+{
+  int af, rc;
+
+  af = get_addr_family (ip_address);
+
+  switch (af)
+    {
+    case AF_INET:
+      if (name->type == HNT_UNSPEC)
+       {
+         name->type = HNT_CONTIGUOUS_V4;
+       }
+      name->len = IPV4_ADDR_LEN;
+      break;
+    case AF_INET6:
+      if (name->type == HNT_UNSPEC)
+       {
+         name->type = HNT_CONTIGUOUS_V6;
+       }
+      name->len = IPV6_ADDR_LEN;
+      break;
+    default:
+      return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
+    }
+
+  if ((name->type != HNT_CONTIGUOUS_V4) && (name->type != HNT_CONTIGUOUS_V6))
+    {
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  rc = inet_pton (af, ip_address, name->buffer);
+  if (rc <= 0)
+    {
+      return HICN_LIB_ERROR_UNKNOWN_ADDRESS;
+    }
+  *(u32 *) (name->buffer + name->len) = id;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id,
+                                 hicn_name_t * name)
+{
+  switch (ip_address->family)
+    {
+    case AF_INET:
+      if (name->type == HNT_UNSPEC)
+       {
+         name->type = HNT_CONTIGUOUS_V4;
+       }
+      break;
+    case AF_INET6:
+      if (name->type == HNT_UNSPEC)
+       {
+         name->type = HNT_CONTIGUOUS_V6;
+       }
+      break;
+    default:
+      return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
+    }
+
+  name->len = ip_address->prefix_len;
+  if ((name->type != HNT_CONTIGUOUS_V4) && (name->type != HNT_CONTIGUOUS_V6))
+    {
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  memcpy (name->buffer, ip_address->buffer, ip_address_len (ip_address));
+  *(u32 *) (name->buffer + name->len) = id;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+u8
+hicn_name_get_length (const hicn_name_t * name)
+{
+  return name->len;
+}
+
+int
+hicn_name_compare (const hicn_name_t * name_1, const hicn_name_t * name_2,
+                  bool consider_segment)
+{
+  hicn_name_t *name1 = (hicn_name_t *) name_1;
+  hicn_name_t *name2 = (hicn_name_t *) name_2;
+
+  if ((name1->type == HNT_CONTIGUOUS_V4 && name2->type == HNT_CONTIGUOUS_V6)
+      || (name1->type == HNT_CONTIGUOUS_V6
+         && name2->type == HNT_CONTIGUOUS_V4))
+    {
+      return -1;
+    }
+
+  if ((name1->type == HNT_IOV_V4 && name2->type == HNT_IOV_V6) ||
+      (name1->type == HNT_IOV_V6 && name2->type == HNT_IOV_V4))
+    {
+      return -1;
+    }
+
+  if ((name1->type == HNT_IOV_V4 && name2->type == HNT_CONTIGUOUS_V6) ||
+      (name1->type == HNT_IOV_V6 && name2->type == HNT_CONTIGUOUS_V4))
+    {
+      return -1;
+    }
+
+  if (name1->type == HNT_UNSPEC || name2->type == HNT_UNSPEC)
+    {
+      return -1;
+    }
+
+  size_t len1 = 0, len2 = 0;
+
+  u8 *buffer11, *buffer12, *buffer21, *buffer22;
+
+  switch (name1->type)
+    {
+    case HNT_CONTIGUOUS_V4:
+      buffer11 = name1->buffer;
+      buffer12 = name1->buffer + IPV4_ADDR_LEN;
+      len1 = IPV4_ADDR_LEN;
+      break;
+    case HNT_CONTIGUOUS_V6:
+      buffer11 = name1->buffer;
+      buffer12 = name1->buffer + IPV6_ADDR_LEN;
+      len1 = IPV6_ADDR_LEN;
+      break;
+    case HNT_IOV_V4:
+      buffer11 = name1->iov.buffers[0].iov_base;
+      buffer12 = name1->iov.buffers[1].iov_base;
+      len1 = IPV4_ADDR_LEN;
+      break;
+    case HNT_IOV_V6:
+      buffer11 = name1->iov.buffers[0].iov_base;
+      buffer12 = name1->iov.buffers[1].iov_base;
+      len1 = IPV6_ADDR_LEN;
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  switch (name2->type)
+    {
+    case HNT_CONTIGUOUS_V4:
+      buffer21 = name2->buffer;
+      buffer22 = name2->buffer + IPV4_ADDR_LEN;
+      len2 = IPV4_ADDR_LEN;
+      break;
+    case HNT_CONTIGUOUS_V6:
+      buffer21 = name2->buffer;
+      buffer22 = name2->buffer + IPV6_ADDR_LEN;
+      len2 = IPV6_ADDR_LEN;
+      break;
+    case HNT_IOV_V4:
+      buffer21 = name2->iov.buffers[0].iov_base;
+      buffer22 = name2->iov.buffers[1].iov_base;
+      len2 = IPV4_ADDR_LEN;
+      break;
+    case HNT_IOV_V6:
+      buffer21 = name2->iov.buffers[0].iov_base;
+      buffer22 = name2->iov.buffers[1].iov_base;
+      len2 = IPV6_ADDR_LEN;
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  // Sanity check
+  if (len1 != len2)
+    {
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  int ret1 = memcmp ((u8 *) buffer11, (u8 *) buffer21, len1);
+
+  if (!consider_segment)
+    {
+      return ret1;
+    }
+
+  int ret2 = memcmp ((u8 *) buffer12, (u8 *) buffer22, HICN_SEGMENT_LEN);
+
+  return ret1 || ret2;
+}
+
+int
+hicn_name_hash (const hicn_name_t * name, u32 * hash)
+{
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V4:
+      *hash = hash32 (name->buffer, HICN_V4_NAME_LEN);
+      break;
+    case HNT_CONTIGUOUS_V6:
+      *hash = hash32 (name->buffer, HICN_V6_NAME_LEN);
+      break;
+    case HNT_IOV_V4:
+    case HNT_IOV_V6:
+      *hash =
+       hash32 (name->iov.buffers[0].iov_base, name->iov.buffers[0].iov_len);
+      *hash =
+       cumulative_hash32 (name->iov.buffers[1].iov_base,
+                          name->iov.buffers[1].iov_len, *hash);
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_empty (hicn_name_t * name)
+{
+  return name->type == HNT_UNSPEC ? HICN_LIB_ERROR_NONE : 1;
+}
+
+int
+hicn_name_copy (hicn_name_t * dst, const hicn_name_t * src)
+{
+  switch (src->type)
+    {
+    case HNT_CONTIGUOUS_V4:
+    case HNT_CONTIGUOUS_V6:
+      *dst = *src;
+      break;
+    case HNT_IOV_V4:
+    case HNT_IOV_V6:
+      dst->type =
+       src->type == HNT_IOV_V4 ? HNT_CONTIGUOUS_V4 : HNT_CONTIGUOUS_V6;
+      memcpy (dst->buffer, src->iov.buffers[0].iov_base,
+             src->iov.buffers[0].iov_len);
+      memcpy (dst->buffer + src->iov.buffers[0].iov_len,
+             src->iov.buffers[1].iov_base, src->iov.buffers[1].iov_len);
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_copy_to_destination (u8 * dst, const hicn_name_t * src,
+                              bool copy_suffix)
+{
+  size_t length;
+
+  switch (src->type)
+    {
+    case HNT_CONTIGUOUS_V4:
+      if (copy_suffix)
+       {
+         length = HICN_V4_NAME_LEN;
+       }
+      else
+       {
+         length = IPV4_ADDR_LEN;
+       }
+      memcpy (dst, src->buffer, length);
+      break;
+    case HNT_CONTIGUOUS_V6:
+      if (copy_suffix)
+       {
+         length = HICN_V6_NAME_LEN;
+       }
+      else
+       {
+         length = IPV6_ADDR_LEN;
+       }
+      memcpy (dst, src->buffer, length);
+      break;
+    case HNT_IOV_V4:
+    case HNT_IOV_V6:
+      memcpy (dst, src->iov.buffers[0].iov_base, src->iov.buffers[0].iov_len);
+      if (copy_suffix)
+       {
+         memcpy (dst + src->iov.buffers[0].iov_len,
+                 src->iov.buffers[1].iov_base, src->iov.buffers[1].iov_len);
+       }
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_set_seq_number (hicn_name_t * name, u32 seq_number)
+{
+  u8 *sequence_number = NULL;
+
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+      sequence_number = name->buffer + IPV6_ADDR_LEN;
+      break;
+    case HNT_CONTIGUOUS_V4:
+      sequence_number = name->buffer + IPV4_ADDR_LEN;
+      break;
+    case HNT_IOV_V6:
+    case HNT_IOV_V4:
+      sequence_number = name->iov.buffers[1].iov_base;
+      break;
+    case HNT_UNSPEC:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  if (sequence_number)
+    {
+      *(u32 *) sequence_number = seq_number;
+    }
+  else
+    {
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_to_sockaddr_address (const hicn_name_t * name,
+                              struct sockaddr *ip_address)
+{
+  struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) ip_address;
+  struct sockaddr_in *tmp4 = (struct sockaddr_in *) ip_address;
+
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+      tmp6->sin6_family = AF_INET6;
+      tmp6->sin6_scope_id = 0;
+      tmp6->sin6_port = DUMMY_PORT;
+      memcpy (&tmp6->sin6_addr, name->buffer, IPV6_ADDR_LEN);
+      break;
+    case HNT_IOV_V6:
+      tmp6->sin6_family = AF_INET6;
+      tmp6->sin6_scope_id = 0;
+      tmp6->sin6_port = DUMMY_PORT;
+      memcpy (&tmp6->sin6_addr, name->iov.buffers[0].iov_base,
+             name->iov.buffers[0].iov_len);
+      break;
+    case HNT_CONTIGUOUS_V4:
+      tmp4->sin_family = AF_INET;
+      tmp4->sin_port = DUMMY_PORT;
+      memcpy (&tmp4->sin_addr, name->buffer, IPV4_ADDR_LEN);
+      break;
+    case HNT_IOV_V4:
+      tmp4->sin_family = AF_INET;
+      tmp4->sin_port = DUMMY_PORT;
+      memcpy (&tmp4->sin_addr, name->iov.buffers[0].iov_base,
+             name->iov.buffers[0].iov_len);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_to_ip_address (const hicn_name_t * name, ip_address_t * ip_address)
+{
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+      memcpy (&ip_address->buffer, name->buffer, IPV6_ADDR_LEN);
+      ip_address->family = AF_INET6;
+      break;
+    case HNT_IOV_V6:
+      memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base,
+             name->iov.buffers[0].iov_len);
+      ip_address->family = AF_INET6;
+      break;
+    case HNT_CONTIGUOUS_V4:
+      memcpy (&ip_address->buffer, name->buffer, IPV4_ADDR_LEN);
+      ip_address->family = AF_INET;
+      break;
+    case HNT_IOV_V4:
+      memcpy (&ip_address->buffer, name->iov.buffers[0].iov_base,
+             name->iov.buffers[0].iov_len);
+      ip_address->family = AF_INET;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_get_seq_number (const hicn_name_t * name, u32 * seq_number)
+{
+  const u8 *sequence_number = NULL;
+
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+      sequence_number = name->buffer + IPV6_ADDR_LEN;
+      break;
+    case HNT_CONTIGUOUS_V4:
+      sequence_number = name->buffer + IPV4_ADDR_LEN;
+      break;
+    case HNT_IOV_V6:
+    case HNT_IOV_V4:
+      sequence_number = name->iov.buffers[1].iov_base;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  if (sequence_number)
+    {
+      *seq_number = *(u32 *) sequence_number;
+    }
+  else
+    {
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_name_ntop (const hicn_name_t * src, char *dst, size_t len)
+{
+  int offset;
+  const char *rc;
+  void *seg_number = NULL;
+
+  switch (src->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+      rc = inet_ntop (AF_INET6, src->buffer, dst, len);
+      seg_number = (u8 *) src->buffer + IPV6_ADDR_LEN;
+      break;
+    case HNT_CONTIGUOUS_V4:
+      rc = inet_ntop (AF_INET, src->buffer, dst, len);
+      seg_number = (u8 *) src->buffer + IPV4_ADDR_LEN;
+      break;
+    case HNT_IOV_V6:
+      rc = inet_ntop (AF_INET6, src->iov.buffers[0].iov_base, dst, len);
+      seg_number = src->iov.buffers[1].iov_base;
+      break;
+    case HNT_IOV_V4:
+      rc = inet_ntop (AF_INET, src->iov.buffers[0].iov_base, dst, len);
+      seg_number = src->iov.buffers[1].iov_base;
+      break;
+    default:
+      return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+    }
+
+  if (!rc)
+    {
+      goto ERR;
+    }
+
+  offset = strlen (dst);
+  dst[offset] = '|';
+
+  sprintf (dst + offset + 1, "%lu", (unsigned long) (*(u32 *) seg_number));
+
+  return HICN_LIB_ERROR_NONE;
+
+ERR:
+  return HICN_LIB_ERROR_UNSPECIFIED;
+}
+
+int
+hicn_name_pton (const char *src, hicn_name_t * dst)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+}
+
+int
+hicn_name_get_family (const hicn_name_t * name, int *family)
+{
+  switch (name->type)
+    {
+    case HNT_CONTIGUOUS_V6:
+    case HNT_IOV_V6:
+      *family = AF_INET6;
+      break;
+    case HNT_CONTIGUOUS_V4:
+    case HNT_IOV_V4:
+      *family = AF_INET;
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+hicn_prefix_create_from_ip_address (const ip_address_t * ip_address,
+                                   hicn_prefix_t * prefix)
+{
+  switch (ip_address->family)
+    {
+    case AF_INET:
+      prefix->name.ip4.as_u32 = ip_address->as_u32[0];
+      break;
+    case AF_INET6:
+      prefix->name.ip6.as_u64[0] = ip_address->as_u64[0];
+      prefix->name.ip6.as_u64[1] = ip_address->as_u64[1];
+      break;
+    default:
+      return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
+    }
+  prefix->len = ip_address->prefix_len;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+#endif /* ! HICN_VPP_PLUGIN */
+
+/********
+ * IP
+ */
+
+inline int
+ip_address_len (const ip_address_t * ip_address)
+{
+  return (ip_address->family == AF_INET6) ? IPV6_ADDR_LEN :
+    (ip_address->family == AF_INET) ? IPV4_ADDR_LEN : 0;
+}
+
+bool
+ip_address_empty (const ip_address_t * ip_address)
+{
+  return ip_address->prefix_len == 0;
+}
+
+int
+hicn_ip_ntop (const ip_address_t * ip_address, char *dst, const size_t len)
+{
+  const char *rc;
+
+  rc = inet_ntop (ip_address->family, ip_address->buffer, dst, len);
+  if (!rc)
+    {
+      printf ("error ntop: %d %s\n", errno, strerror (errno));
+      return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+/*
+ * Parse ip addresses in presentation format, or prefixes (in bits, separated by a slash)
+ */
+int
+hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address)
+{
+  int pton_fd;
+  char *p;
+  char *eptr;
+  u32 dst_len;
+  char *addr = strdup (ip_address_str);
+
+  p = strchr (addr, '/');
+  if (!p)
+    {
+      dst_len = 0;             // until we get the ip address family
+    }
+  else
+    {
+      dst_len = strtoul (p + 1, &eptr, 10);
+      *p = 0;
+    }
+
+  ip_address->family = get_addr_family (addr);
+
+  switch (ip_address->family)
+    {
+    case AF_INET6:
+      if (dst_len > IPV6_ADDR_LEN_BITS)
+       goto ERR;
+      pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer);
+      ip_address->prefix_len = dst_len ? : IPV6_ADDR_LEN_BITS;
+      break;
+    case AF_INET:
+      if (dst_len > IPV4_ADDR_LEN_BITS)
+       goto ERR;
+      pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer);
+      ip_address->prefix_len = dst_len ? : IPV4_ADDR_LEN_BITS;
+      break;
+    default:
+      goto ERR;
+    }
+
+  //   0 = not in presentation format
+  // < 0 = other error (use perror)
+  if (pton_fd <= 0)
+    {
+      goto ERR;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+ERR:
+  free (addr);
+  return HICN_LIB_ERROR_INVALID_IP_ADDRESS;
+}
+
+int
+hicn_ip_to_sockaddr_address (const ip_address_t * ip_address,
+                            struct sockaddr *sockaddr_address)
+{
+  struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address;
+  struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address;
+
+  switch (ip_address->family)
+    {
+    case AF_INET6:
+      tmp6->sin6_family = AF_INET6;
+      tmp6->sin6_port = DUMMY_PORT;
+      tmp6->sin6_scope_id = 0;
+      memcpy (&tmp6->sin6_addr, ip_address->buffer, IPV6_ADDR_LEN);
+      break;
+    case AF_INET:
+      tmp4->sin_family = AF_INET;
+      tmp4->sin_port = DUMMY_PORT;
+      memcpy (&tmp4->sin_addr, ip_address->buffer, IPV4_ADDR_LEN);
+      break;
+    default:
+      return HICN_LIB_ERROR_UNEXPECTED;
+    }
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/name.h b/lib/src/name.h
new file mode 100755 (executable)
index 0000000..0a55fed
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file name.h
+ * @brief hICN name helpers.
+ *
+ * The purpose of the file is to offer an efficient, platform- and protocol-
+ * independent way to manipulate hICN names.
+ */
+
+#ifndef HICN_NAME_H
+#define HICN_NAME_H
+
+#include <stdbool.h>
+#include <netinet/in.h>                // struct sockadd
+
+#include "common.h"
+
+/******************************************************************************
+ * IP address helpers
+ ******************************************************************************/
+
+/* Presentation format */
+#define INET_ADDRSTRLEN 16
+#define INET6_ADDRSTRLEN 46
+//#define INET_MAX_ADDRSTRLEN INET6_ADDRSTRLEN
+
+/* Address size */
+#define bytes_to_bits(x) (x * 8)
+#define IPV6_ADDR_LEN 16       /* bytes */
+#define IPV4_ADDR_LEN 4                /* bytes */
+#define IPV6_ADDR_LEN_BITS bytes_to_bits(IPV6_ADDR_LEN)
+#define IPV4_ADDR_LEN_BITS bytes_to_bits(IPV4_ADDR_LEN)
+
+#define IP_MAX_ADDR_LEN IPV6_ADDR_LEN
+#define TCP_SEQNO_LEN 4                /* bytes */
+
+typedef struct
+{
+  union
+  {
+    u8 buffer[IP_MAX_ADDR_LEN];
+    u8 as_u8[IP_MAX_ADDR_LEN];
+    u16 as_u16[IP_MAX_ADDR_LEN >> 1];
+    u32 as_u32[IP_MAX_ADDR_LEN >> 2];
+    u64 as_u64[IP_MAX_ADDR_LEN >> 3];
+    ip4_address_t as_ip4;
+    ip6_address_t as_ip6;
+  };
+  int family;
+  unsigned short prefix_len;
+} ip_address_t;
+
+int ip_address_len (const ip_address_t * ip_address);
+bool ip_address_empty (const ip_address_t * ip_address);
+
+int hicn_ip_ntop (const ip_address_t * ip_address, char *dst,
+                 const size_t len);
+int hicn_ip_pton (const char *ip_address_str, ip_address_t * ip_address);
+int hicn_ip_to_sockaddr_address (const ip_address_t * ip_address,
+                                struct sockaddr *sockaddr_address);
+
+/******************************************************************************
+ * hICN names
+ ******************************************************************************/
+
+#define HICN_V4_PREFIX_LEN IPV4_ADDR_LEN
+#define HICN_V6_PREFIX_LEN IPV6_ADDR_LEN
+#define HICN_SEGMENT_LEN TCP_SEQNO_LEN
+#define HICN_V6_NAME_LEN (HICN_V6_PREFIX_LEN + HICN_SEGMENT_LEN)       /* 20 bytes */
+#define HICN_V4_NAME_LEN (HICN_V4_PREFIX_LEN + HICN_SEGMENT_LEN)       /*  8 bytes */
+
+/* Prefix */
+
+typedef u32 hicn_name_suffix_t;
+
+typedef struct
+{
+  ip46_address_t name;
+  u8 len;
+} hicn_prefix_t;
+
+/*
+ * Name
+ *
+ * A name is a prefix + a segment name (suffix)
+ */
+
+typedef union
+{
+  struct
+  {
+    union
+    {
+      u32 prefix;
+      u8 prefix_as_u8[4];
+      ip4_address_t prefix_as_ip4;
+    };
+    hicn_name_suffix_t suffix;
+  };
+  u8 buffer[HICN_V4_NAME_LEN];
+} hicn_v4_name_t;
+
+typedef union
+{
+  struct
+  {
+    union
+    {
+      u64 prefix[2];
+      u8 prefix_as_u8[16];
+      ip6_address_t prefix_as_ip6;
+    };
+    hicn_name_suffix_t suffix;
+  };
+  u8 buffer[HICN_V6_NAME_LEN];
+} hicn_v6_name_t;
+
+typedef struct
+{
+  u8 buffer[0];
+} hicn_v46_name_t;
+
+#ifndef HICN_VPP_PLUGIN
+#define HICN_NAME_COMPONENT_SIZE 2
+
+typedef struct
+{
+  struct iovec buffers[HICN_NAME_COMPONENT_SIZE];
+} hicn_iov_name_t;
+
+#define UNSPEC            1 << 0
+#define HNT_CONTIGUOUS    1 << 1
+#define HNT_IOV           1 << 2
+#define HNT_INET          1 << 3
+#define HNT_INET6         1 << 4
+
+typedef enum
+{
+  HNT_UNSPEC = UNSPEC,
+  HNT_CONTIGUOUS_V4 = HNT_CONTIGUOUS | HNT_INET,
+  HNT_CONTIGUOUS_V6 = HNT_CONTIGUOUS | HNT_INET6,
+  HNT_IOV_V4 = HNT_IOV | HNT_INET,
+  HNT_IOV_V6 = HNT_IOV | HNT_INET6,
+} hicn_name_type_t;
+#endif /* HICN_VPP_PLUGIN */
+
+typedef struct
+{
+#ifndef HICN_VPP_PLUGIN
+  hicn_name_type_t type;
+  u8 len;
+#endif                         /* HICN_VPP_PLUGIN */
+  union
+  {
+    hicn_v4_name_t ip4;
+    hicn_v6_name_t ip6;
+    ip46_address_t ip46;
+#ifndef HICN_VPP_PLUGIN
+    hicn_iov_name_t iov;
+    u8 buffer[0];
+#endif                         /* HICN_VPP_PLUGIN */
+  };
+} hicn_name_t;
+
+#ifndef HICN_VPP_PLUGIN
+#define _is_unspec(name)     ((name->type & UNSPEC))
+#define _is_contiguous(name) ((name->type & HNT_CONTIGUOUS) >> 1)
+#define _is_iov(name)        ((name->type & HNT_IOV) >> 2)
+#define _is_inet4(name)      ((name->type & HNT_INET) >> 3)
+#define _is_inet6(name)      ((name->type & HNT_INET6) >> 4)
+#endif /* HICN_VPP_PLUGIN */
+
+/**
+ * @brief Create an hICN name from IP address in presentation format
+ * @param [in] ip_address - IP address
+ * @param [in] id - Segment identifier
+ * @param [out] Resulting hICN name
+ * @return hICN error code
+ */
+int hicn_name_create (const char *ip_address, u32 id, hicn_name_t * name);
+
+/**
+ * @brief Create an hICN name from IP address
+ * @param [in] ip_address - IP address
+ * @param [in] id Segment - identifier
+ * @param [out] Resulting - hICN name
+ * @return hICN error code
+ */
+int hicn_name_create_from_ip_address (const ip_address_t * ip_address, u32 id,
+                                     hicn_name_t * name);
+
+/**
+ * @brief Returns the length of an hICN name
+ * @param [in] name - hICN name
+ * @return Name length
+ */
+u8 hicn_name_get_length (const hicn_name_t * name);
+
+/**
+ * @brief Compare two hICN names
+ * @param [in] name_1 - First name to compare
+ * @param [in] name_2 - Second name to compare
+ * @param [in] consider_segment - Flag indicating whether the segment part has to be
+ *   considered
+ * @return An integer less than, equal to, or greater than zero if name_1 is
+ *   found, respectively, to be lest than, to match, or be greater than name_2
+ *   based on numeric order.
+ */
+int hicn_name_compare (const hicn_name_t * name_1, const hicn_name_t * name_2,
+                      bool consider_segment);
+
+/**
+ * @brief Provides a 32-bit hash of an hICN name
+ * @param [in] name - Name to hash
+ * @param [out] hash - Resulting hash
+ * @return hICN error code
+ */
+int hicn_name_hash (const hicn_name_t * name, u32 * hash);
+
+/**
+ * @brief Test whether an hICN name is empty
+ * @param [in] name - Name to test
+ * @return 0 if the name is empty, any other value otherwise (implementation
+ *   returns 1)
+ */
+int hicn_name_empty (hicn_name_t * name);
+
+/**
+ * @brief Copy an hICN name
+ * @param [out] dst - Destination name
+ * @param [in] src - Source name to copy
+ * @return hICN error code
+ */
+int hicn_name_copy (hicn_name_t * dst, const hicn_name_t * src);
+
+/**
+ * @brief Copy an hICN name to a buffer
+ * @param [out] dst - Destination buffer
+ * @param [in] src - Source name to copy
+ * @param [in] copy_suffix - Flag indicating whether the suffix has to be
+ *   considered
+ */
+int hicn_name_copy_to_destination (u8 * dst, const hicn_name_t * src,
+                                  bool copy_suffix);
+
+/**
+ * @brief Sets the segment part of an hICN name
+ * @param [in,out] name - hICN name to modify
+ * @param [in] seq_number - Segment identifier
+ * @return hICN error code
+ */
+int hicn_name_set_seq_number (hicn_name_t * name, u32 seq_number);
+
+/**
+ * @brief Retrieves the segment part of an hICN name
+ * @param [in,out] name - hICN name
+ * @param [in] seq_number - Segment identifier
+ * @return hICN error code
+ */
+int hicn_name_get_seq_number (const hicn_name_t * name, u32 * seq_number);
+
+/**
+ * @brief Convert an hICN name to a socket address
+ * @param [in] name - Name to convert
+ * @param [out] ip_address - Resulting socket address
+ * @return hICN error code
+ */
+int hicn_name_to_sockaddr_address (const hicn_name_t * name,
+                                  struct sockaddr *ip_address);
+
+/**
+ * @brief Convert an hICN name to an IP address
+ * @param [in] name - Name to convert
+ * @param [out] ip_address - Resulting IP address
+ * @return hICN error code
+ */
+int hicn_name_to_ip_address (const hicn_name_t * name,
+                            ip_address_t * ip_address);
+
+/**
+ * @brief Convert an hICN name to presentation format
+ * @param [in] src - Name to convert
+ * @param [out] dst - Buffer to receive the name in presentation format
+ * @param [in] len - Number of bytes available in the buffer
+ * @return hICN error code
+ */
+int hicn_name_ntop (const hicn_name_t * src, char *dst, size_t len);
+
+/**
+ * @brief Convert an hICN name from presentation format
+ * @param [in] src - Name in presentation format to parse
+ * @param [out] dst - Resulting name
+ * @return hICN error code
+ */
+int hicn_name_pton (const char *src, hicn_name_t * dst);
+
+/**
+ * @brief Returns the IP address family of an hICN name
+ * @param [in] name - Name to lookup
+ * @param [out] family - Resulting IP address family (AF_INET or AF_INET6)
+ * @return hICN error code
+ */
+int hicn_name_get_family (const hicn_name_t * name, int *family);
+
+/**
+ * @brief Creates an hICN prefix from an IP address
+ * @param [in] ip_address - Input IP address
+ * @param [out] prefix - Resulting prefix
+ * @return hICN error code
+ */
+int hicn_prefix_create_from_ip_address (const ip_address_t * ip_address,
+                                       hicn_prefix_t * prefix);
+
+#endif /* HICN_NAME_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/ops.c b/lib/src/ops.c
new file mode 100755 (executable)
index 0000000..ad45a13
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file ops.c
+ * @brief Initializers for protocol-independent packet operations
+ */
+
+#include <netinet/in.h>
+#include <stdlib.h>
+#include "ops.h"
+
+#include "header.h"
+
+extern const hicn_ops_t hicn_ops_ipv4;
+extern const hicn_ops_t hicn_ops_icmp;
+extern const hicn_ops_t hicn_ops_tcp;
+extern const hicn_ops_t hicn_ops_ipv6;
+extern const hicn_ops_t hicn_ops_ah;
+
+/* Declare empty operations (terminates recursion on protocol layers) */
+DECLARE_init_packet_header (none, NONE);
+DECLARE_get_interest_locator (none, NONE);
+DECLARE_set_interest_locator (none, NONE);
+DECLARE_get_interest_name (none, NONE);
+DECLARE_set_interest_name (none, NONE);
+DECLARE_get_interest_name_suffix (none, NONE);
+DECLARE_set_interest_name_suffix (none, NONE);
+DECLARE_reset_interest_for_hash (none, NONE);
+DECLARE_get_data_locator (none, NONE);
+DECLARE_set_data_locator (none, NONE);
+DECLARE_get_data_name (none, NONE);
+DECLARE_set_data_name (none, NONE);
+DECLARE_get_data_name_suffix (none, NONE);
+DECLARE_set_data_name_suffix (none, NONE);
+DECLARE_get_data_pathlabel (none, NONE);
+DECLARE_set_data_pathlabel (none, NONE);
+DECLARE_update_data_pathlabel (none, NONE);
+DECLARE_reset_data_for_hash (none, NONE);
+DECLARE_get_lifetime (none, NONE);
+DECLARE_set_lifetime (none, NONE);
+DECLARE_update_checksums (none, NONE);
+DECLARE_verify_checksums (none, NONE);
+DECLARE_rewrite_interest (none, NONE);
+DECLARE_rewrite_data (none, NONE);
+DECLARE_get_length (none, NONE);
+DECLARE_get_header_length (none, NONE);
+DECLARE_get_current_header_length (none, NONE);
+DECLARE_get_payload_length (none, NONE);
+DECLARE_set_payload_length (none, NONE);
+DECLARE_get_signature_size (none, NONE);
+DECLARE_set_signature_size (none, NONE);
+DECLARE_set_signature_timestamp (none, NONE);
+DECLARE_get_signature_timestamp (none, NONE);
+DECLARE_set_validation_algorithm (none, NONE);
+DECLARE_get_validation_algorithm (none, NONE);
+DECLARE_set_key_id (none, NONE);
+DECLARE_get_key_id (none, NONE);
+DECLARE_HICN_OPS (none);
+
+/**
+ * @brief Virtual function table for packet operations
+ * NOTE: protocol numbers have to be kept in order
+ */
+const hicn_ops_t *const hicn_ops_vft[] = {
+  /*  0 */ [IPPROTO_IP] = &hicn_ops_ipv4,
+  /*  1 */ [IPPROTO_ICMP] = &hicn_ops_icmp,
+  /*  6 */ [IPPROTO_TCP] = &hicn_ops_tcp,
+  /* 41 */ [IPPROTO_IPV6] = &hicn_ops_ipv6,
+  /* 51 */ [IPPROTO_AH] = &hicn_ops_ah,
+  /* 58 */ [IPPROTO_ICMPV6] = &hicn_ops_icmp,
+  [IPPROTO_NONE] = &hicn_ops_none,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/ops.h b/lib/src/ops.h
new file mode 100755 (executable)
index 0000000..d56e6ae
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file base.h
+ * @brief Protocol-independent packet operations
+ */
+
+#ifndef HICN_OPS_H
+#define HICN_OPS_H
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "header.h"
+#include "name.h"
+
+/*
+ * hICN operations on packets
+ *
+ * All prototypes take an hicn_type_t parameter as their first argument, as this
+ * decides the sequence of protocols that are being used by the different
+ * operations.
+ */
+
+typedef struct hicn_ops_s
+{
+    /** Protocol name */
+  const char *name;
+
+    /**
+     * @brief Initialize the headers of the hicn packet
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the packet
+     */
+  int (*init_packet_header) (hicn_type_t type, hicn_protocol_t * h);
+
+    /**
+     * @brief Retrieves an Interest locator
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest packet
+     * @param [out] ip_address - Retrieved locator
+     * @return hICN error code
+     */
+  int (*get_interest_locator) (hicn_type_t type, const hicn_protocol_t * h,
+                              ip46_address_t * ip_address);
+
+    /**
+     * @brief Sets an Interest locator
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest packet
+     * @param [in] ip_address - Locator to set
+     * @return hICN error code
+     */
+  int (*set_interest_locator) (hicn_type_t type, hicn_protocol_t * h,
+                              const ip46_address_t * ip_address);
+
+    /**
+     * @brief Retrieves an Interest name
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest packet
+     * @param [out] name - Retrieved name
+     * @return hICN error code
+     */
+  int (*get_interest_name) (hicn_type_t type, const hicn_protocol_t * h,
+                           hicn_name_t * name);
+
+    /**
+     * @brief Sets an Interest name
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest packet
+     * @param [in] name - Name to set
+     * @return hICN error code
+     */
+  int (*set_interest_name) (hicn_type_t type, hicn_protocol_t * h,
+                           const hicn_name_t * name);
+
+    /**
+     * @brief Retrieves an Interest name suffix
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest packet
+     * @param [out] suffix - Retrieved name suffix
+     * @return hICN error code
+     */
+  int (*get_interest_name_suffix) (hicn_type_t type,
+                                  const hicn_protocol_t * h,
+                                  hicn_name_suffix_t * suffix);
+
+    /**
+     * @brief Sets an Interest name suffix
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest packet
+     * @param [in] suffix - Name suffix to set
+     * @return hICN error code
+     */
+  int (*set_interest_name_suffix) (hicn_type_t type, hicn_protocol_t * h,
+                                  const hicn_name_suffix_t * suffix);
+
+    /**
+     * @brief Clear the necessary Interest fields in order to hash it
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest packet
+     * @return hICN error code
+     */
+  int (*reset_interest_for_hash) (hicn_type_t type, hicn_protocol_t * h);
+
+    /**
+     * @brief Retrieves a Data locator
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Data packet
+     * @param [out] ip_address - Retrieved locator
+     * @return hICN error code
+     */
+  int (*get_data_locator) (hicn_type_t type, const hicn_protocol_t * h,
+                          ip46_address_t * ip_address);
+
+    /**
+     * @brief Sets a Data locator
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @param [in] ip_address - Locator to set
+     * @return hICN error code
+     */
+  int (*set_data_locator) (hicn_type_t type, hicn_protocol_t * h,
+                          const ip46_address_t * ip_address);
+
+    /**
+     * @brief Retrieves a Data name
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Data packet
+     * @param [out] name - Retrieved name
+     * @return hICN error code
+     */
+  int (*get_data_name) (hicn_type_t type, const hicn_protocol_t * h,
+                       hicn_name_t * name);
+
+    /**
+     * @brief Sets a Data name
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @param [in] name - Name to set
+     * @return hICN error code
+     */
+  int (*set_data_name) (hicn_type_t type, hicn_protocol_t * h,
+                       const hicn_name_t * name);
+
+    /**
+     * @brief Retrieves a Data name suffix
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Data packet
+     * @param [out] suffix - Retrieved name suffix
+     * @return hICN error code
+     */
+  int (*get_data_name_suffix) (hicn_type_t type, const hicn_protocol_t * h,
+                              hicn_name_suffix_t * suffix);
+
+    /**
+     * @brief Sets a Data name suffix
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @param [in] suffix - Name suffix to set
+     * @return hICN error code
+     */
+  int (*set_data_name_suffix) (hicn_type_t type, hicn_protocol_t * h,
+                              const hicn_name_suffix_t * suffix);
+
+    /**
+     * @brief Retrieves a Data pathlabel
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Data packet
+     * @param [out] pathlabel - Retrieved pathlabel
+     * @return hICN error code
+     */
+  int (*get_data_pathlabel) (hicn_type_t type, const hicn_protocol_t * h,
+                            u32 * pathlabel);
+
+    /**
+     * @brief Sets a Data pathlabel
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @param [in] pathlabel - Pathlabel to set
+     * @return hICN error code
+     */
+  int (*set_data_pathlabel) (hicn_type_t type, hicn_protocol_t * h,
+                            const u32 pathlabel);
+
+    /**
+     * @brief Update a Data pathlabel with a new face identifier
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @param [in] pathlabel - Face identifier used to update pathlabel
+     * @return hICN error code
+     */
+  int (*update_data_pathlabel) (hicn_type_t type, hicn_protocol_t * h,
+                               const hicn_faceid_t face_id);
+
+    /**
+     * @brief Clear the necessary Data fields in order to hash it
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Data packet
+     * @return hICN error code
+     */
+  int (*reset_data_for_hash) (hicn_type_t type, hicn_protocol_t * h);
+
+    /**
+     * @brief Retrieves an Interest or Data lifetime
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest or Data packet
+     * @param [out] pathlabel - Retrieved lifetime
+     * @return hICN error code
+     */
+  int (*get_lifetime) (hicn_type_t type, const hicn_protocol_t * h,
+                      hicn_lifetime_t * lifetime);
+
+    /**
+     * @brief Sets an Interest or Data lifetime
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [in] pathlabel - Lifetime to set
+     * @return hICN error code
+     */
+  int (*set_lifetime) (hicn_type_t type, hicn_protocol_t * h,
+                      const hicn_lifetime_t lifetime);
+
+    /**
+     * @brief Update all checksums in packet headers
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the packet
+     * @param [in] partial_csum - Partial checksum (set to 0, used internally to
+     *   carry intermediate values from IP pseudo-header)
+     * @param [in] payload_length - Payload length (can be set to 0, retrieved
+     *   and used internally to carry payload length across protocol headers)
+     * @return hICN error code
+     */
+  int (*update_checksums) (hicn_type_t type, hicn_protocol_t * h,
+                          u16 partial_csum, size_t payload_length);
+
+    /**
+     * @brief Validate all checksums in packet headers
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the packet
+     * @param [in] partial_csum - Partial checksum (set to 0, used internally to
+     *   carry intermediate values from IP pseudo-header)
+     * @param [in] payload_length - Payload length (can be set to 0, retrieved
+     *   and used internally to carry payload length across protocol headers)
+     * @return hICN error code
+     */
+  int (*verify_checksums) (hicn_type_t type, hicn_protocol_t * h,
+                          u16 partial_csum, size_t payload_length);
+
+    /**
+     * @brief Rewrite an Interest packet header (locator)
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest packet
+     * @param [in] addr_new - New locator
+     * @param [in] addr_old - Old locator (set to NULL, used internally to
+     *   compute incremental checksums)
+     * @return hICN error code
+     */
+  int (*rewrite_interest) (hicn_type_t type, hicn_protocol_t * h,
+                          const ip46_address_t * addr_new,
+                          ip46_address_t * addr_old);
+
+    /**
+     * @brief Rewrite a Data packet header (locator + pathlabel)
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Data packet
+     * @param [in] addr_new - New locator
+     * @param [in] addr_old - Old locator (set to NULL, used internally to
+     *   compute incremental checksums)
+     * @param [in] face_id - Face identifier used to update pathlabel
+     * @return hICN error code
+     */
+  int (*rewrite_data) (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * addr_new,
+                      ip46_address_t * addr_old,
+                      const hicn_faceid_t face_id);
+
+    /**
+     * @brief Return the packet length
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the packet
+     * @parma [out] length - Returned packet length
+     * @return hICN error code
+     */
+  int (*get_length) (hicn_type_t type, const hicn_protocol_t * h,
+                    size_t * length);
+
+    /**
+     * @brief Return the current packet header length
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the packet
+     * @parma [out] header_length - Returned packet current header length
+     * @return hICN error code
+     */
+  int (*get_current_header_length) (hicn_type_t type,
+                                   const hicn_protocol_t * h,
+                                   size_t * header_length);
+
+    /**
+     * @brief Return the packet header length
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the packet
+     * @parma [out] header_length - Returned packet header length
+     * @return hICN error code
+     */
+  int (*get_header_length) (hicn_type_t type, const hicn_protocol_t * h,
+                           size_t * header_length);
+
+    /**
+     * @brief Return the packet payload length
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the packet
+     * @parma [out] payload_length - Returned packet payload length
+     * @return hICN error code
+     */
+  int (*get_payload_length) (hicn_type_t type, const hicn_protocol_t * h,
+                            size_t * payload_length);
+
+    /**
+     * @brief Sets the packet paylaod length
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the packet
+     * @parma [out] payload_length - Payload length to set
+     * @return hICN error code
+     */
+  int (*set_payload_length) (hicn_type_t type, hicn_protocol_t * h,
+                            size_t payload_length);
+
+    /**
+     * @brief Retrieves an Interest or Data signature size
+     * @param [in] type - hICN packet type
+     * @param [in] h - Buffer holding the Interest or Data packet
+     * @param [out] signature_size - Retrieved signature size
+     * @return hICN error code
+     */
+  int (*get_signature_size) (hicn_type_t type, const hicn_protocol_t * h,
+                            size_t * signature_size);
+
+    /**
+     * @brief Sets an Interest or Data signature size
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [in] signature_size - Signature size to set
+     * @return hICN error code
+     */
+  int (*set_signature_size) (hicn_type_t type, hicn_protocol_t * h,
+                            size_t signature_size);
+
+    /**
+     * @brief Sets the signature timestamp
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [in] signature_timestamp - Signature timestamp to set
+     * @return hICN error code
+     */
+  int (*set_signature_timestamp) (hicn_type_t type, hicn_protocol_t * h,
+                 uint64_t signature_timestamp);
+
+    /**
+     * @brief Gets the signature timestamp
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [out] signature_timestamp - Retrieved signature timestamp
+     * @return hICN error code
+     */
+  int (*get_signature_timestamp) (hicn_type_t type, const hicn_protocol_t * h,
+                 uint64_t *signature_timestamp);
+
+    /**
+     * @brief Sets the signature validation algorithm
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [in] validation_algorithm - Validation algorithm enumeration
+     * @return hICN error code
+     */
+  int (*set_validation_algorithm) (hicn_type_t type, hicn_protocol_t * h,
+                 uint8_t validation_algorithm);
+
+    /**
+     * @brief Gets the signature validation algorithm
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [out] validation_algorithm - Retrieved validation_algorithm
+     * @return hICN error code
+     */
+  int (*get_validation_algorithm) (hicn_type_t type, const hicn_protocol_t * h,
+                 uint8_t *validation_algorithm);
+
+    /**
+     * @brief Sets the key id
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [in] key_id - Key id first byte address
+     * @return hICN error code
+     */
+  int (*set_key_id) (hicn_type_t type, hicn_protocol_t * h,
+                 uint8_t *key_id);
+
+    /**
+     * @brief Gets the key id
+     * @param [in] type - hICN packet type
+     * @param [in,out] h - Buffer holding the Interest or Data packet
+     * @param [out] key_id - Retrieved key id first byte address
+     * @return hICN error code
+     */
+  int (*get_key_id) (hicn_type_t type, hicn_protocol_t * h,
+                 uint8_t **key_id, uint8_t *key_id_size);
+
+} hicn_ops_t;
+
+#define DECLARE_HICN_OPS(protocol)                                              \
+    const hicn_ops_t hicn_ops_ ## protocol = {                                  \
+        .init_packet_header       = protocol ## _init_packet_header,            \
+        .get_interest_locator     = protocol ## _get_interest_locator,          \
+        .set_interest_locator     = protocol ## _set_interest_locator,          \
+        .get_interest_name        = protocol ## _get_interest_name,             \
+        .set_interest_name        = protocol ## _set_interest_name,             \
+        .get_interest_name_suffix = protocol ## _get_interest_name_suffix,      \
+        .set_interest_name_suffix = protocol ## _set_interest_name_suffix,      \
+        .reset_interest_for_hash  = protocol ## _reset_interest_for_hash,       \
+        .get_data_locator         = protocol ## _get_data_locator,              \
+        .set_data_locator         = protocol ## _set_data_locator,              \
+        .get_data_name            = protocol ## _get_data_name,                 \
+        .set_data_name            = protocol ## _set_data_name,                 \
+        .get_data_name_suffix     = protocol ## _get_data_name_suffix,          \
+        .set_data_name_suffix     = protocol ## _set_data_name_suffix,          \
+        .get_data_pathlabel       = protocol ## _get_data_pathlabel,            \
+        .set_data_pathlabel       = protocol ## _set_data_pathlabel,            \
+        .update_data_pathlabel    = protocol ## _update_data_pathlabel,         \
+        .reset_data_for_hash      = protocol ## _reset_data_for_hash,           \
+        .get_lifetime             = protocol ## _get_lifetime,                  \
+        .set_lifetime             = protocol ## _set_lifetime,                  \
+        .update_checksums         = protocol ## _update_checksums,              \
+        .verify_checksums         = protocol ## _verify_checksums,              \
+        .rewrite_interest         = protocol ## _rewrite_interest,              \
+        .rewrite_data             = protocol ## _rewrite_data,                  \
+        .get_length               = protocol ## _get_length,                    \
+        .get_current_header_length= protocol ## _get_current_header_length,     \
+        .get_header_length        = protocol ## _get_header_length,             \
+        .get_payload_length       = protocol ## _get_payload_length,            \
+        .set_payload_length       = protocol ## _set_payload_length,            \
+        .get_signature_size       = protocol ## _get_signature_size,            \
+        .set_signature_size       = protocol ## _set_signature_size,            \
+        .set_signature_timestamp  = protocol ## _set_signature_timestamp,       \
+        .get_signature_timestamp  = protocol ## _get_signature_timestamp,       \
+        .set_validation_algorithm = protocol ## _set_validation_algorithm,      \
+        .get_validation_algorithm = protocol ## _get_validation_algorithm,      \
+        .set_key_id               = protocol ## _set_key_id,                    \
+        .get_key_id               = protocol ## _get_key_id,                    \
+    }
+
+/**
+ * @brief Protocol-independent packet operations VFT
+ * NOTE: The following declarations should be kept in order
+ */
+extern const hicn_ops_t *const hicn_ops_vft[];
+
+/*
+ * Helpers for writing recursive protocol operations on packet headers
+ *
+ * NOTE : we cannot use a shift operation as IPPROTO_NONE != 0 (and 0 is IPv4...)
+ */
+always_inline hicn_type_t
+TYPE_POP (hicn_type_t type)
+{
+  return (hicn_type_t)
+  {
+    {
+    .l1 = type.l2,.l2 = type.l3,.l3 = type.l4,.l4 = IPPROTO_NONE,}
+  };
+}
+
+always_inline hicn_protocol_t *
+PAYLOAD (hicn_type_t type, const hicn_protocol_t * h)
+{
+  size_t header_length;
+  int rc = hicn_ops_vft[type.l1]->get_current_header_length (type, h,
+                                                            &header_length);
+  if (rc < 0)
+    return NULL;
+  return (hicn_protocol_t *) ((u8 *) h + header_length);
+}
+
+#define CHILD_OPS(f, type, h, ...) (hicn_ops_vft[type.l2]->f(TYPE_POP(type), PAYLOAD(type, h), ## __VA_ARGS__))
+
+/** Shortcuts to entry points in VFT */
+#define HICN_OPS4 hicn_ops_vft[IPPROTO_IP]
+#define HICN_OPS6 hicn_ops_vft[IPPROTO_IPV6]
+
+/* Helpers for simple declarations */
+
+#define DECLARE_init_packet_header(protocol, error) \
+    int protocol ## _init_packet_header(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_interest_locator(protocol, error) \
+    int protocol ## _get_interest_locator(hicn_type_t type, const hicn_protocol_t * h, ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_interest_locator(protocol, error) \
+    int protocol ## _set_interest_locator(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_interest_name(protocol, error) \
+    int protocol ## _get_interest_name(hicn_type_t type, const hicn_protocol_t * h, hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_interest_name(protocol, error) \
+    int protocol ## _set_interest_name(hicn_type_t type, hicn_protocol_t * h, const hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_interest_name_suffix(protocol, error) \
+    int protocol ## _get_interest_name_suffix(hicn_type_t type, const hicn_protocol_t * h, hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_interest_name_suffix(protocol, error) \
+    int protocol ## _set_interest_name_suffix(hicn_type_t type, hicn_protocol_t * h, const hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_reset_interest_for_hash(protocol, error) \
+    int protocol ## _reset_interest_for_hash(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_data_locator(protocol, error) \
+    int protocol ## _get_data_locator(hicn_type_t type, const hicn_protocol_t * h, ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_data_locator(protocol, error) \
+    int protocol ## _set_data_locator(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * ip_address) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_data_name(protocol, error) \
+    int protocol ## _get_data_name(hicn_type_t type, const hicn_protocol_t * h, hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_data_name(protocol, error) \
+    int protocol ## _set_data_name(hicn_type_t type, hicn_protocol_t * h, const hicn_name_t * name) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_data_name_suffix(protocol, error) \
+    int protocol ## _get_data_name_suffix(hicn_type_t type, const hicn_protocol_t * h, hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_data_name_suffix(protocol, error) \
+    int protocol ## _set_data_name_suffix(hicn_type_t type, hicn_protocol_t * h, const hicn_name_suffix_t * suffix) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_data_pathlabel(protocol, error) \
+    int protocol ## _get_data_pathlabel(hicn_type_t type, const hicn_protocol_t * h, u32 * pathlabel) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_data_pathlabel(protocol, error) \
+    int protocol ## _set_data_pathlabel(hicn_type_t type, hicn_protocol_t * h, const u32 pathlabel) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_update_data_pathlabel(protocol, error) \
+    int protocol ## _update_data_pathlabel(hicn_type_t type, hicn_protocol_t * h, const hicn_faceid_t face_id) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_reset_data_for_hash(protocol, error) \
+    int protocol ## _reset_data_for_hash(hicn_type_t type, hicn_protocol_t * h) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_lifetime(protocol, error) \
+    int protocol ## _get_lifetime(hicn_type_t type, const hicn_protocol_t * h, hicn_lifetime_t * lifetime) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_lifetime(protocol, error) \
+    int protocol ## _set_lifetime(hicn_type_t type, hicn_protocol_t * h, const hicn_lifetime_t lifetime) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_update_checksums(protocol, error) \
+    int protocol ## _update_checksums(hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_verify_checksums(protocol, error) \
+    int protocol ## _verify_checksums(hicn_type_t type, hicn_protocol_t * h, u16 partial_csum, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_rewrite_interest(protocol, error) \
+    int protocol ## _rewrite_interest(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * addr_new, ip46_address_t * addr_old) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_rewrite_data(protocol, error) \
+    int protocol ## _rewrite_data(hicn_type_t type, hicn_protocol_t * h, const ip46_address_t * addr_new, ip46_address_t * addr_old, const hicn_faceid_t face_id) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_length(protocol, error) \
+    int protocol ## _get_length(hicn_type_t type, const hicn_protocol_t * h, size_t * length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_current_header_length(protocol, error) \
+    int protocol ## _get_current_header_length(hicn_type_t type, const hicn_protocol_t * h, size_t * header_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_header_length(protocol, error) \
+    int protocol ## _get_header_length(hicn_type_t type, const hicn_protocol_t * h, size_t * header_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_payload_length(protocol, error) \
+    int protocol ## _get_payload_length(hicn_type_t type, const hicn_protocol_t * h, size_t * payload_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_payload_length(protocol, error) \
+    int protocol ## _set_payload_length(hicn_type_t type, hicn_protocol_t * h, size_t payload_length) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_signature_size(protocol, error) \
+    int protocol ## _get_signature_size(hicn_type_t type, const hicn_protocol_t * h, size_t * signature_size) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_signature_size(protocol, error) \
+    int protocol ## _set_signature_size(hicn_type_t type, hicn_protocol_t * h, size_t signature_size) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_signature_timestamp(protocol, error) \
+    int protocol ## _set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h, uint64_t signature_timestamp) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_signature_timestamp(protocol, error) \
+    int protocol ## _get_signature_timestamp(hicn_type_t type, const hicn_protocol_t * h, uint64_t * signature_timestamp) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_validation_algorithm(protocol, error) \
+    int protocol ## _set_validation_algorithm(hicn_type_t type, hicn_protocol_t * h, uint8_t validation_algorithm) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_validation_algorithm(protocol, error) \
+    int protocol ## _get_validation_algorithm(hicn_type_t type, const hicn_protocol_t * h, uint8_t * validation_algorithm) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_set_key_id(protocol, error) \
+    int protocol ## _set_key_id(hicn_type_t type, hicn_protocol_t * h, uint8_t * key_id) { return HICN_LIB_ERROR_ ## error ; }
+
+#define DECLARE_get_key_id(protocol, error) \
+    int protocol ## _get_key_id(hicn_type_t type, hicn_protocol_t * h, uint8_t ** key_id, uint8_t *key_id_size) { return HICN_LIB_ERROR_ ## error ; }
+
+#endif /* HICN_OPS_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol.h b/lib/src/protocol.h
new file mode 100755 (executable)
index 0000000..a97cc99
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol.h
+ * @brief Protocol header definitions
+ */
+#ifndef HICN_PROTOCOL_H
+#define HICN_PROTOCOL_H
+
+#include "protocol/ah.h"
+#include "protocol/ipv4.h"
+#include "protocol/ipv6.h"
+#include "protocol/icmp.h"
+#include "protocol/icmprd.h"
+#include "protocol/tcp.h"
+#include "protocol/udp.h"
+
+typedef union
+{
+  _ipv4_header_t ipv4;
+  _ipv6_header_t ipv6;
+  _tcp_header_t tcp;
+  _udp_header_t udp;
+  _icmp_header_t icmp;
+  _icmprd_header_t icmprd;
+  _ah_header_t ah;
+  void *bytes;
+} hicn_protocol_t;
+
+#endif /* HICN_PROTOCOL_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ah.c b/lib/src/protocol/ah.c
new file mode 100755 (executable)
index 0000000..f9ddf77
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol/ah.c
+ * @brief hICN operations for AH header
+ */
+
+#include <string.h>            // memcpy
+#include "../common.h"
+#include "../error.h"
+#include "../header.h"
+#include "../ops.h"
+#include "ah.h"
+
+DECLARE_get_interest_locator (ah, UNEXPECTED);
+DECLARE_set_interest_locator (ah, UNEXPECTED);
+DECLARE_get_interest_name (ah, UNEXPECTED);
+DECLARE_set_interest_name (ah, UNEXPECTED);
+DECLARE_get_interest_name_suffix (ah, UNEXPECTED);
+DECLARE_set_interest_name_suffix (ah, UNEXPECTED);
+DECLARE_get_data_locator (ah, UNEXPECTED);
+DECLARE_set_data_locator (ah, UNEXPECTED);
+DECLARE_get_data_name (ah, UNEXPECTED);
+DECLARE_set_data_name (ah, UNEXPECTED);
+DECLARE_get_data_name_suffix (ah, UNEXPECTED);
+DECLARE_set_data_name_suffix (ah, UNEXPECTED);
+DECLARE_get_data_pathlabel (ah, UNEXPECTED);
+DECLARE_set_data_pathlabel (ah, UNEXPECTED);
+DECLARE_update_data_pathlabel (ah, UNEXPECTED);
+DECLARE_get_lifetime (ah, UNEXPECTED);
+DECLARE_set_lifetime (ah, UNEXPECTED);
+DECLARE_get_payload_length (ah, UNEXPECTED);
+DECLARE_set_payload_length (ah, UNEXPECTED);
+
+int
+ah_init_packet_header (hicn_type_t type, hicn_protocol_t * h)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+}
+
+int
+ah_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  size_t signature_size;
+  int rc =
+    hicn_ops_vft[type.l1]->get_signature_size (type, h, &signature_size);
+  if (rc < 0)
+    return rc;
+  memset (&(h->ah.validationPayload), 0, signature_size);
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+int
+ah_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  size_t signature_size;
+  int rc =
+    hicn_ops_vft[type.l1]->get_signature_size (type, h, &signature_size);
+  if (rc < 0)
+    return rc;
+  memset (&(h->ah.validationPayload), 0, signature_size);
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+int
+ah_update_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum,
+                    size_t payload_length)
+{
+  /* Nothing to do as there is no checksum in AH */
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_verify_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum,
+                    size_t payload_length)
+{
+  /* Nothing to do as there is no checksum in AH */
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_rewrite_interest (hicn_type_t type, hicn_protocol_t * h,
+                    const ip46_address_t * addr_new,
+                    ip46_address_t * addr_old)
+{
+  /* Nothing to do on signature */
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_rewrite_data (hicn_type_t type, hicn_protocol_t * h,
+                const ip46_address_t * addr_new, ip46_address_t * addr_old,
+                const hicn_faceid_t face_id)
+{
+  /* Nothing to do on signature */
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_length (hicn_type_t type, const hicn_protocol_t * h, size_t * length)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+}
+
+int
+ah_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                             size_t * header_length)
+{
+  *header_length = AH_HDRLEN + (h->ah.payloadlen << 2);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                     size_t * header_length)
+{
+  size_t child_header_length = 0;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  *header_length = AH_HDRLEN + (h->ah.payloadlen << 2) + child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_signature_size (hicn_type_t type, const hicn_protocol_t * h,
+                      size_t * signature_size)
+{
+  *signature_size = h->ah.payloadlen << 2;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_set_signature_size (hicn_type_t type, hicn_protocol_t * h,
+                      const size_t signature_size)
+{
+  h->ah.payloadlen = signature_size >> 2;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h,
+       uint64_t signature_timestamp)
+{
+  h->ah.timestamp_as_u64 = signature_timestamp;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h,
+       uint64_t * signature_timestamp)
+{
+  *signature_timestamp = h->ah.timestamp_as_u64;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t validation_algorithm)
+{
+  h->ah.validationAlgorithm = validation_algorithm;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h,
+       uint8_t * validation_algorithm)
+{
+  *validation_algorithm = h->ah.validationAlgorithm;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_set_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t *key_id)
+{
+  memcpy(h->ah.keyId, key_id, sizeof(h->ah.keyId));
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ah_get_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t **key_id, uint8_t *key_id_size)
+{
+  *key_id = h->ah.keyId;
+  *key_id_size = sizeof(h->ah.keyId);
+  return HICN_LIB_ERROR_NONE;
+}
+
+DECLARE_HICN_OPS (ah);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ah.h b/lib/src/protocol/ah.h
new file mode 100755 (executable)
index 0000000..0b41711
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol/ah.h
+ * @brief AH packet header
+ */
+#ifndef HICN_PROTOCOL_AH_H
+#define HICN_PROTOCOL_AH_H
+
+/*
+ * The TCP PSH flag is set to indicate TCP payload in fact contains a AH header
+ * with signature information for the packet
+ */
+#define AH_FLAG 0x10
+
+typedef struct
+{
+  u8 nh;                       // (to match with reserved in IPSEC AH)
+  u8 payloadlen;               // Len of signature/HMAC in 4-bytes words
+  union
+  {
+    u16 reserved;
+    struct
+    {
+      u8 validationAlgorithm;  // As defined in parc_SignerAlgorithm.h
+      u8 unused;               // Unused (to match with reserved in IPSEC AH)
+    };
+  };
+  union
+  {
+    struct
+    {
+      u32 spi;
+      u32 seq;
+    };
+    union
+    {
+      u8 timestamp_as_u8[8];
+      u64 timestamp_as_u64;
+    }; // Unix timestamp indicating when the signature has been calculated
+
+  };
+  // ICV would follow
+  u8 keyId[32];                        // Hash of the pub key
+  /* 44 B + validationPayload */
+  u8 validationPayload[0];     // Holds the signature
+} _ah_header_t;
+
+#define AH_HDRLEN sizeof(_ah_header_t)
+
+#endif /* HICN_PROTOCOL_AH_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/icmp.c b/lib/src/protocol/icmp.c
new file mode 100755 (executable)
index 0000000..44b646f
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2017-2019 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 <string.h>
+#include "icmp.h"
+
+#include "../error.h"
+#include "../ops.h"
+
+DECLARE_get_interest_locator (icmp, UNEXPECTED)
+DECLARE_set_interest_locator (icmp, UNEXPECTED)
+DECLARE_get_interest_name (icmp, UNEXPECTED)
+DECLARE_set_interest_name (icmp, UNEXPECTED)
+DECLARE_get_interest_name_suffix (icmp, UNEXPECTED)
+DECLARE_set_interest_name_suffix (icmp, UNEXPECTED)
+DECLARE_get_data_locator (icmp, UNEXPECTED)
+DECLARE_set_data_locator (icmp, UNEXPECTED)
+DECLARE_get_data_name (icmp, UNEXPECTED)
+DECLARE_set_data_name (icmp, UNEXPECTED)
+DECLARE_get_data_name_suffix (icmp, UNEXPECTED)
+DECLARE_set_data_name_suffix (icmp, UNEXPECTED)
+DECLARE_get_data_pathlabel (icmp, UNEXPECTED)
+DECLARE_set_data_pathlabel (icmp, UNEXPECTED)
+DECLARE_update_data_pathlabel (icmp, UNEXPECTED)
+DECLARE_get_lifetime (icmp, UNEXPECTED)
+DECLARE_set_lifetime (icmp, UNEXPECTED)
+DECLARE_get_length (icmp, UNEXPECTED)
+DECLARE_get_payload_length (icmp, UNEXPECTED)
+DECLARE_set_payload_length (icmp, UNEXPECTED)
+     int icmp_init_packet_header (hicn_type_t type, hicn_protocol_t * h)
+{
+  h->icmp = (_icmp_header_t)
+  {
+  .type = 0,.code = 0,.csum = 0,};
+
+  return HICN_LIB_ERROR_NONE;  // CHILD_OPS(init_packet_header, type, h->icmp);
+}
+
+int
+icmp_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  h->icmp.csum = 0;
+
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+int
+icmp_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  h->icmp.csum = 0;
+
+  return CHILD_OPS (reset_data_for_hash, type, h);
+}
+
+int
+icmp_update_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+//    h->icmp.csum = 0;
+//    h->icmp.csum = csum(h->bytes, TCP_HDRLEN + payload_length, ~partial_csum);
+//
+//    return CHILD_OPS(update_checksums, type, h->icmp, 0, payload_length);
+}
+
+int
+icmp_verify_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+//    if (csum(h->bytes, TCP_HDRLEN + payload_length, ~partial_csum) != 0)
+//        return HICN_LIB_ERROR_CORRUPTED_PACKET;
+//    return CHILD_OPS(verify_checksums, type, h->icmp, 0, payload_length);
+}
+
+int
+icmp_rewrite_interest (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * addr_new,
+                      ip46_address_t * addr_old)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+//    u16 *icmp_checksum = &(h->icmp.csum);
+//
+//    /*
+//     * Padding fields are set to zero so we can apply checksum on the
+//     * whole struct by interpreting it as IPv6 in all cases
+//     *
+//     * v4 code would be:
+//     * csum = ip_csum_sub_even (*icmp_checksum, h->ipv4.saddr.as_u32);
+//     * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32);
+//     */
+//    u16 csum = ip_csum_sub_even (*icmp_checksum, h->ipv6.saddr.as_u64[0]);
+//    csum = ip_csum_sub_even (csum, h->ipv6.saddr.as_u64[1]);
+//    csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[0]);
+//    csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[1]);
+//
+//    *icmp_checksum = ip_csum_fold (csum);
+//
+//    return HICN_LIB_ERROR_NONE;
+}
+
+int
+icmp_rewrite_data (hicn_type_t type, hicn_protocol_t * h,
+                  const ip46_address_t * addr_new, ip46_address_t * addr_old,
+                  const hicn_faceid_t face_id)
+{
+  return HICN_LIB_ERROR_NOT_IMPLEMENTED;
+//    u16 *icmp_checksum = &(h->icmp.csum);
+//
+//    /*
+//     * Padding fields are set to zero so we can apply checksum on the
+//     * whole struct by interpreting it as IPv6 in all cases
+//     *
+//     * v4 code would be:
+//     * csum = ip_csum_sub_even (*icmp_checksum, h->ipv4.saddr.as_u32);
+//     * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32);
+//     */
+//    u16 csum = ip_csum_sub_even (*icmp_checksum, addr_old->ip6.as_u64[0]);
+//    csum = ip_csum_sub_even (*icmp_checksum, addr_old->ip6.as_u64[1]);
+//    csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[0]);
+//    csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[1]);
+//
+//    csum = ip_csum_sub_even (csum, h->icmp.pathlabel);
+//    icmp_update_data_pathlabel(type, h, face_id);
+//    csum = ip_csum_add_even (csum, h->icmp.pathlabel);
+//
+//    *icmp_checksum = ip_csum_fold (csum);
+//
+//    return HICN_LIB_ERROR_NONE;
+}
+
+int
+icmp_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                               size_t * header_length)
+{
+  *header_length = ICMP_HDRLEN;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+icmp_get_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                       size_t * header_length)
+{
+  size_t child_header_length = 0;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+
+  *header_length = ICMP_HDRLEN + child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+icmp_get_signature_size (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * signature_size)
+{
+  return CHILD_OPS (get_signature_size, type, h, signature_size);
+}
+
+int
+icmp_set_signature_size (hicn_type_t type, hicn_protocol_t * h,
+                        size_t signature_size)
+{
+  return CHILD_OPS (set_signature_size, type, h, signature_size);
+}
+
+int
+icmp_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h,
+       uint64_t signature_timestamp)
+{
+  return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+icmp_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h,
+       uint64_t * signature_timestamp)
+{
+  return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+icmp_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t validation_algorithm)
+{
+  return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+icmp_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h,
+       uint8_t * validation_algorithm)
+{
+  return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+icmp_set_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t *key_id)
+{
+  return CHILD_OPS (set_key_id, type, h, key_id);
+}
+
+int
+icmp_get_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t **key_id, uint8_t *key_id_size)
+{
+  return CHILD_OPS (get_key_id, type, h, key_id, key_id_size);
+}
+
+DECLARE_HICN_OPS (icmp);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/icmp.h b/lib/src/protocol/icmp.h
new file mode 100755 (executable)
index 0000000..5a84995
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol/icmp.h
+ * @brief ICMP packet header
+ */
+#ifndef HICN_PROTOCOL_ICMP_H
+#define HICN_PROTOCOL_ICMP_H
+
+#include "../common.h"
+
+typedef struct
+{
+  u8 type;
+  u8 code;
+  u16 csum;
+} _icmp_header_t;
+
+typedef struct
+{
+  u8 type;
+  u8 code;
+  u16 csum;
+  union
+  {
+    struct
+    {
+      u16 id;
+      u16 sequence;
+    } echo;                    /* echo datagram */
+    u32 gateway;               /* gateway address */
+    struct
+    {
+      u16 _unused;
+      u16 mtu;
+    } frag;                    /* path mtu discovery */
+    struct
+    {
+      u16 expected_lbl;
+      u16 received_lbl;
+    } wldr_notification_lbl;
+  };
+} _icmp_wldr_header_t;
+
+#define ICMP_HDRLEN sizeof(_icmp_header_t)
+
+#endif /* HICN_PROTOCOL_ICMP_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/icmprd.h b/lib/src/protocol/icmprd.h
new file mode 100755 (executable)
index 0000000..c2f27d6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol/icmp-rd.c
+ * @brief hICN operations for ICMP Redirect header
+ */
+#ifndef HICN_PROTOCOL_ICMPRD_H
+#define HICN_PROTOCOL_ICMPRD_H
+
+#include "../common.h"
+
+typedef struct __attribute__ ((__packed__))
+{
+  ip4_address_t ip;
+  _ipv4_header_t iph;
+  u8 data[64];
+} _icmprd4_header_t;
+
+typedef struct __attribute__ ((__packed__))
+{
+  u32 res;
+  ip6_address_t tgt;
+  ip6_address_t dst;
+} _icmprd_header_t;
+
+#endif /* HICN_PROTOCOL_ICMPRD_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ipv4.c b/lib/src/protocol/ipv4.c
new file mode 100755 (executable)
index 0000000..7c6af12
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/**
+ * @file protocol/ipv4.c
+ * @brief hICN operations for IPv4 header
+ *
+ * NOTE: IPv4 options (affecting the header size) are currently not supported.
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../error.h"
+#include "../ops.h"
+#include "../common.h"
+#include "../header.h"
+
+#include "ipv4.h"
+
+int ipv4_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
+                            size_t * payload_length);
+
+int
+ipv4_init_packet_header (hicn_type_t type, hicn_protocol_t * h)
+{
+  size_t total_header_length;
+  int rc =
+    hicn_ops_vft[type.l1]->get_header_length (type, h, &total_header_length);
+  if (rc < 0)
+    return rc;
+
+  h->ipv4 = (_ipv4_header_t)
+  {
+  .version_ihl =
+      (IPV4_DEFAULT_VERSION << 4) | (0x0f & IPV4_DEFAULT_IHL),.tos =
+      IPV4_DEFAULT_TOS,.len = htons ((u16) total_header_length),.id =
+      htons (IPV4_DEFAULT_ID),.frag_off =
+      htons (IPV4_DEFAULT_FRAG_OFF),.ttl = HICN_DEFAULT_TTL,.protocol =
+      type.l2,.csum = 0,.saddr.as_u32 = 0,.daddr.as_u32 = 0,};
+
+  return CHILD_OPS (init_packet_header, type, h);
+}
+
+int
+ipv4_get_interest_locator (hicn_type_t type, const hicn_protocol_t * h,
+                          ip46_address_t * ip_address)
+{
+  ip_address->ip4 = h->ipv4.saddr;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_set_interest_locator (hicn_type_t type, hicn_protocol_t * h,
+                          const ip46_address_t * ip_address)
+{
+  h->ipv4.saddr = ip_address->ip4;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_interest_name (hicn_type_t type, const hicn_protocol_t * h,
+                       hicn_name_t * name)
+{
+  name->ip4.prefix_as_ip4 = h->ipv4.daddr;
+#ifndef HICN_VPP_PLUGIN
+  name->type = HNT_CONTIGUOUS_V4;
+  name->len = HICN_V4_NAME_LEN;
+#endif /* HICN_VPP_PLUGIN */
+  return CHILD_OPS (get_interest_name_suffix, type, h, &(name->ip4.suffix));
+}
+
+int
+ipv4_set_interest_name (hicn_type_t type, hicn_protocol_t * h,
+                       const hicn_name_t * name)
+{
+  h->ipv4.daddr = name->ip4.prefix_as_ip4;
+  return CHILD_OPS (set_interest_name_suffix, type, h, &(name->ip4.suffix));
+}
+
+int
+ipv4_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                              hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (set_interest_name_suffix, type, h, suffix);
+}
+
+int
+ipv4_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                              const hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (set_interest_name_suffix, type, h, suffix);
+}
+
+int
+ipv4_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  /* Sets everything to 0 up to IP destination address */
+  memset (&(h->ipv4), 0, 16);
+
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+int
+ipv4_get_data_locator (hicn_type_t type, const hicn_protocol_t * h,
+                      ip46_address_t * ip_address)
+{
+  ip_address->ip4 = h->ipv4.daddr;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_set_data_locator (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * ip_address)
+{
+  h->ipv4.daddr = ip_address->ip4;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_data_name (hicn_type_t type, const hicn_protocol_t * h,
+                   hicn_name_t * name)
+{
+  name->ip4.prefix_as_ip4 = h->ipv4.saddr;
+#ifndef HICN_VPP_PLUGIN
+  name->type = HNT_CONTIGUOUS_V4;
+  name->len = HICN_V4_NAME_LEN;
+#endif /* HICN_VPP_PLUGIN */
+  return CHILD_OPS (get_data_name_suffix, type, h, &(name->ip4.suffix));
+}
+
+int
+ipv4_set_data_name (hicn_type_t type, hicn_protocol_t * h,
+                   const hicn_name_t * name)
+{
+  h->ipv4.saddr = name->ip4.prefix_as_ip4;
+  return CHILD_OPS (set_data_name_suffix, type, h, &(name->ip4.suffix));
+}
+
+int
+ipv4_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                          hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (get_data_name_suffix, type, h, suffix);
+}
+
+int
+ipv4_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                          const hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (set_data_name_suffix, type, h, suffix);
+}
+
+int
+ipv4_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h,
+                        u32 * pathlabel)
+{
+  return CHILD_OPS (get_data_pathlabel, type, h, pathlabel);
+}
+
+int
+ipv4_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                        const u32 pathlabel)
+{
+  return CHILD_OPS (set_data_pathlabel, type, h, pathlabel);
+}
+
+int
+ipv4_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                           const hicn_faceid_t face_id)
+{
+  return CHILD_OPS (update_data_pathlabel, type, h, face_id);
+}
+
+int
+ipv4_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  /* Sets everything to 0 up to source address */
+  memset (&h->ipv4, 0, 12);
+  /* Clears destination address */
+  memset (&(h->ipv4.daddr), 0, 4);
+
+  return CHILD_OPS (reset_data_for_hash, type, h);
+}
+
+int
+ipv4_get_lifetime (hicn_type_t type, const hicn_protocol_t * h,
+                  hicn_lifetime_t * lifetime)
+{
+  return CHILD_OPS (get_lifetime, type, h, lifetime);
+}
+
+int
+ipv4_set_lifetime (hicn_type_t type, hicn_protocol_t * h,
+                  const hicn_lifetime_t lifetime)
+{
+  return CHILD_OPS (set_lifetime, type, h, lifetime);
+}
+
+int
+ipv4_update_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  /*
+   * Checksum field is not accounted for in lower layers, so we can compute
+   * them in any order. Note that it is only a header checksum.
+   */
+  h->ipv4.csum = 0;
+  h->ipv4.csum = csum (h, IPV4_HDRLEN, 0);
+
+  /* Retrieve payload length if not specified, as it is not available later */
+  if (payload_length == 0)
+    {
+      int rc = ipv4_get_payload_length (type, h, &payload_length);
+      if (rc < 0)
+       return rc;
+    }
+
+  /* Ignore the payload if payload_length = ~0 */
+  if (payload_length == ~0)
+    {
+      payload_length = 0;
+    }
+
+  /* Build pseudo-header */
+  ipv4_pseudo_header_t psh;
+  psh.ip_src = h->ipv4.saddr;
+  psh.ip_dst = h->ipv4.daddr;
+  /* Size is u32 and not u16, we cannot copy and need to care about endianness */
+  psh.size = htons (ntohs (h->ipv4.len) - (u16) IPV4_HDRLEN);
+  psh.zero = 0;
+  psh.protocol = (u8) h->ipv4.protocol;
+
+  /* Compute partial checksum based on pseudo-header */
+  if (partial_csum != 0)
+    {
+      partial_csum = ~partial_csum;
+    }
+  partial_csum = csum (&psh, IPV4_PSHDRLEN, partial_csum);
+
+  return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length);
+}
+
+int
+ipv4_verify_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  /*
+   * Checksum field is not accounted for in lower layers, so we can compute
+   * them in any order. Note that it is only a header checksum.
+   */
+  if (csum (h, IPV4_HDRLEN, 0) != 0)
+    return HICN_LIB_ERROR_CORRUPTED_PACKET;
+
+  /* Retrieve payload length if not specified, as it is not available later */
+  if (payload_length == 0)
+    {
+      int rc = ipv4_get_payload_length (type, h, &payload_length);
+      if (rc < 0)
+       return rc;
+    }
+
+  /* Build pseudo-header */
+  ipv4_pseudo_header_t psh;
+  psh.ip_src = h->ipv4.saddr;
+  psh.ip_dst = h->ipv4.daddr;
+  /* Size is u32 and not u16, we cannot copy and need to care about endianness */
+  psh.size = htons (ntohs (h->ipv4.len) - (u16) IPV4_HDRLEN);
+  psh.zero = 0;
+  psh.protocol = (u8) h->ipv4.protocol;
+
+  /* Compute partial checksum based on pseudo-header */
+  partial_csum = csum (&psh, IPV4_PSHDRLEN, 0);
+
+  return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length);
+}
+
+int
+ipv4_rewrite_interest (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * addr_new,
+                      ip46_address_t * addr_old)
+{
+  // ASSERT(addr_old == NULL);
+  addr_old->ip4 = h->ipv4.saddr;
+  addr_old->pad[0] = 0;
+  addr_old->pad[1] = 0;
+  addr_old->pad[2] = 0;
+
+  h->ipv4.saddr = addr_new->ip4;
+  h->ipv4.csum = 0;
+  h->ipv4.csum = csum (&h->ipv4, IPV4_HDRLEN, 0);
+
+  return CHILD_OPS (rewrite_interest, type, h, addr_new, addr_old);
+}
+
+int
+ipv4_rewrite_data (hicn_type_t type, hicn_protocol_t * h,
+                  const ip46_address_t * addr_new, ip46_address_t * addr_old,
+                  const hicn_faceid_t face_id)
+{
+  // ASSERT(addr_old == NULL);
+  addr_old->ip4 = h->ipv4.daddr;
+  addr_old->pad[0] = 0;
+  addr_old->pad[1] = 0;
+  addr_old->pad[2] = 0;
+
+  h->ipv4.daddr = addr_new->ip4;
+  h->ipv4.csum = 0;
+  h->ipv4.csum = csum (&h->ipv4, IPV4_HDRLEN, 0);
+
+  return CHILD_OPS (rewrite_data, type, h, addr_new, addr_old, face_id);
+}
+
+int
+ipv4_get_current_length (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * header_length)
+{
+  *header_length = IPV4_HDRLEN;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_length (hicn_type_t type, const hicn_protocol_t * h,
+                size_t * header_length)
+{
+  *header_length = h->ipv4.len;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                               size_t * header_length)
+{
+  *header_length = IPV4_HDRLEN;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                       size_t * header_length)
+{
+  size_t child_header_length = 0;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  *header_length = IPV4_HDRLEN + child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * payload_length)
+{
+  size_t child_header_length;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  *payload_length = htons (h->ipv4.len) - IPV4_HDRLEN - child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_set_payload_length (hicn_type_t type, hicn_protocol_t * h,
+                        size_t payload_length)
+{
+  size_t child_header_length;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  h->ipv4.len = htons (payload_length + IPV4_HDRLEN + child_header_length);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv4_get_signature_size (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * signature_size)
+{
+  return CHILD_OPS (get_signature_size, type, h, signature_size);
+}
+
+int
+ipv4_set_signature_size (hicn_type_t type, hicn_protocol_t * h,
+                        size_t signature_size)
+{
+  return CHILD_OPS (set_signature_size, type, h, signature_size);
+}
+
+int
+ipv4_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h,
+       uint64_t signature_timestamp)
+{
+  return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+ipv4_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h,
+       uint64_t * signature_timestamp)
+{
+  return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+ipv4_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t validation_algorithm)
+{
+  return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+ipv4_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h,
+       uint8_t * validation_algorithm)
+{
+  return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+ipv4_set_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t *key_id)
+{
+  return CHILD_OPS (set_key_id, type, h, key_id);
+}
+
+int
+ipv4_get_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t **key_id, uint8_t *key_id_size)
+{
+  return CHILD_OPS (get_key_id, type, h, key_id, key_id_size);
+}
+
+DECLARE_HICN_OPS (ipv4);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ipv4.h b/lib/src/protocol/ipv4.h
new file mode 100755 (executable)
index 0000000..c57485b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019 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 HICN_PROTOCOL_IPV4
+#define HICN_PROTOCOL_IPV4
+
+#include "../base.h"
+#include "../common.h"
+#include "../protocol.h"
+
+/* Headers were adapted from linux' definitions in netinet/ip.h */
+
+typedef struct
+{
+  union
+  {
+    struct
+    {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      u8 ihl:4;
+      u8 version:4;
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+      u8 version:4;
+      u8 ihl:4;
+#else
+#error "Unsupported endianness"
+#endif
+    };
+
+    u8 version_ihl;
+  };
+  u8 tos;
+  u16 len;
+  u16 id;
+  u16 frag_off;
+  u8 ttl;
+  u8 protocol;
+  u16 csum;
+  ip4_address_t saddr;
+  ip4_address_t daddr;
+} _ipv4_header_t;
+
+#define ipv4_header_bytes(ipv4_header) (sizeof(u32) * (ipv4_header->version_ihl & 0xf))
+
+#define IPV4_HDRLEN sizeof(_ipv4_header_t)
+
+typedef struct
+{
+  ip4_address_t ip_src;
+  ip4_address_t ip_dst;
+  u8 zero;
+  u8 protocol;
+  u16 size;
+} ipv4_pseudo_header_t;
+
+#define IPV4_PSHDRLEN sizeof(ipv4_pseudo_header_t)
+
+/* Default field values */
+#define IPV4_DEFAULT_VERSION         4
+#define IPV4_DEFAULT_IHL             5
+#define IPV4_DEFAULT_TOS             0
+#define IPV4_DEFAULT_PAYLOAD_LENGTH  0
+#define IPV4_DEFAULT_ID              300
+#define IPV4_DEFAULT_FRAG_OFF        0x000
+#define IPV4_DEFAULT_TTL             64
+#define IPV4_DEFAULT_PROTOCOL        IPPROTO_TCP
+#define IPV4_DEFAULT_SRC_IP          0, 0, 0, 0
+#define IPV4_DEFAULT_DST_IP          0, 0, 0, 0
+
+
+#endif /* HICN_PROTOCOL_IPV4 */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ipv6.c b/lib/src/protocol/ipv6.c
new file mode 100755 (executable)
index 0000000..41b00ec
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdlib.h>
+#include <string.h>
+
+#include "../common.h"
+#include "../error.h"
+#include "../ops.h"
+
+int
+ipv6_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * payload_length);
+
+int
+ipv6_init_packet_header (hicn_type_t type, hicn_protocol_t * h)
+{
+  size_t total_header_length;
+  int rc = CHILD_OPS (get_header_length, type, h, &total_header_length);
+  if (rc < 0)
+    return rc;
+
+  /* *INDENT-OFF* */
+  h->ipv6 = (_ipv6_header_t)
+  {
+    .saddr = {{ 0 }}
+    ,.daddr = {{ 0 }}
+    ,.version_class_flow = htonl ((IPV6_DEFAULT_VERSION << 28) |
+                                 (IPV6_DEFAULT_TRAFFIC_CLASS << 20) |
+                                 (IPV6_DEFAULT_FLOW_LABEL & 0xfffff)),
+    .len = htons ((u16) total_header_length),
+    .nxt = type.l2,
+    .hlim = HICN_DEFAULT_TTL,
+  };
+  /* *INDENT-ON* */
+  return CHILD_OPS (init_packet_header, type, h);
+}
+
+int
+ipv6_get_interest_locator (hicn_type_t type, const hicn_protocol_t * h,
+                          ip46_address_t * ip_address)
+{
+  ip_address->ip6 = h->ipv6.saddr;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_set_interest_locator (hicn_type_t type, hicn_protocol_t * h,
+                          const ip46_address_t * ip_address)
+{
+  h->ipv6.saddr = ip_address->ip6;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_interest_name (hicn_type_t type, const hicn_protocol_t * h,
+                       hicn_name_t * name)
+{
+  name->ip6.prefix_as_ip6 = h->ipv6.daddr;
+#ifndef HICN_VPP_PLUGIN
+  name->type = HNT_CONTIGUOUS_V6;
+  name->len = HICN_V6_NAME_LEN;
+#endif /* HICN_VPP_PLUGIN */
+  return CHILD_OPS (get_interest_name_suffix, type, h, &(name->ip6.suffix));
+}
+
+int
+ipv6_set_interest_name (hicn_type_t type, hicn_protocol_t * h,
+                       const hicn_name_t * name)
+{
+  h->ipv6.daddr = name->ip6.prefix_as_ip6;
+  return CHILD_OPS (set_interest_name_suffix, type, h, &(name->ip6.suffix));
+}
+
+int
+ipv6_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                              hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (get_interest_name_suffix, type, h, suffix);
+}
+
+int
+ipv6_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                              const hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (set_interest_name_suffix, type, h, suffix);
+}
+
+int
+ipv6_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  /* Sets everything to 0 up to IP destination address */
+  memset (&(h->ipv6), 0, 24);
+
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+int
+ipv6_get_data_locator (hicn_type_t type, const hicn_protocol_t * h,
+                      ip46_address_t * ip_address)
+{
+  ip_address->ip6 = h->ipv6.daddr;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_set_data_locator (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * ip_address)
+{
+  h->ipv6.daddr = ip_address->ip6;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_data_name (hicn_type_t type, const hicn_protocol_t * h,
+                   hicn_name_t * name)
+{
+  name->ip6.prefix_as_ip6 = h->ipv6.saddr;
+#ifndef HICN_VPP_PLUGIN
+  name->type = HNT_CONTIGUOUS_V6;
+  name->len = HICN_V6_NAME_LEN;
+#endif /* HICN_VPP_PLUGIN */
+  return CHILD_OPS (get_data_name_suffix, type, h, &(name->ip6.suffix));
+}
+
+int
+ipv6_set_data_name (hicn_type_t type, hicn_protocol_t * h,
+                   const hicn_name_t * name)
+{
+  h->ipv6.saddr = name->ip6.prefix_as_ip6;
+  return CHILD_OPS (set_data_name_suffix, type, h, &(name->ip6.suffix));
+}
+
+int
+ipv6_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                          hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (get_data_name_suffix, type, h, suffix);
+}
+
+int
+ipv6_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                          const hicn_name_suffix_t * suffix)
+{
+  return CHILD_OPS (set_data_name_suffix, type, h, suffix);
+}
+
+int
+ipv6_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h,
+                        u32 * pathlabel)
+{
+  return CHILD_OPS (get_data_pathlabel, type, h, pathlabel);
+}
+
+int
+ipv6_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                        const u32 pathlabel)
+{
+  return CHILD_OPS (set_data_pathlabel, type, h, pathlabel);
+}
+
+int
+ipv6_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                           const hicn_faceid_t face_id)
+{
+  return CHILD_OPS (update_data_pathlabel, type, h, face_id);
+}
+
+int
+ipv6_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  /* IP: Set everithing to 0 up to destination address */
+  memset (&h->ipv6, 0, 8);
+  /* Clears destination address */
+  memset (&(h->ipv6.daddr), 0, 16);
+
+  return CHILD_OPS (reset_data_for_hash, type, h);
+}
+
+int
+ipv6_get_lifetime (hicn_type_t type, const hicn_protocol_t * h,
+                  hicn_lifetime_t * lifetime)
+{
+  return CHILD_OPS (get_lifetime, type, h, lifetime);
+}
+
+int
+ipv6_set_lifetime (hicn_type_t type, hicn_protocol_t * h,
+                  const hicn_lifetime_t lifetime)
+{
+  return CHILD_OPS (set_lifetime, type, h, lifetime);
+}
+
+int
+ipv6_update_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  /* Retrieve payload length if not specified */
+  if (payload_length == 0)
+    {
+      int rc = ipv6_get_payload_length (type, h, &payload_length);
+      if (rc < 0)
+       return rc;
+    }
+
+  /* Ignore the payload if payload_length = ~0 */
+  if (payload_length == ~0)
+    {
+      payload_length = 0;
+    }
+
+  /* Build pseudo-header */
+  ipv6_pseudo_header_t psh;
+  psh.ip_src = h->ipv6.saddr;
+  psh.ip_dst = h->ipv6.daddr;
+  /* Size is u32 and not u16, we cannot copy and need to care about endianness */
+  psh.size = htonl (ntohs (h->ipv6.len));
+  psh.zeros = 0;
+  psh.zero = 0;
+  psh.protocol = h->ipv6.nxt;
+
+  /* Compute partial checksum based on pseudo-header */
+  if (partial_csum != 0)
+    {
+      partial_csum = ~partial_csum;
+    }
+  partial_csum = csum (&psh, IPV6_PSHDRLEN, partial_csum);
+
+  return CHILD_OPS (update_checksums, type, h, partial_csum, payload_length);
+}
+
+int
+ipv6_verify_checksums (hicn_type_t type, hicn_protocol_t * h,
+                      u16 partial_csum, size_t payload_length)
+{
+  /* Retrieve payload length if not specified */
+  if (payload_length == 0)
+    {
+      int rc = ipv6_get_payload_length (type, h, &payload_length);
+      if (rc < 0)
+       return rc;
+    }
+
+  /* Build pseudo-header */
+  ipv6_pseudo_header_t pseudo;
+  pseudo.ip_src = h->ipv6.saddr;
+  pseudo.ip_dst = h->ipv6.daddr;
+  /* Size is u32 and not u16, we cannot copy and need to care about endianness */
+  pseudo.size = htonl (ntohs (h->ipv6.len));
+  pseudo.zeros = 0;
+  pseudo.zero = 0;
+  pseudo.protocol = h->ipv6.nxt;
+
+  /* Compute partial checksum based on pseudo-header */
+  partial_csum = csum (&pseudo, IPV6_PSHDRLEN, 0);
+
+  return CHILD_OPS (verify_checksums, type, h, partial_csum, payload_length);
+}
+
+int
+ipv6_rewrite_interest (hicn_type_t type, hicn_protocol_t * h,
+                      const ip46_address_t * addr_new,
+                      ip46_address_t * addr_old)
+{
+  // ASSERT(addr_old == NULL);
+  addr_old->ip6 = h->ipv6.saddr;
+  h->ipv6.saddr = addr_new->ip6;
+
+  return CHILD_OPS (rewrite_interest, type, h, addr_new, addr_old);
+}
+
+int
+ipv6_rewrite_data (hicn_type_t type, hicn_protocol_t * h,
+                  const ip46_address_t * addr_new, ip46_address_t * addr_old,
+                  const hicn_faceid_t face_id)
+{
+  // ASSERT(addr_old == NULL);
+  addr_old->ip6 = h->ipv6.daddr;
+  h->ipv6.daddr = addr_new->ip6;
+
+  return CHILD_OPS (rewrite_data, type, h, addr_new, addr_old, face_id);
+}
+
+int
+ipv6_get_length (hicn_type_t type, const hicn_protocol_t * h,
+                size_t * header_length)
+{
+  *header_length = IPV6_HDRLEN + ntohs (h->ipv6.len);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                               size_t * header_length)
+{
+  *header_length = IPV6_HDRLEN;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                       size_t * header_length)
+{
+  size_t child_header_length = 0;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  *header_length = IPV6_HDRLEN + child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_payload_length (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * payload_length)
+{
+  size_t child_header_length;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  *payload_length = ntohs (h->ipv6.len) - child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_set_payload_length (hicn_type_t type, hicn_protocol_t * h,
+                        size_t payload_length)
+{
+  size_t child_header_length;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+  h->ipv6.len = htons (payload_length + child_header_length);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+ipv6_get_signature_size (hicn_type_t type, const hicn_protocol_t * h,
+                        size_t * signature_size)
+{
+  return CHILD_OPS (get_signature_size, type, h, signature_size);
+}
+
+int
+ipv6_set_signature_size (hicn_type_t type, hicn_protocol_t * h,
+                        size_t signature_size)
+{
+  return CHILD_OPS (set_signature_size, type, h, signature_size);
+}
+
+int
+ipv6_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h,
+       uint64_t signature_timestamp)
+{
+  return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+ipv6_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h,
+       uint64_t * signature_timestamp)
+{
+  return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+ipv6_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t validation_algorithm)
+{
+  return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+ipv6_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h,
+       uint8_t * validation_algorithm)
+{
+  return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+ipv6_set_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t *key_id)
+{
+  return CHILD_OPS (set_key_id, type, h, key_id);
+}
+
+int
+ipv6_get_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t **key_id, uint8_t *key_id_size)
+{
+  return CHILD_OPS (get_key_id, type, h, key_id, key_id_size);
+}
+
+DECLARE_HICN_OPS (ipv6);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/ipv6.h b/lib/src/protocol/ipv6.h
new file mode 100755 (executable)
index 0000000..28a1aa4
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017-2019 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 HICN_PROTOCOL_IPV6_H
+#define HICN_PROTOCOL_IPV6_H
+
+#include "../common.h"
+
+typedef struct
+{
+  union
+  {
+    struct
+    {
+      u32 version_class_flow;  /* version, traffic class and 20 bits of flow-ID */
+      u16 len;                 /* payload length */
+      u8 nxt;                  /* next header */
+      u8 hlim;                 /* hop limit */
+    };
+    u8 vfc;                    /* 4 bits version, top 4 bits class */
+  };
+  ip6_address_t saddr;         /* source address */
+  ip6_address_t daddr;         /* destination address */
+} _ipv6_header_t;
+
+
+#define IPV6_HDRLEN sizeof(_ipv6_header_t)
+
+typedef struct
+{
+  ip6_address_t ip_src;
+  ip6_address_t ip_dst;
+  u32 size;
+  u16 zeros;
+  u8 zero;
+  u8 protocol;
+} ipv6_pseudo_header_t;
+
+#define IPV6_PSHDRLEN sizeof(ipv6_pseudo_header_t)
+
+/* Default field values */
+#define IPV6_DEFAULT_VERSION         6
+#define IPV6_DEFAULT_TRAFFIC_CLASS   0
+#define IPV6_DEFAULT_FLOW_LABEL      0
+#define IPV6_DEFAULT_PAYLOAD_LENGTH  0
+
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/tcp.c b/lib/src/protocol/tcp.c
new file mode 100755 (executable)
index 0000000..2afc4f6
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2017-2019 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 <string.h>
+#include "tcp.h"
+
+#include "../error.h"
+#include "../ops.h"
+
+#define TCP_DEFAULT_SRC_PORT           0x8000
+#define TCP_DEFAULT_DST_PORT           0x0080
+#define TCP_DEFAULT_WINDOW_SIZE        0       // In [2, 65535]
+#define TCP_DEFAULT_HLEN               20
+#define TCP_DEFAULT_DATA_OFFSET_RES    (TCP_DEFAULT_HLEN >> 2) << 4
+#define TCP_DEFAULT_CWR                0
+#define TCP_DEFAULT_ECE                0
+#define TCP_DEFAULT_URG                0
+#define TCP_DEFAULT_ACK                0
+#define TCP_DEFAULT_PSH                0
+#define TCP_DEFAULT_RST                0
+#define TCP_DEFAULT_SYN                1
+#define TCP_DEFAULT_FIN                0
+
+DECLARE_get_interest_locator (tcp, UNEXPECTED);
+DECLARE_set_interest_locator (tcp, UNEXPECTED);
+DECLARE_get_interest_name (tcp, UNEXPECTED);
+DECLARE_set_interest_name (tcp, UNEXPECTED);
+DECLARE_get_data_locator (tcp, UNEXPECTED);
+DECLARE_set_data_locator (tcp, UNEXPECTED);
+DECLARE_get_data_name (tcp, UNEXPECTED);
+DECLARE_set_data_name (tcp, UNEXPECTED);
+DECLARE_get_length (tcp, UNEXPECTED);
+DECLARE_get_payload_length (tcp, UNEXPECTED);
+DECLARE_set_payload_length (tcp, UNEXPECTED);
+
+int
+tcp_init_packet_header (hicn_type_t type, hicn_protocol_t * h)
+{
+  h->tcp = (_tcp_header_t)
+  {
+  .sport = htons (TCP_DEFAULT_SRC_PORT),.dport =
+      htons (TCP_DEFAULT_DST_PORT),.seq = 0,.seq_ack =
+      0,.data_offset_and_reserved = TCP_DEFAULT_DATA_OFFSET_RES,.flags =
+      TCP_DEFAULT_CWR << 7 | TCP_DEFAULT_ECE << 6 | TCP_DEFAULT_URG << 5 |
+      TCP_DEFAULT_ACK << 4 | TCP_DEFAULT_PSH << 3 | TCP_DEFAULT_RST << 2 |
+      TCP_DEFAULT_SYN << 1 | TCP_DEFAULT_FIN << 0,.window =
+      htons (TCP_DEFAULT_WINDOW_SIZE),.csum = 0,.urg_ptr = 65000,};
+
+  return CHILD_OPS (init_packet_header, type, h);
+}
+
+int
+tcp_get_interest_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                             hicn_name_suffix_t * suffix)
+{
+  *suffix = ntohl (h->tcp.name_suffix);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_interest_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                             const hicn_name_suffix_t * suffix)
+{
+  h->tcp.name_suffix = htonl (*suffix);
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_reset_interest_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  memset (&(h->tcp), 0, 4);
+  memset (&(h->tcp.seq_ack), 0, 12);
+
+  return CHILD_OPS (reset_interest_for_hash, type, h);
+}
+
+
+int
+tcp_get_data_name_suffix (hicn_type_t type, const hicn_protocol_t * h,
+                         hicn_name_suffix_t * suffix)
+{
+  *suffix = ntohl (h->tcp.name_suffix);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_data_name_suffix (hicn_type_t type, hicn_protocol_t * h,
+                         const hicn_name_suffix_t * suffix)
+{
+  h->tcp.name_suffix = htonl (*suffix);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_get_data_pathlabel (hicn_type_t type, const hicn_protocol_t * h,
+                       u32 * pathlabel)
+{
+  *pathlabel = h->tcp.seq_ack;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                       const u32 pathlabel)
+{
+  h->tcp.seq_ack = pathlabel;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_update_data_pathlabel (hicn_type_t type, hicn_protocol_t * h,
+                          const hicn_faceid_t face_id)
+{
+  hicn_pathlabel_t pl =
+    (hicn_pathlabel_t) ((h->tcp.pathlabel & HICN_PATH_LABEL_MASK) >> (32 -
+                                                                     HICN_PATH_LABEL_SIZE));
+  hicn_pathlabel_t new_pl;
+
+  update_pathlabel (pl, face_id, &new_pl);
+  h->tcp.pathlabel = new_pl;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_reset_data_for_hash (hicn_type_t type, hicn_protocol_t * h)
+{
+  memset (&(h->tcp), 0, 4);
+  memset (&(h->tcp.seq_ack), 0, 12);
+
+  return CHILD_OPS (reset_data_for_hash, type, h);
+}
+
+
+int
+tcp_get_lifetime (hicn_type_t type, const hicn_protocol_t * h,
+                 hicn_lifetime_t * lifetime)
+{
+  *lifetime =
+    ntohs (h->tcp.urg_ptr) << (h->tcp.data_offset_and_reserved & 0xF);
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_set_lifetime (hicn_type_t type, hicn_protocol_t * h,
+                 const hicn_lifetime_t lifetime)
+{
+  u8 multiplier = 0;
+  u32 lifetime_scaled = lifetime;
+
+  if (PREDICT_FALSE (lifetime >= HICN_MAX_LIFETIME))
+    {
+      h->tcp.urg_ptr = htons (HICN_MAX_LIFETIME_SCALED);
+      h->tcp.data_offset_and_reserved =
+       (h->
+        tcp.data_offset_and_reserved & ~0xF) | HICN_MAX_LIFETIME_MULTIPLIER;
+      return HICN_LIB_ERROR_NONE;
+    }
+
+  while (lifetime_scaled > HICN_MAX_LIFETIME_SCALED
+        && multiplier <= HICN_MAX_LIFETIME_MULTIPLIER)
+    {
+      multiplier++;
+      lifetime_scaled = lifetime_scaled >> 1;
+    }
+
+  h->tcp.urg_ptr = htons (lifetime_scaled);
+  h->tcp.data_offset_and_reserved =
+    (h->tcp.data_offset_and_reserved & ~0xF) | multiplier;
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_update_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum,
+                     size_t payload_length)
+{
+  h->tcp.csum = 0;
+
+  if (PREDICT_TRUE (partial_csum != 0))
+    {
+      partial_csum = ~partial_csum;
+    }
+
+  h->tcp.csum = csum (h, TCP_HDRLEN + payload_length, partial_csum);
+
+  return CHILD_OPS (update_checksums, type, h, 0, payload_length);
+}
+
+int
+tcp_verify_checksums (hicn_type_t type, hicn_protocol_t * h, u16 partial_csum,
+                     size_t payload_length)
+{
+  if (csum (h, TCP_HDRLEN + payload_length, ~partial_csum) != 0)
+    return HICN_LIB_ERROR_CORRUPTED_PACKET;
+  return CHILD_OPS (verify_checksums, type, h, 0, payload_length);
+}
+
+#define TCP_OFFSET_MASK                13
+#define TCP_OFFSET_DATA_OFFSET         12
+#define TCP_OFFSET_IN_BITS_DATA_OFFSET 0
+#define TCP_OFFSET_IN_BITS_RESERVED    4
+#define TCP_OFFSET_IN_BITS_NS          7
+
+#define TCP_DEFAULT_SRC_PORT           0x8000
+#define TCP_DEFAULT_DST_PORT           0x0080
+#define TCP_DEFAULT_WINDOW_SIZE        0       // In [2, 65535]
+#define TCP_DEFAULT_DATA_OFFSET        5       // Size of the TCP header in words (= 4 bytes). Must be greater or equal than 5.
+#define TCP_DEFAULT_CWR                0
+#define TCP_DEFAULT_ECE                0
+#define TCP_DEFAULT_URG                0
+#define TCP_DEFAULT_ACK                0
+#define TCP_DEFAULT_PSH                0
+#define TCP_DEFAULT_RST                0
+#define TCP_DEFAULT_SYN                1
+#define TCP_DEFAULT_FIN                0
+
+int
+tcp_rewrite_interest (hicn_type_t type, hicn_protocol_t * h,
+                     const ip46_address_t * addr_new,
+                     ip46_address_t * addr_old)
+{
+  u16 *tcp_checksum = &(h->tcp.csum);
+
+  /*
+   * Padding fields are set to zero so we can apply checksum on the
+   * whole struct by interpreting it as IPv6 in all cases
+   *
+   * v4 code would be:
+   * csum = ip_csum_sub_even (*tcp_checksum, h->ipv4.saddr.as_u32);
+   * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32);
+   */
+  u16 csum = ip_csum_sub_even (*tcp_checksum, h->ipv6.saddr.as_u64[0]);
+  csum = ip_csum_sub_even (csum, h->ipv6.saddr.as_u64[1]);
+  csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[0]);
+  csum = ip_csum_add_even (csum, h->ipv6.saddr.as_u64[1]);
+
+  *tcp_checksum = ip_csum_fold (csum);
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_rewrite_data (hicn_type_t type, hicn_protocol_t * h,
+                 const ip46_address_t * addr_new, ip46_address_t * addr_old,
+                 const hicn_faceid_t face_id)
+{
+  u16 *tcp_checksum = &(h->tcp.csum);
+
+  /*
+   * Padding fields are set to zero so we can apply checksum on the
+   * whole struct by interpreting it as IPv6 in all cases
+   *
+   * v4 code would be:
+   * csum = ip_csum_sub_even (*tcp_checksum, h->ipv4.saddr.as_u32);
+   * csum = ip_csum_add_even (csum, h->ipv4.saddr.as_u32);
+   */
+  u16 csum = ip_csum_sub_even (*tcp_checksum, addr_old->ip6.as_u64[0]);
+  csum = ip_csum_sub_even (*tcp_checksum, addr_old->ip6.as_u64[1]);
+  csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[0]);
+  csum = ip_csum_add_even (csum, addr_new->ip6.as_u64[1]);
+
+  csum = ip_csum_sub_even (csum, h->tcp.pathlabel);
+  tcp_update_data_pathlabel (type, h, face_id);
+  csum = ip_csum_add_even (csum, h->tcp.pathlabel);
+
+  *tcp_checksum = ip_csum_fold (csum);
+
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_get_current_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                              size_t * header_length)
+{
+  *header_length = TCP_HDRLEN;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_get_header_length (hicn_type_t type, const hicn_protocol_t * h,
+                      size_t * header_length)
+{
+  size_t child_header_length = 0;
+  int rc = CHILD_OPS (get_header_length, type, h, &child_header_length);
+  if (rc < 0)
+    return rc;
+
+  *header_length = TCP_HDRLEN + child_header_length;
+  return HICN_LIB_ERROR_NONE;
+}
+
+int
+tcp_get_signature_size (hicn_type_t type, const hicn_protocol_t * h,
+                       size_t * signature_size)
+{
+  return CHILD_OPS (get_signature_size, type, h, signature_size);
+}
+
+int
+tcp_set_signature_size (hicn_type_t type, hicn_protocol_t * h,
+                       size_t signature_size)
+{
+  return CHILD_OPS (set_signature_size, type, h, signature_size);
+}
+
+int
+tcp_set_signature_timestamp(hicn_type_t type, hicn_protocol_t * h,
+       uint64_t signature_timestamp)
+{
+  return CHILD_OPS (set_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+tcp_get_signature_timestamp (hicn_type_t type, const hicn_protocol_t * h,
+       uint64_t * signature_timestamp)
+{
+  return CHILD_OPS (get_signature_timestamp, type, h, signature_timestamp);
+}
+
+int
+tcp_set_validation_algorithm (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t validation_algorithm)
+{
+  return CHILD_OPS (set_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+tcp_get_validation_algorithm (hicn_type_t type, const hicn_protocol_t * h,
+       uint8_t * validation_algorithm)
+{
+  return CHILD_OPS (get_validation_algorithm, type, h, validation_algorithm);
+}
+
+int
+tcp_set_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t *key_id)
+{
+  return CHILD_OPS (set_key_id, type, h, key_id);
+}
+
+int
+tcp_get_key_id (hicn_type_t type, hicn_protocol_t * h,
+       uint8_t **key_id, uint8_t *key_id_size)
+{
+  return CHILD_OPS (get_key_id, type, h, key_id, key_id_size);
+}
+
+DECLARE_HICN_OPS (tcp);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/tcp.h b/lib/src/protocol/tcp.h
new file mode 100755 (executable)
index 0000000..68f4bf8
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2019 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 HICN_PROTOCOL_TCP_H
+#define HICN_PROTOCOL_TCP_H
+
+#include "../base.h"
+#include "../common.h"
+#include "../name.h"
+
+/*
+ * NOTE: bitfields are problematic for portability reasons. There are provided
+ * here for reference and documentation purposes, we might just provide a macro
+ * to disable and use it instead of __BYTE_ORDER__.
+ */
+typedef struct __attribute__ ((packed))
+{
+  u16 sport;
+  u16 dport;
+  union
+  {
+    u32 seq;
+    hicn_name_suffix_t name_suffix;
+  };
+  union
+  {
+    u32 seq_ack;
+    struct
+    {
+      hicn_pathlabel_t pathlabel;
+      u8 pad[3];
+    };
+  };
+
+  union
+  {
+    struct
+    {
+      u8 data_offset_and_reserved;
+      u8 flags;
+    };
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    struct
+    {
+      u16 reserved:4;
+      u16 doff:4;
+      u16 fin:1;
+      u16 syn:1;
+      u16 rst:1;
+      u16 psh:1;
+      u16 ack:1;
+      u16 urg:1;
+      u16 ece:1;
+      u16 cwr:1;
+    };
+    struct
+    {                          /* __ denotes unchanged bitfields */
+      u16 timescale:4;
+      u16 __doff:4;
+      u16 __fin:1;
+      u16 __syn:1;
+      u16 __rst:1;
+      u16 sig:1;
+      u16 __ack:1;
+      u16 man:1;
+      u16 id:1;
+      u16 __cwr:1;
+    };
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    struct
+    {
+      u16 doff:4;
+      u16 reserved:4;
+      u16 cwr:1;
+      u16 ece:1;
+      u16 urg:1;
+      u16 ack:1;
+      u16 psh:1;
+      u16 rst:1;
+      u16 syn:1;
+      u16 fin:1;
+    };
+    struct
+    {
+      u16 __doff:4;
+      u16 timescale:4;
+      u16 __cwr:1;
+      u16 id:1 u16 man:1;
+      u16 __ack:1;
+      u16 sig:1;
+      u16 __rst:1;
+      u16 __syn:1;
+      u16 __fin:1;
+    };
+#endif
+  };
+  union
+  {
+    u16 window;
+    u16 ldr;
+  };
+  u16 csum;
+  union
+  {
+    u16 urg_ptr;
+    u16 lifetime;
+  };
+} _tcp_header_t;
+
+#define TCP_HDRLEN sizeof(_tcp_header_t)
+
+#ifndef HICN_VPP_PLUGIN
+
+/* TCP flags bit 0 first. */
+#define foreach_tcp_flag                                \
+          _ (FIN) /**< No more data from sender. */             \
+      _ (SYN) /**< Synchronize sequence numbers. */         \
+      _ (RST) /**< Reset the connection. */                 \
+      _ (PSH) /**< Push function. */                        \
+      _ (ACK) /**< Ack field significant. */                \
+      _ (URG) /**< Urgent pointer field significant. */     \
+      _ (ECE) /**< ECN-echo. Receiver got CE packet */      \
+      _ (CWR) /**< Sender reduced congestion window */
+
+enum
+{
+#define _(f) TCP_FLAG_BIT_##f,
+  foreach_tcp_flag
+#undef _
+    TCP_N_FLAG_BITS,
+};
+
+enum
+{
+#define _(f) TCP_FLAG_##f = 1 << TCP_FLAG_BIT_##f,
+  foreach_tcp_flag
+#undef _
+};
+
+#endif /* HICN_VPP_PLUGIN */
+
+// get_data_name_suffix
+// name->ip4.suffix = h->v4.tcp.seq;
+
+
+#endif /* HICN_PROTOCOL_TCP_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/lib/src/protocol/udp.h b/lib/src/protocol/udp.h
new file mode 100755 (executable)
index 0000000..58cd650
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019 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 HICN_PROTOCOL_UDP_H
+#define HICN_PROTOCOL_UDP_H
+
+typedef struct
+{
+  u16 src_port;
+  u16 dst_port;
+  u16 length;
+  u16 checksum;
+} _udp_header_t;
+
+#define UDP_HDRLEN sizeof(_udp_header_t)
+
+#endif /* HICN_PROTOCOL_UDP_H */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/libtransport/AUTHORS b/libtransport/AUTHORS
new file mode 100755 (executable)
index 0000000..12d1ae6
--- /dev/null
@@ -0,0 +1,8 @@
+Libtransport authors are listed below
+
+    Mauro Sardara <msardara@cisco.com>
+    Michele Papalini <micpapal@cisco.com>
+    Alberto Compagno <acompagn@cisco.com>
+    Luca Muscariello <lumuscar@cisco.com>
+
+Copyright (c) 2017-2019 Cisco and/or its affiliates.
\ No newline at end of file
diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f2ade45
--- /dev/null
@@ -0,0 +1,122 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+project(Transport VERSION 1.0)
+
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+)
+
+include(DefaultConfiguration)
+include(Packager)
+include(BuildMacros)
+
+if (NOT CMAKE_BUILD_TYPE)
+  message(STATUS "No build type selected, default to Release")
+  set(CMAKE_BUILD_TYPE "Release")
+endif ()
+
+set(TRANSPORT_ROOT_PATH "src/hicn/transport")
+
+set(TRANSPORT_CORE ${TRANSPORT_ROOT_PATH}/core)
+set(TRANSPORT_TRANSPORT ${TRANSPORT_ROOT_PATH}/transport)
+set(TRANSPORT_ERRORS ${TRANSPORT_ROOT_PATH}/errors)
+set(TRANSPORT_UTILS ${TRANSPORT_ROOT_PATH}/utils)
+set(TRANSPORT_HTTP ${TRANSPORT_ROOT_PATH}/http)
+set(TRANSPORT_PORTABILITY ${TRANSPORT_ROOT_PATH}/portability)
+set(TRANSPORT_INTERFACES ${TRANSPORT_ROOT_PATH}/interfaces)
+
+set(raaqm_config_path ${CMAKE_INSTALL_PREFIX}/etc/hicn-consumer.conf)
+
+# Install includes
+set(INSTALL_INCLUDE_DIR include/hicn/transport)
+
+if ((BUILD_MEMIF_CONNECTOR OR BUILD_VPP_PLUGIN) AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+  set(__vpp__ 1)
+  find_package(Vpp REQUIRED)
+  find_package(Libmemif REQUIRED)
+  list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+    ${VPP_INCLUDE_DIRS}
+    ${LIBMEMIF_INCLUDE_DIRS}
+  )
+
+  list(APPEND LIBRARIES
+    # ${VPP_INCLUDE_DIRS}
+    ${LIBMEMIF_LIBRARIES}
+  )
+endif ()
+
+include(IosMacros)
+find_package_wrapper(Libparc REQUIRED)
+find_package_wrapper(Asio REQUIRED)
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+  find_package_wrapper(Libhicn REQUIRED)
+  if (__vpp__)
+    find_package_wrapper(HicnBinaryApi REQUIRED)
+  endif()
+  set(LIBTRANSPORT transport)
+else()
+  set(HICN_LIBRARIES ${LIBHICN_SHARED})
+  list(APPEND DEPENDENCIES
+    ${LIBHICN}
+    ${LIBHICN_SHARED}
+  )
+
+  if (__vpp__)
+    list(APPEND DEPENDENCIES
+      hicn_plugin
+    )
+  endif()
+endif()
+
+find_package(Threads REQUIRED)
+
+if (${COMPILE_TESTS})
+  include(TestMacros)
+  find_package(GTest REQUIRED)
+  list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+    ${GTEST_INCLUDE_DIRS}
+  )
+endif()
+
+list(APPEND LIBRARIES
+  ${LIBPARC_LIBRARIES}
+  ${CMAKE_THREAD_LIBS_INIT}
+  ${HICN_LIBRARIES}
+  ${VPP_LIBRARIES}
+  ${ANDROID_LIBRARIES}
+  ${OPENSSL_LIBRARIES}
+)
+
+# Include dirs -- Order does matter!
+list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+  ${HICN_INCLUDE_DIRS}
+  ${HICN_BINARY_API_INCLUDE_DIRS}
+  ${LIBPARC_INCLUDE_DIRS}
+  ${CMAKE_THREADS_INCLUDE_DIRS}
+  ${ASIO_INCLUDE_DIRS}
+)
+
+add_subdirectory(${TRANSPORT_ROOT_PATH})
+
+# Packaging
+add_package(libtransport
+  NAME "libtransport"
+  # DEPENDENCIES "fd.io" FIXME
+  DESCRIPTION "Shared Memory Interface"
+)
diff --git a/libtransport/README.md b/libtransport/README.md
new file mode 100755 (executable)
index 0000000..e7fc267
--- /dev/null
@@ -0,0 +1,126 @@
+Libtransport: data transport library for hICN
+====================================================
+
+## Introduction ##
+
+This library provides transport services and socket API for applications willing to communicate
+using the hICN protocol stack.
+
+Overview:
+
+- Implementation of the hICN core objects (interest, data, name..) exploiting the API provided by [libhicn](../lib).
+- Connectors for connecting the application to either the hicn-plugin or the hicn-light forwarder.
+- Transport protocols (RAAQM, CBR, RTP)
+- Transport services (authentication, integrity, segmentation, reassembly, naming)
+- Interfaces for Applications (from low-level interfaces for interest-data interaction to high level interfaces for Application Data Unit interaction)
+
+## Build Dependencies ##
+
+- libparc
+- libmemif (linux only, if compiling with VPP support)
+- libasio
+
+### Ubuntu 16.04 and Ubuntu 18.04 ###
+
+```bash
+ $ echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io.master.ubuntu.$(lsb_release -sc).main/ ./" \
+          | sudo tee -a /etc/apt/sources.list.d/99fd.io.list
+ $ sudo apt-get install libparc libasio-dev
+```
+
+If you wish to use the library for connecting to the vpp hicn-plugin, you will need to also install vpp, the vpp libraries and the libmemif libraries:
+
+- DEB packages:
+  - vpp
+  - vpp-lib
+  - vpp-dev
+
+You can get them either from from the vpp packages ot the source code. Check the [VPP wiki](https://wiki.fd.io/view/VPP) for instructions.
+
+Libmemif is in the vpp-lib and vpp-dev packages.
+
+### Mac OSX ###
+
+We recommend to use [HomeBrew](https://brew.sh/) for installing the libasio dependency:
+
+```bash
+ $ brew install asio
+```
+
+Download, compile and install libparc:
+
+```bash
+ $ git clone -b cframework/master https://gerrit.fd.io/r/cicn cframework && cd cframework
+ $ mkdir -p libparc.build && cd libparc.build
+ $ cmake ../libparc
+ $ make
+ $ make install
+```
+
+Libparc will be installed by default under `/usr/local/lib` and `/usr/local/include`.
+
+Since VPP does not support MAC OS, the hicn-plugin connector is not built.
+
+## Build The library ##
+
+From the project root folder:
+
+```bash
+ $ cd libtransport
+ $ mkdir build && cd build
+ $ cmake ..
+ $ make
+```
+### Compile options ###
+
+The build process can be customized with the following options:
+
+- `CMAKE_INSTALL_PREFIX`: The path where you want to install the library.
+- `CMAKE_BUILD_TYPE`: The build configuration. Options: `Release`, `Debug`. Default is `Release`.
+- `ASIO_HOME`: The folder containing the libasio headers.
+- `LIBPARC_HOME`: The folder containing the libparc headers and libraries.
+- `VPP_HOME`: The folder containing the installation of VPP.
+- `LIBMEMIF_HOME`: The folder containing the libmemif headers and libraries.
+- `BUILD_MEMIF_CONNECTOR`: On linux, set this value to `ON` for building the VPP connector.
+
+An option can be set using cmake -D`OPTION`=`VALUE`.
+
+Install the library
+-------------------
+
+For installing the library, from the cmake build folder:
+
+```bash
+ $ sudo make install
+```
+
+## Supported platforms
+
+- Ubuntu 16.04 LTS (x86_64)
+- Ubuntu 18.04 LTS (x86_64)
+- Debian Stable/Testing
+- Red Hat Enterprise Linux 7
+- CentOS 7
+- Android 8
+- iOS 12
+- macOS 10.12
+- Windows 10
+
+## License ##
+
+This software is distributed under the following license:
+
+```
+Copyright (c) 2017-2019 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.
+```
\ No newline at end of file
diff --git a/libtransport/cmake/Modules/Android.cmake b/libtransport/cmake/Modules/Android.cmake
new file mode 100755 (executable)
index 0000000..7891845
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) 2017-2019 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.
+
+function (configure_android_environment)
+  set(CMAKE_CXX_FLAGS "  -Wall -stdlib=libc++ -DASIO_STANDALONE -pthread -isystem -lm")
+
+  #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
+  #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ANDROID_C_FLAGS}" PARENT_SCOPE)
+endfunction()
\ No newline at end of file
diff --git a/libtransport/cmake/Modules/DefaultConfiguration.cmake b/libtransport/cmake/Modules/DefaultConfiguration.cmake
new file mode 100755 (executable)
index 0000000..2110ac0
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (c) 2017-2019 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.
+
+# C/c++ standard
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_C_STANDARD 11)
+
+# Compilation options
+option(BUILD_APPS "Build apps" ON)
+option(BUILD_WITH_VPP "Add support for VPP" OFF)
+option(COMPILE_TESTS "Compile functional tests" OFF)
+
+# Compilation flags
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fpermissive")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fpermissive")
+set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -fpermissive")
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
+
+# Packaging
+# TODO Libasio and libmemif
+set(DEPS_DEB "libparc (>= 1.0)")
+set(DEPS_RPM "libparc >= 1.0")
+set(BUILD_DEPS_DEB "libtransport (>= 1.0), libhicn-dev (>= 1.0), libparc-dev (>= 1.0)")
+set(BUILD_DEPS_RPM "libtransport >= 1.0, libhicn-devel >= 1.0, libparc-devel >= 1.0")
+
+set(VPP_DEPS_DEB "${DEPS_DEB}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+set(VPP_DEPS_RPM "${DEPS_RPM}, hicn-plugin, vpp-lib >= 18.07), vpp-dev (>= 18.07)")
+set(VPP_BUILD_DEPS_DEB "${BUILD_DEPS_DEB}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+set(VPP_BUILD_DEPS_RPM "${BUILD_DEPS_RPM}, hicn-plugin, vpp-lib (>= 18.07), vpp-dev (>= 18.07)")
+
+set(PACKAGE_DESCRIPTION "This library is designed to provide a transport layer and API for applications willing to communicate using an hICN protocol stack.")
+set(PACKAGE_HOMEPAGE "https://wiki.fd.io/view/Libicnet")
\ No newline at end of file
diff --git a/libtransport/cmake/Modules/Ios.cmake b/libtransport/cmake/Modules/Ios.cmake
new file mode 100755 (executable)
index 0000000..a4e625e
--- /dev/null
@@ -0,0 +1,23 @@
+# Copyright (c) 2017-2019 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.
+
+function (configure_ios_environment)
+  find_host_package ( OpenSSL REQUIRED )
+  include_directories(extras/iOS)
+
+  find_host_package(Libparc REQUIRED)
+  include_directories(${LIBPARC_INCLUDE_DIRS})
+
+  find_host_package(Libhicn REQUIRED)
+  include_directories(${HICN_INCLUDE_DIRS})
+endfunction()
\ No newline at end of file
diff --git a/libtransport/cmake/Modules/Packager.cmake b/libtransport/cmake/Modules/Packager.cmake
new file mode 100755 (executable)
index 0000000..019f18c
--- /dev/null
@@ -0,0 +1,197 @@
+# Copyright (c) 2017-2019 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.
+
+# Generate DEB / RPM packages
+
+# Default variables
+
+if (NOT DEFINED ENV{VENDOR})
+  set(VENDOR "Cisco Systems" CACHE STRING "Vendor")
+else ()
+  set(VENDOR ENV{VENDOR} CACHE STRING "Vendor")
+endif ()
+
+if (NOT DEFINED ENV{CONTACT})
+  set(CONTACT "msardara@cisco.com" CACHE STRING "Contact")
+else ()
+  set(CONTACT ENV{CONTACT} CACHE STRING "Contact")
+endif()
+
+if (NOT DEFINED ENV{PACKAGE_MAINTAINER})
+  set(PACKAGE_MAINTAINER "Mauro Sardara (msardara@cisco.com)" CACHE STRING "Maintainer")
+else ()
+  set(PACKAGE_MAINTAINER ENV{PACKAGE_MAINTAINER} CACHE STRING "Maintainer")
+endif()
+
+if (NOT DEFINED ENV{CPACK_PACKAGING_INSTALL_PREFIX})
+  set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+else ()
+  set(CPACK_PACKAGING_INSTALL_PREFIX ENV{CPACK_PACKAGING_INSTALL_PREFIX})
+endif()
+
+set(CPACK_COMPONENTS_ALL library headers utils documentation)
+
+function (make_package_internal PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE GENERATOR TYPE DESCRIPTION HOMEPAGE)
+  set(CPACK_GENERATOR ${GENERATOR})
+  set(CPACK_PACKAGE_VENDOR ${VENDOR})
+  set(CPACK_PACKAGE_CONTACT ${CONTACT})
+
+  set(CPACK_${GENERATOR}_COMPONENT_INSTALL ON)
+  set(CPACK_${TYPE}_PACKAGE_MAINTAINER ${PACKAGE_MAINTAINER})
+  set(CPACK_${TYPE}_PACKAGE_NAME ${PACKAGE_NAME})
+  set(CPACK_${TYPE}_PACKAGE_VERSION ${PACKAGE_VERSION})
+  set(CPACK_${TYPE}_PACKAGE_ARCHITECTURE ${ARCHITECTURE})
+  set(CPACK_${TYPE}_PACKAGE_RELEASE 1)
+  set(CPACK_${TYPE}_PACKAGE_VENDOR ${VENDOR})
+  set(CPACK_${TYPE}_PACKAGE_DESCRIPTION ${DESCRIPTION})
+  set(CPACK_${TYPE}_PACKAGE_HOMEPAGE ${HOMEPAGE})
+
+  include(CPack)
+endfunction()
+
+function(make_deb_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE DEPS BUILD_DEPS DESCRIPTION HOMEPAGE)
+
+  set(TYPE "DEBIAN")
+  set(GENERATOR "DEB")
+
+  set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+  set(CPACK_${TYPE}_UTILS_PACKAGE_NAME "${PACKAGE_NAME}-utils")
+  set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-dev")
+  set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+  set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+  set(CPACK_${TYPE}_UTILS_FILE_NAME "${CPACK_${TYPE}_UTILS_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+  set(CPACK_${TYPE}_HEADERS_FILE_NAME "${CPACK_${TYPE}_HEADERS_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+  set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}.deb")
+
+  set(CPACK_DEBIAN_LIBRARY_PACKAGE_SHLIBDEPS OFF)
+
+  set(CPACK_${TYPE}_LIBRARY_PACKAGE_DEPENDS ${DEPS})
+  set(CPACK_${TYPE}_UTILS_PACKAGE_DEPENDS ${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME})
+  set(CPACK_${TYPE}_HEADERS_PACKAGE_DEPENDS ${BUILD_DEPS})
+  set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_DEPENDS "")
+
+  make_package_internal(${PACKAGE_NAME} ${PACKAGE_VERSION} ${ARCHITECTURE} ${GENERATOR} ${TYPE} ${DESCRIPTION} ${HOMEPAGE})
+endfunction()
+
+function(make_rpm_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE DEPS BUILD_DEPS DESCRIPTION HOMEPAGE)
+  set(TYPE "RPM")
+  set(GENERATOR "RPM")
+
+  set(CPACK_${TYPE}_LIBRARY_PACKAGE_NAME "${PACKAGE_NAME}")
+  set(CPACK_${TYPE}_UTILS_PACKAGE_NAME "${PACKAGE_NAME}-utils")
+  set(CPACK_${TYPE}_HEADERS_PACKAGE_NAME "${PACKAGE_NAME}-devel")
+  set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME "${PACKAGE_NAME}-doc")
+
+  set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+  set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${CPACK_${TYPE}_UTILS_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+  set(CPACK_${TYPE}_HEADERS_FILE_NAME "${CPACK_${TYPE}_HEADERS_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+  set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${CPACK_${TYPE}_DOCUMENTATION_PACKAGE_NAME}-${PACKAGE_VERSION}.${ARCHITECTURE}.rpm")
+
+  set(CPACK_${TYPE}_LIBRARY_PACKAGE_AUTOREQ OFF)
+
+  set(CPACK_${TYPE}_LIBRARY_PACKAGE_REQUIRES ${DEPS})
+  set(CPACK_${TYPE}_UTILS_PACKAGE_DEPENDS ${CPACK_${TYPE}_LIBRARY_PACKAGE_NAME})
+  set(CPACK_${TYPE}_HEADERS_PACKAGE_REQUIRES ${BUILD_DEPS})
+  set(CPACK_${TYPE}_DOCUMENTATION_PACKAGE_REQUIRES "")
+
+  set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/etc" "/usr/lib/python2.7" "/usr/lib/python2.7/site-packages")
+
+  make_package_internal(${PACKAGE_NAME} ${PACKAGE_VERSION} ${ARCHITECTURE} ${GENERATOR} ${TYPE} ${DESCRIPTION} ${HOMEPAGE})
+endfunction()
+
+function(make_tgz_package PACKAGE_NAME PACKAGE_VERSION ARCHITECTURE)
+
+  set(TYPE "ARCHIVE")
+  set(GENERATOR "TGZ")
+
+  set(CPACK_${TYPE}_COMPONENT_INSTALL ON)
+  set(CPACK_${TYPE}_LIBRARY_FILE_NAME "${PACKAGE_NAME}_${PACKAGE_VERSION}_${ARCHITECTURE}")
+  set(CPACK_${TYPE}_UTILS_FILE_NAME "${PACKAGE_NAME}-utils_${PACKAGE_VERSION}_${ARCHITECTURE}")
+  set(CPACK_${TYPE}_HEADERS_FILE_NAME "${PACKAGE_NAME}-dev_${PACKAGE_VERSION}_${ARCHITECTURE}")
+  set(CPACK_${TYPE}_DOCUMENTATION_FILE_NAME "${PACKAGE_NAME}-doc_${PACKAGE_VERSION}_${ARCHITECTURE}")
+
+  set(CPACK_GENERATOR ${GENERATOR})
+  set(CPACK_PACKAGE_VENDOR ${VENDOR})
+  set(CPACK_PACKAGE_CONTACT ${CONTACT})
+
+  include(CPack)
+
+endfunction()
+
+function (make_package DEPS_DEB DEPS_RPM BUILD_DEPS_DEB BUILD_DEPS_RPM DESCRIPTION HOMEPAGE)
+
+  if (NOT DEFINED ENV{PACKAGE_NAME})
+    string(TOLOWER ${CMAKE_PROJECT_NAME} PACKAGE_NAME)
+  else ()
+    string(TOLOWER $ENV{PACKAGE_NAME} PACKAGE_NAME)
+  endif ()
+
+  # Get the version
+  execute_process(COMMAND bash ${CMAKE_SOURCE_DIR}/scripts/version
+    OUTPUT_VARIABLE PACKAGE_VERSION)
+
+  if (PACKAGE_VERSION)
+    string(STRIP ${PACKAGE_VERSION} PACKAGE_VERSION)
+  else ()
+    set(PACKAGE_VERSION 1.0)
+  endif ()
+
+  if (EXISTS "/etc/lsb-release")
+    execute_process(COMMAND grep -oP "(?<=DISTRIB_ID=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_ID)
+    execute_process(COMMAND grep -oP "(?<=DISTRIB_RELEASE=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_RELEASE)
+    execute_process(COMMAND grep -oP "(?<=DISTRIB_CODENAME=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_CODENAME)
+    execute_process(COMMAND grep -oP "(?<=DISTRIB_DESCRIPTION=).*" /etc/lsb-release OUTPUT_VARIABLE DISTRIB_DESCRIPTION)
+    execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+    if (${ARCHITECTURE} STREQUAL "x86_64")
+      set(ARCHITECTURE "amd64")
+    endif()
+
+    make_deb_package(${PACKAGE_NAME}
+                     ${PACKAGE_VERSION}
+                     ${ARCHITECTURE}
+                     ${DEPS_DEB}
+                     ${BUILD_DEPS_DEB}
+                     ${DESCRIPTION}
+                     ${HOMEPAGE})
+
+  elseif(EXISTS "/etc/redhat-release")
+    execute_process(COMMAND sudo yum install -y redhat-lsb)
+    execute_process(COMMAND lsb_release -si OUTPUT_VARIABLE DISTRIB_ID)
+    execute_process(COMMAND lsb_release -sr OUTPUT_VARIABLE DISTRIB_RELEASE)
+    execute_process(COMMAND lsb_release -sc OUTPUT_VARIABLE DISTRIB_CODENAME)
+    execute_process(COMMAND lsb_release -sd OUTPUT_VARIABLE DISTRIB_DESCRIPTION)
+    execute_process(COMMAND uname -m -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+    make_rpm_package(${PACKAGE_NAME}
+                     ${PACKAGE_VERSION}
+                     ${ARCHITECTURE}
+                     ${DEPS_RPM}
+                     ${BUILD_DEPS_RPM}
+                     ${DESCRIPTION}
+                     ${HOMEPAGE})
+  else()
+    execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE)
+
+    if (${ARCHITECTURE} STREQUAL "x86_64")
+      set(ARCHITECTURE "amd64")
+    endif()
+
+    # Other linux system. Create a tar.gz package
+    make_tgz_package(${PACKAGE_NAME}
+                     ${PACKAGE_VERSION}
+                     ${ARCHITECTURE})
+
+  endif()
+endfunction()
diff --git a/libtransport/cmake/Modules/TestMacros.cmake b/libtransport/cmake/Modules/TestMacros.cmake
new file mode 100755 (executable)
index 0000000..680b558
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2017-2019 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(CTest)
+
diff --git a/libtransport/src/hicn/transport/CMakeLists.txt b/libtransport/src/hicn/transport/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f3c1cd2
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+configure_file("config.h.in" "config.h" @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h DESTINATION include/hicn/transport COMPONENT libtransport-dev)
+
+add_subdirectory(core)
+add_subdirectory(errors)
+add_subdirectory(http)
+add_subdirectory(interfaces)
+add_subdirectory(portability)
+add_subdirectory(protocols)
+add_subdirectory(utils)
+
+set (COMPILER_DEFINITIONS "-DASIO_STANDALONE")
+
+list(APPEND LIBTRANSPORT_INCLUDE_DIRS
+  ${CMAKE_CURRENT_SOURCE_DIR}/../..
+  ${CMAKE_CURRENT_BINARY_DIR}/../..
+)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
+if (ANDROID_API)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -isystem -lm")
+endif()
+
+build_library(${LIBTRANSPORT}
+  STATIC SHARED
+  SOURCES ${SOURCE_FILES}
+  INSTALL_HEADERS ${HEADER_FILES}
+  LINK_LIBRARIES ${LIBRARIES}
+  DEPENDS ${DEPENDENCIES}
+  COMPONENT libtransport
+  INCLUDE_DIRS ${LIBTRANSPORT_INCLUDE_DIRS}
+  INSTALL_ROOT_DIR hicn/transport
+  DEFINITIONS ${COMPILER_DEFINITIONS}
+)
+
+if (${COMPILE_TESTS})
+  add_subdirectory(core/test)
+  add_subdirectory(transport/test)
+endif()
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/config.h.in b/libtransport/src/hicn/transport/config.h.in
new file mode 100755 (executable)
index 0000000..a140f4b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#cmakedefine TRANSPORT_HAVE_PTHREAD 1
+
+#define RAAQM_CONFIG_PATH "@raaqm_config_path@"
+
+#cmakedefine __vpp__
diff --git a/libtransport/src/hicn/transport/core/CMakeLists.txt b/libtransport/src/hicn/transport/core/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..c8dea83
--- /dev/null
@@ -0,0 +1,87 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/content_object.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/facade.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/interest.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/key_locator_type.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/manifest.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/manifest_inline.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/packet.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/payload_type.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/portal.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/prefix.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/connector.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/forwarder_interface.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/content_object.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/interest.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/key_locator.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/pending_interest.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/packet.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/name.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/prefix.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_connector.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/hicn_forwarder_interface.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/manifest_format_fixed.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/connector.cc
+)
+
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+  if (BUILD_WITH_VPP OR BUILD_VPP_PLUGIN)
+    list(APPEND HEADER_FILES
+      ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.h
+      ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.h
+      ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.h
+      ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.h
+      ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.h
+    )
+
+    list(APPEND SOURCE_FILES
+      ${CMAKE_CURRENT_SOURCE_DIR}/vpp_forwarder_interface.cc
+      ${CMAKE_CURRENT_SOURCE_DIR}/memif_connector.cc
+      ${CMAKE_CURRENT_SOURCE_DIR}/hicn_binary_api.c
+      ${CMAKE_CURRENT_SOURCE_DIR}/vpp_binary_api.c
+      ${CMAKE_CURRENT_SOURCE_DIR}/memif_binary_api.c
+    )
+  endif()
+
+  list(APPEND HEADER_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.h
+  )
+
+  list(APPEND SOURCE_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_connector.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/raw_socket_interface.cc
+  )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/connector.cc b/libtransport/src/hicn/transport/core/connector.cc
new file mode 100755 (executable)
index 0000000..ff567d7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/connector.h>
+
+namespace transport {
+
+namespace core {
+
+std::once_flag Connector::init_flag_;
+
+Connector::Connector() : packet_pool_() { init(); }
+
+void Connector::init() { increasePoolSize(); }
+
+void Connector::increasePoolSize(std::size_t size) {
+  // Allocate space for receiving packets
+  const auto capacity = packet_size * size;
+  uint8_t *buffer = static_cast<uint8_t *>(malloc(capacity));
+  std::unique_ptr<utils::MemBuf> buffer0 =
+      utils::MemBuf::takeOwnership(buffer, capacity, 0, nullptr, nullptr, true);
+
+  for (std::size_t i = 1; i < size; i++) {
+    auto b = buffer0->cloneOne();
+    b->advance(i * packet_size);
+    packet_pool_.add(b.release());
+  }
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/connector.h b/libtransport/src/hicn/transport/core/connector.h
new file mode 100755 (executable)
index 0000000..1420187
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/ring_buffer.h>
+
+#include <deque>
+#include <functional>
+
+namespace transport {
+
+namespace core {
+
+enum class ConnectorType : uint8_t {
+  SOCKET_CONNECTOR,
+  RAW_SOCKET_CONNECTOR,
+  VPP_CONNECTOR,
+};
+
+static constexpr std::size_t packet_size = 2000;
+static constexpr std::size_t queue_size = 4096;
+static constexpr std::size_t packet_pool_size = 4096;
+
+using PacketRing = utils::CircularFifo<Packet::MemBufPtr, queue_size>;
+using PacketQueue = std::deque<Packet::MemBufPtr>;
+using PacketReceivedCallback = std::function<void(Packet::MemBufPtr &&)>;
+using OnReconnect = std::function<void()>;
+using PacketSentCallback = std::function<void()>;
+
+class Connector {
+ public:
+  Connector();
+
+  virtual ~Connector() = default;
+
+  virtual void send(const Packet::MemBufPtr &packet) = 0;
+
+  virtual void send(const uint8_t *packet, std::size_t len,
+                    const PacketSentCallback &packet_sent = 0) = 0;
+
+  virtual void close() = 0;
+
+  virtual void enableBurst() = 0;
+
+  virtual void state() = 0;
+
+ protected:
+  void increasePoolSize(std::size_t size = packet_pool_size);
+
+  TRANSPORT_ALWAYS_INLINE utils::ObjectPool<utils::MemBuf>::Ptr getPacket() {
+    auto result = packet_pool_.get();
+
+    while (TRANSPORT_EXPECT_FALSE(!result.first)) {
+      // Add packets to the pool
+      increasePoolSize();
+      result = packet_pool_.get();
+    }
+
+    result.second->clear();
+    return std::move(result.second);
+  }
+
+ private:
+  void init();
+
+ protected:
+  static std::once_flag init_flag_;
+  utils::ObjectPool<utils::MemBuf> packet_pool_;
+  PacketQueue output_buffer_;
+};
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/content_object.cc b/libtransport/src/hicn/transport/core/content_object.cc
new file mode 100755 (executable)
index 0000000..dc20565
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/content_object.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+}
+
+#include <cstring>
+#include <memory>
+
+namespace transport {
+
+namespace core {
+
+ContentObject::ContentObject(const Name &name, Packet::Format format)
+    : Packet(format) {
+  if (TRANSPORT_EXPECT_FALSE(
+          hicn_data_set_name(format, (hicn_header_t *)packet_start_,
+                             name.getStructReference()) < 0)) {
+    throw errors::RuntimeException("Error filling the packet name.");
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(
+          hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0)) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+ContentObject::ContentObject(hicn_format_t format)
+    : ContentObject(Packet::base_name, format) {}
+
+ContentObject::ContentObject(const Name &name, hicn_format_t format,
+                             const uint8_t *payload, std::size_t size)
+    : ContentObject(name, format) {
+  appendPayload(payload, size);
+}
+
+ContentObject::ContentObject(const uint8_t *buffer, std::size_t size)
+    : Packet(buffer, size) {
+  if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                         name_.getStructReference()) < 0) {
+    throw errors::RuntimeException("Error getting name from content object.");
+  }
+}
+
+ContentObject::ContentObject(MemBufPtr &&buffer) : Packet(std::move(buffer)) {
+  if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                         name_.getStructReference()) < 0) {
+    throw errors::RuntimeException("Error getting name from content object.");
+  }
+}
+
+ContentObject::ContentObject(ContentObject &&other) : Packet(std::move(other)) {
+  name_ = std::move(other.name_);
+
+  if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                         name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+ContentObject::~ContentObject() {}
+
+const Name &ContentObject::getName() const {
+  if (!name_) {
+    if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                           (hicn_name_t *)name_.getStructReference()) < 0) {
+      throw errors::MalformedPacketException();
+    }
+  }
+
+  return name_;
+}
+
+ContentObject &ContentObject::setName(const Name &name) {
+  if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_,
+                         name.getStructReference()) < 0) {
+    throw errors::RuntimeException("Error setting content object name.");
+  }
+
+  if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                         name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+
+  return *this;
+}
+
+void ContentObject::setName(Name &&name) {
+  if (hicn_data_set_name(format_, (hicn_header_t *)packet_start_,
+                         name.getStructReference()) < 0) {
+    throw errors::RuntimeException(
+        "Error getting the payload length from content object.");
+  }
+
+  if (hicn_data_get_name(format_, (hicn_header_t *)packet_start_,
+                         name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+uint32_t ContentObject::getPathLabel() const {
+  uint32_t path_label;
+  if (hicn_data_get_path_label((hicn_header_t *)packet_start_, &path_label) <
+      0) {
+    throw errors::RuntimeException(
+        "Error retrieving the path label from content object");
+  }
+
+  return path_label;
+}
+
+ContentObject &ContentObject::setPathLabel(uint32_t path_label) {
+  if (hicn_data_set_path_label((hicn_header_t *)packet_start_, path_label) <
+      0) {
+    throw errors::RuntimeException(
+        "Error setting the path label from content object");
+  }
+
+  return *this;
+}
+
+void ContentObject::setLocator(const ip_address_t &ip_address) {
+  if (hicn_data_set_locator(format_, (hicn_header_t *)packet_start_,
+                            &ip_address) < 0) {
+    throw errors::RuntimeException("Error setting content object locator");
+  }
+
+  return;
+}
+
+ip_address_t ContentObject::getLocator() const {
+  ip_address_t ip;
+
+  if (hicn_data_get_locator(format_, (hicn_header_t *)packet_start_, &ip) < 0) {
+    throw errors::RuntimeException("Error getting content object locator.");
+  }
+
+  return ip;
+}
+
+void ContentObject::resetForHash() {
+  if (hicn_data_reset_for_hash(
+          format_, reinterpret_cast<hicn_header_t *>(packet_start_)) < 0) {
+    throw errors::RuntimeException(
+        "Error resetting content object fields for hash computation.");
+  }
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/content_object.h b/libtransport/src/hicn/transport/core/content_object.h
new file mode 100755 (executable)
index 0000000..c85259f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/packet.h>
+
+namespace transport {
+
+namespace core {
+
+// This class is used just to transfer buffer pointers
+// without making a copy, as std::vector<> would do
+
+class ContentObject : public Packet {
+ public:
+  using Ptr = utils::ObjectPool<ContentObject>::Ptr;
+  using HICNContentObject = hicn_header_t;
+
+  ContentObject(Packet::Format format = HF_INET6_TCP);
+
+  ContentObject(const Name &name, Packet::Format format = HF_INET6_TCP);
+
+  ContentObject(const Name &name, hicn_format_t format, const uint8_t *payload,
+                std::size_t payload_size);
+
+  ContentObject(const uint8_t *buffer, std::size_t size);
+  ContentObject(MemBufPtr &&buffer);
+
+  ContentObject(const ContentObject &content_object) = delete;
+
+  ContentObject(ContentObject &&content_object);
+
+  ~ContentObject() override;
+
+  const Name &getName() const;
+
+  ContentObject &setName(const Name &name);
+
+  void setName(Name &&name);
+
+  uint32_t getPathLabel() const;
+
+  ContentObject &setPathLabel(uint32_t path_label);
+
+  void setLocator(const ip_address_t &ip_address) override;
+
+  ip_address_t getLocator() const override;
+
+ private:
+  void resetForHash() override;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/facade.h b/libtransport/src/hicn/transport/core/facade.h
new file mode 100755 (executable)
index 0000000..c28c846
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/hicn_forwarder_interface.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/portal.h>
+
+#ifdef __linux__
+#ifndef __ANDROID__
+#include <hicn/transport/core/raw_socket_interface.h>
+#ifdef __vpp__
+#include <hicn/transport/core/vpp_forwarder_interface.h>
+#endif
+#endif
+#endif
+
+namespace transport {
+
+namespace core {
+
+using HicnForwarderPortal = Portal<HicnForwarderInterface>;
+
+#ifdef __linux__
+#ifndef __ANDROID_API__
+using RawSocketPortal = Portal<RawSocketInterface>;
+#endif
+#ifdef __vpp__
+using VPPForwarderPortal = Portal<VPPForwarderInterface>;
+#endif
+#endif
+
+using ContentObjectManifest = core::ManifestInline<ContentObject, Fixed>;
+using InterestManifest = core::ManifestInline<Interest, Fixed>;
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/forwarder_interface.h b/libtransport/src/hicn/transport/core/forwarder_interface.h
new file mode 100755 (executable)
index 0000000..e7b6fb1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/portability/portability.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+typedef struct {
+  uint64_t rx_packets;
+  uint64_t tx_packets;
+  uint64_t rx_bytes;
+  uint64_t tx_bytes;
+  uint64_t rx_errors;
+  uint64_t tx_errors;
+} Counters;
+
+template <typename Implementation, typename ConnectorType>
+class ForwarderInterface {
+  static_assert(std::is_base_of<Connector, ConnectorType>::value,
+                "T must inherit from connector!");
+
+  static constexpr uint32_t standard_cs_reserved = 5000;
+
+ protected:
+  ForwarderInterface(ConnectorType &c)
+      : connector_(c),
+        inet_address_({}),
+        inet6_address_({}),
+        mtu_(1500),
+        output_interface_(""),
+        content_store_reserved_(standard_cs_reserved) {
+    inet_address_.family = AF_INET;
+    inet6_address_.family = AF_INET6;
+  }
+
+ public:
+  static constexpr uint8_t ack_code = 102;
+
+  virtual ~ForwarderInterface() {}
+
+  TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) {
+    static_cast<Implementation &>(*this).connect(is_consumer);
+  }
+
+  TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) {
+    static_cast<Implementation &>(*this).registerRoute();
+  }
+
+  TRANSPORT_ALWAYS_INLINE std::uint32_t getMtu() {
+    return static_cast<Implementation &>(*this).getMtu();
+  }
+
+  template <
+      typename R,
+      typename = std::enable_if_t<
+          std::is_base_of<Packet, typename std::remove_reference_t<R>>::value,
+          R>>
+  TRANSPORT_ALWAYS_INLINE void send(R &&packet) {
+    counters_.tx_packets++;
+    counters_.tx_bytes += packet.payloadSize() + packet.headerSize();
+
+    if (_is_ipv4(packet.getFormat())) {
+      packet.setLocator(inet_address_);
+    } else {
+      packet.setLocator(inet6_address_);
+    }
+
+    packet.setChecksum();
+    connector_.send(packet.data());
+  }
+
+  template <typename Handler>
+  TRANSPORT_ALWAYS_INLINE void send(const uint8_t *packet, std::size_t len,
+                                    Handler &&packet_sent) {
+    // ASIO_COMPLETION_HANDLER_CHECK(Handler, packet_sent) type_check;
+    counters_.tx_packets++;
+    counters_.tx_bytes += len;
+
+    // Perfect forwarding
+    connector_.send(packet, len, std::forward<Handler>(packet_sent));
+  }
+
+  TRANSPORT_ALWAYS_INLINE void shutdown() { connector_.close(); }
+
+  TRANSPORT_ALWAYS_INLINE Connector &getConnector() { return connector_; }
+
+  TRANSPORT_ALWAYS_INLINE void setContentStoreSize(uint32_t cs_size) {
+    content_store_reserved_ = cs_size;
+  }
+
+  TRANSPORT_ALWAYS_INLINE uint32_t getContentStoreSize() const {
+    return content_store_reserved_;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void setOutputInterface(
+      const std::string &interface) {
+    output_interface_ = interface;
+  }
+
+  TRANSPORT_ALWAYS_INLINE std::string &getOutputInterface() {
+    return output_interface_;
+  }
+
+ protected:
+  ConnectorType &connector_;
+  ip_address_t inet_address_;
+  ip_address_t inet6_address_;
+  uint16_t mtu_;
+  std::string output_interface_;
+  uint32_t content_store_reserved_;
+  Counters counters_;
+};
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.c b/libtransport/src/hicn/transport/core/hicn_binary_api.c
new file mode 100755 (executable)
index 0000000..c49cb5c
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vlib/vlib.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vppinfra/error.h>
+
+#include <vnet/ip/format.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+
+#include <vpp_plugins/hicn/error.h>
+#include <vpp_plugins/hicn/hicn_api.h>
+
+// uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <hicn/hicn_msg_enum.h>
+
+#define vl_endianfun /* define message structures */
+#define vl_print(handle, ...)
+#define vl_printfun
+#define vl_api_version(n, v) static u32 api_version = (v);
+#define vl_msg_name_crc_list
+#include <hicn/hicn_all_api_h.h>
+#undef vl_msg_name_crc_list
+#undef vl_api_version
+#undef vl_printfun
+#undef vl_endianfun
+
+/////////////////////////////////////////////////////
+const char *HICN_ERROR_STRING[] = {
+#define _(a, b, c) c,
+    foreach_hicn_error
+#undef _
+};
+/////////////////////////////////////////////////////
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+#define CONTEXT_SAVE(pointer, mp)                             \
+  do {                                                        \
+    global_pointers_map[global_pointers_map_index] = pointer; \
+    mp->context = global_pointers_map_index++;                \
+    global_pointers_map_index %= POINTER_MAP_SIZE;            \
+  } while (0);
+
+#define CONTEXT_GET(mp, pointer)                \
+  do {                                          \
+    pointer = global_pointers_map[mp->context]; \
+  } while (0);
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_hicn_api_reply_msg                                      \
+  _(HICN_API_REGISTER_PROD_APP_REPLY, hicn_api_register_prod_app_reply) \
+  _(HICN_API_REGISTER_CONS_APP_REPLY, hicn_api_register_cons_app_reply) \
+  _(HICN_API_ROUTE_NHOPS_ADD_REPLY, hicn_api_route_nhops_add_reply)
+
+int hicn_binary_api_register_prod_app(
+    vpp_plugin_binary_api_t *api, hicn_producer_input_params *input_params,
+    hicn_producer_output_params *output_params) {
+  vl_api_hicn_api_register_prod_app_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+  api->vpp_api->user_param = output_params;
+
+  /* Construct the API message */
+  M(HICN_API_REGISTER_PROD_APP, mp);
+
+  CONTEXT_SAVE(api, mp)
+
+  mp->len = (u8)input_params->prefix.prefix_length;
+  mp->swif = clib_host_to_net_u32(input_params->swif);
+  mp->cs_reserved = clib_host_to_net_u32(input_params->cs_reserved);
+
+  mp->prefix[0] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[0]);
+  mp->prefix[1] = clib_host_to_net_u64(input_params->prefix.ip6.as_u64[1]);
+
+  TRANSPORT_LOGI("Prefix length: %u", mp->len);
+  TRANSPORT_LOGI("Memif ID: %u", mp->swif);
+
+  return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_register_prod_app_reply_t_handler(
+    vl_api_hicn_api_register_prod_app_reply_t *mp) {
+  vpp_plugin_binary_api_t *binary_api;
+  CONTEXT_GET(mp, binary_api);
+  hicn_producer_output_params *params = binary_api->vpp_api->user_param;
+
+  binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+  params->cs_reserved = mp->cs_reserved;
+  params->prod_addr.ip6.as_u64[0] = mp->prod_addr[0];
+  params->prod_addr.ip6.as_u64[1] = mp->prod_addr[1];
+  params->face_id = clib_net_to_host_u32(mp->faceid);
+
+  TRANSPORT_LOGI("ret :%s", get_error_string(binary_api->vpp_api->ret_val));
+
+  vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+int hicn_binary_api_register_cons_app(
+    vpp_plugin_binary_api_t *api, hicn_consumer_input_params *input_params,
+    hicn_consumer_output_params *output_params) {
+  vl_api_hicn_api_register_cons_app_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+
+  hm->vpp_api->user_param = output_params;
+
+  /* Construct the API message */
+  M(HICN_API_REGISTER_CONS_APP, mp);
+
+  mp->swif = clib_host_to_net_u32(input_params->swif);
+
+  CONTEXT_SAVE(api, mp)
+
+  TRANSPORT_LOGI("Message created");
+
+  return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_register_cons_app_reply_t_handler(
+    vl_api_hicn_api_register_cons_app_reply_t *mp) {
+  vpp_plugin_binary_api_t *binary_api;
+  CONTEXT_GET(mp, binary_api);
+  hicn_consumer_output_params *params = binary_api->vpp_api->user_param;
+
+  binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+
+  params->src4.ip4.as_u32 = clib_net_to_host_u32(mp->src_addr4);
+  params->src6.ip6.as_u64[0] = clib_net_to_host_u64(mp->src_addr6[0]);
+  params->src6.ip6.as_u64[1] = clib_net_to_host_u64(mp->src_addr6[1]);
+  params->face_id = clib_host_to_net_u32(mp->faceid);
+
+  vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+int hicn_binary_api_register_route(
+    vpp_plugin_binary_api_t *api,
+    hicn_producer_set_route_params *input_params) {
+  vl_api_hicn_api_route_nhops_add_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+
+  /* Construct the API message */
+  M(HICN_API_ROUTE_NHOPS_ADD, mp);
+
+  CONTEXT_SAVE(api, mp)
+
+  mp->prefix[0] = input_params->prefix.ip6.as_u64[0];
+  mp->prefix[1] = input_params->prefix.ip6.as_u64[1];
+  mp->len = input_params->prefix.prefix_length;
+  mp->face_ids[0] = input_params->face_id;
+  mp->n_faces = 1;
+
+  return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_hicn_api_route_nhops_add_reply_t_handler(
+    vl_api_hicn_api_route_nhops_add_reply_t *mp) {
+  vpp_plugin_binary_api_t *binary_api;
+  CONTEXT_GET(mp, binary_api);
+
+  binary_api->vpp_api->ret_val = clib_net_to_host_u32(mp->retval);
+
+  vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static int hicn_binary_api_setup_handlers(vpp_plugin_binary_api_t *binary_api) {
+  vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api;
+#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_hicn_api_reply_msg;
+#undef _
+  return 0;
+}
+
+char *hicn_binary_api_get_error_string(int ret_val) {
+  return get_error_string(ret_val);
+}
+
+vpp_plugin_binary_api_t *hicn_binary_api_init(vpp_binary_api_t *api) {
+  vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t));
+  u8 *name = format(0, "hicn_%08x%c", api_version, 0);
+  ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name);
+  ret->vpp_api = api;
+  ret->my_client_index = api->my_client_index;
+  hicn_binary_api_setup_handlers(ret);
+  return ret;
+}
+
+#endif  // __vpp__
diff --git a/libtransport/src/hicn/transport/core/hicn_binary_api.h b/libtransport/src/hicn/transport/core/hicn_binary_api.h
new file mode 100755 (executable)
index 0000000..7528441
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/vpp_binary_api.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdint.h"
+
+typedef union {
+  uint8_t data[4];
+  uint32_t data_u32;
+  /* Aliases. */
+  uint8_t as_u8[4];
+  uint16_t as_u16[2];
+  uint32_t as_u32;
+} ip4_address;
+
+typedef union {
+  uint8_t as_u8[16];
+  uint16_t as_u16[8];
+  uint32_t as_u32[4];
+  uint64_t as_u64[2];
+} ip6_address;
+
+typedef enum { IP_TYPE_ANY, IP_TYPE_IP4, IP_TYPE_IP6 } ip46_type;
+
+typedef struct {
+  ip46_type type;
+  uint8_t prefix_length;
+  union {
+    ip4_address ip4;
+    ip6_address ip6;
+  };
+} ip46_address;
+
+typedef struct {
+  ip46_address prefix;
+  uint32_t swif;
+  uint32_t cs_reserved;
+} hicn_producer_input_params;
+
+typedef struct {
+  uint32_t swif;
+} hicn_consumer_input_params;
+
+typedef struct {
+  uint32_t cs_reserved;
+  ip46_address prod_addr;
+  uint32_t face_id;
+} hicn_producer_output_params;
+
+typedef struct {
+  ip46_address src4;
+  ip46_address src6;
+  uint32_t face_id;
+} hicn_consumer_output_params;
+
+typedef struct {
+  ip46_address prefix;
+  uint32_t face_id;
+} hicn_producer_set_route_params;
+
+vpp_plugin_binary_api_t* hicn_binary_api_init(vpp_binary_api_t* api);
+
+int hicn_binary_api_register_prod_app(
+    vpp_plugin_binary_api_t* api, hicn_producer_input_params* input_params,
+    hicn_producer_output_params* output_params);
+
+int hicn_binary_api_register_cons_app(
+    vpp_plugin_binary_api_t* api, hicn_consumer_input_params* input_params,
+    hicn_consumer_output_params* output_params);
+
+int hicn_binary_api_register_route(
+    vpp_plugin_binary_api_t* api, hicn_producer_set_route_params* input_params);
+
+char* hicn_binary_api_get_error_string(int ret_val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.cc
new file mode 100755 (executable)
index 0000000..03a2949
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/hicn_forwarder_interface.h>
+
+#define ADDR_INET 1
+#define ADDR_INET6 2
+#define ADD_ROUTE 3
+#define REQUEST_LIGHT 100
+
+union AddressLight {
+  uint32_t ipv4;
+  struct in6_addr ipv6;
+};
+
+typedef struct {
+  uint8_t message_type;
+  uint8_t command_id;
+  uint16_t length;
+  uint32_t seq_num;
+  char symbolic_or_connid[16];
+  union AddressLight address;
+  uint16_t cost;
+  uint8_t address_type;
+  uint8_t len;
+} RouteToSelfCommand;
+
+namespace transport {
+
+namespace core {
+
+HicnForwarderInterface::HicnForwarderInterface(SocketConnector &connector)
+    : ForwarderInterface<HicnForwarderInterface, SocketConnector>(connector) {}
+
+HicnForwarderInterface::~HicnForwarderInterface() {}
+
+void HicnForwarderInterface::connect(bool is_consumer) { connector_.connect(); }
+
+void HicnForwarderInterface::registerRoute(Prefix &prefix) {
+  auto addr = prefix.toSockaddr();
+  const char *identifier = {"SELF_ROUTE"};
+
+  // allocate command payload
+  RouteToSelfCommand *route_to_self = new RouteToSelfCommand();
+
+  // check and set IP address
+  if (addr->sa_family == AF_INET) {
+    route_to_self->address_type = ADDR_INET;
+    route_to_self->address.ipv4 = ((Sockaddr4 *)addr.get())->sin_addr.s_addr;
+  } else if (addr->sa_family == AF_INET6) {
+    route_to_self->address_type = ADDR_INET6;
+    route_to_self->address.ipv6 = ((Sockaddr6 *)addr.get())->sin6_addr;
+  }
+
+  // Fill remaining payload fields
+  strcpy(route_to_self->symbolic_or_connid, identifier);
+  route_to_self->cost = 1;
+  route_to_self->len = prefix.getPrefixLength();
+
+  // Allocate and fill the header
+  route_to_self->command_id = ADD_ROUTE;
+  route_to_self->message_type = REQUEST_LIGHT;
+  route_to_self->length = 1;
+  // route_to_self->seq_num not needed for now
+
+  send((uint8_t *)route_to_self, sizeof(RouteToSelfCommand),
+       [route_to_self]() { delete route_to_self; });
+}
+
+}  // namespace core
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h b/libtransport/src/hicn/transport/core/hicn_forwarder_interface.h
new file mode 100755 (executable)
index 0000000..e57fae1
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class HicnForwarderInterface
+    : public ForwarderInterface<HicnForwarderInterface, SocketConnector> {
+ public:
+  union addressLight {
+    uint32_t ipv4;
+    struct in6_addr ipv6;
+  };
+
+  struct route_to_self_command {
+    uint8_t messageType;
+    uint8_t commandID;
+    uint16_t length;
+    uint32_t seqNum;
+    char symbolicOrConnid[16];
+    union addressLight address;
+    uint16_t cost;
+    uint8_t addressType;
+    uint8_t len;
+  };
+
+  using route_to_self_command = struct route_to_self_command;
+  using ConnectorType = SocketConnector;
+
+  HicnForwarderInterface(SocketConnector &connector);
+
+  ~HicnForwarderInterface();
+
+  void connect(bool is_consumer);
+
+  void registerRoute(Prefix &prefix);
+
+  std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+  static constexpr std::uint16_t interface_mtu = 1500;
+};
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/hicn_memif_api.c b/libtransport/src/hicn/transport/core/hicn_memif_api.c
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/libtransport/src/hicn/transport/core/interest.cc b/libtransport/src/hicn/transport/core/interest.cc
new file mode 100755 (executable)
index 0000000..ff4a5bb
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/interest.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/hash.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+}
+
+#include <cstring>
+#include <memory>
+
+namespace transport {
+
+namespace core {
+
+Interest::Interest(const Name &interest_name, Packet::Format format)
+    : Packet(format) {
+  if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+                             interest_name.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+
+  if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+Interest::Interest(hicn_format_t format) : Interest(base_name, format) {}
+
+Interest::Interest(const uint8_t *buffer, std::size_t size)
+    : Packet(buffer, size) {
+  if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+Interest::Interest(MemBufPtr &&buffer) : Packet(std::move(buffer)) {
+  if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+Interest::Interest(Interest &&other_interest)
+    : Packet(std::move(other_interest)) {
+  name_ = std::move(other_interest.name_);
+}
+
+Interest::~Interest() {}
+
+const Name &Interest::getName() const {
+  if (!name_) {
+    if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                               (hicn_name_t *)name_.getStructReference()) < 0) {
+      throw errors::MalformedPacketException();
+    }
+  }
+
+  return name_;
+}
+
+Name &Interest::getWritableName() {
+  if (!name_) {
+    if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                               (hicn_name_t *)name_.getStructReference()) < 0) {
+      throw errors::MalformedPacketException();
+    }
+  }
+
+  return name_;
+}
+
+Interest &Interest::setName(const Name &name) {
+  if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+                             name.getStructReference()) < 0) {
+    throw errors::RuntimeException("Error setting interest name.");
+  }
+
+  if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+
+  return *this;
+}
+
+Interest &Interest::setName(Name &&name) {
+  if (hicn_interest_set_name(format_, (hicn_header_t *)packet_start_,
+                             name.getStructReference()) < 0) {
+    throw errors::RuntimeException("Error setting interest name.");
+  }
+
+  if (hicn_interest_get_name(format_, (hicn_header_t *)packet_start_,
+                             name_.getStructReference()) < 0) {
+    throw errors::MalformedPacketException();
+  }
+
+  return *this;
+}
+
+void Interest::setLocator(const ip_address_t &ip_address) {
+  if (hicn_interest_set_locator(format_, (hicn_header_t *)packet_start_,
+                                &ip_address) < 0) {
+    throw errors::RuntimeException("Error setting interest locator.");
+  }
+
+  return;
+}
+
+ip_address_t Interest::getLocator() const {
+  ip_address_t ip;
+
+  if (hicn_interest_get_locator(format_, (hicn_header_t *)packet_start_, &ip) <
+      0) {
+    throw errors::RuntimeException("Error getting interest locator.");
+  }
+
+  return ip;
+}
+
+void Interest::resetForHash() {
+  if (hicn_interest_reset_for_hash(
+          format_, reinterpret_cast<hicn_header_t *>(packet_start_)) < 0) {
+    throw errors::RuntimeException(
+        "Error resetting interest fields for hash computation.");
+  }
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/interest.h b/libtransport/src/hicn/transport/core/interest.h
new file mode 100755 (executable)
index 0000000..75fcba8
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/object_pool.h>
+
+namespace transport {
+
+namespace core {
+
+class Interest
+    : public Packet /*, public std::enable_shared_from_this<Interest>*/ {
+ public:
+  using Ptr = utils::ObjectPool<Interest>::Ptr;
+
+  Interest(Packet::Format format = HF_INET6_TCP);
+
+  Interest(const Name &interest_name, Packet::Format format = HF_INET6_TCP);
+
+  Interest(const uint8_t *buffer, std::size_t size);
+  Interest(MemBufPtr &&buffer);
+
+  /*
+   * Enforce zero-copy.
+   */
+  Interest(const Interest &other_interest) = delete;
+  Interest &operator=(const Interest &other_interest) = delete;
+
+  Interest(Interest &&other_interest);
+
+  ~Interest() override;
+
+  const Name &getName() const;
+
+  Name &getWritableName();
+
+  Interest &setName(const Name &name);
+
+  Interest &setName(Name &&name);
+
+  void setLocator(const ip_address_t &ip_address) override;
+
+  ip_address_t getLocator() const override;
+
+ private:
+  void resetForHash() override;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/key_locator.cc b/libtransport/src/hicn/transport/core/key_locator.cc
new file mode 100755 (executable)
index 0000000..509fc35
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/key_locator.h>
+
+namespace transport {
+
+namespace core {
+
+KeyLocator::KeyLocator() : type_(KeyLocatorType::UNKNOWN) {}
+
+KeyLocator::KeyLocator(KeyLocatorType type, Name &name)
+    : type_(type), name_(name) {}
+
+Name &KeyLocator::getName() { return name_; }
+
+void KeyLocator::setName(Name &name) { name_ = name; }
+
+void KeyLocator::setType(KeyLocatorType type) { type_ = type; }
+
+KeyLocatorType KeyLocator::getType() { return type_; }
+
+void KeyLocator::clear() {
+  type_ = KeyLocatorType::UNKNOWN;
+  name_.clear();
+}
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/key_locator.h b/libtransport/src/hicn/transport/core/key_locator.h
new file mode 100755 (executable)
index 0000000..ae3a4ab
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/key_locator_type.h>
+#include <hicn/transport/core/name.h>
+
+namespace transport {
+
+namespace core {
+
+class KeyLocator : public std::enable_shared_from_this<KeyLocator> {
+ public:
+  KeyLocator();
+
+  KeyLocator(KeyLocatorType type, Name &name);
+
+  KeyLocatorType getType();
+
+  void setType(KeyLocatorType type);
+
+  void setName(Name &name);
+
+  Name &getName();
+
+  void clear();
+
+ private:
+  KeyLocatorType type_;
+  Name name_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/key_locator_type.h b/libtransport/src/hicn/transport/core/key_locator_type.h
new file mode 100755 (executable)
index 0000000..0c84a43
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace core {
+
+enum Type { NAME = 0, KEY_DIGEST = 1, UNKNOWN = 255 };
+
+typedef enum Type KeyLocatorType;
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/manifest.cc b/libtransport/src/hicn/transport/core/manifest.cc
new file mode 100755 (executable)
index 0000000..3f890f3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest.h>
+
+namespace transport {
+
+namespace core {
+
+std::string ManifestEncoding::manifest_type = std::string("manifest_type");
+
+std::map<ManifestType, std::string> ManifestEncoding::manifest_types = {
+    {FINAL_CHUNK_NUMBER, "FinalChunkNumber"}, {NAME_LIST, "NameList"}};
+
+std::string ManifestEncoding::final_chunk_number =
+    std::string("final_chunk_number");
+std::string ManifestEncoding::content_name = std::string("content_name");
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest.h b/libtransport/src/hicn/transport/core/manifest.h
new file mode 100755 (executable)
index 0000000..767addb
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+#include <set>
+
+namespace transport {
+
+namespace core {
+
+using typename core::Name;
+using typename core::Packet;
+using typename core::PayloadType;
+
+template <typename Base, typename FormatTraits, typename ManifestImpl>
+class Manifest : public Base {
+  static_assert(std::is_base_of<Packet, Base>::value,
+                "Base must inherit from packet!");
+
+ public:
+  using Encoder = typename FormatTraits::Encoder;
+  using Decoder = typename FormatTraits::Decoder;
+
+  Manifest()
+      : packet_(new Base(HF_INET6_TCP_AH), nullptr),
+        encoder_(*packet_),
+        decoder_(*packet_) {
+    Base::setPayloadType(PayloadType::MANIFEST);
+  }
+
+  Manifest(const core::Name& name)
+      : packet_(new Base(name, HF_INET6_TCP_AH), nullptr),
+        encoder_(*packet_),
+        decoder_(*packet_) {
+    Base::setPayloadType(PayloadType::MANIFEST);
+  }
+
+  Manifest(typename Base::Ptr&& base)
+      : packet_(std::move(base)), encoder_(*packet_), decoder_(*packet_) {
+    Base::setPayloadType(PayloadType::MANIFEST);
+  }
+
+  template <typename T>
+  Manifest(T&& base)
+      : packet_(new Base(std::move<T&&>(base)), nullptr),
+        encoder_(*packet_),
+        decoder_(*packet_) {
+    Base::setPayloadType(PayloadType::MANIFEST);
+  }
+
+  virtual ~Manifest() = default;
+
+  bool operator==(const Manifest& other) {
+    return this->packet_ == other.packet_;
+  }
+
+  std::size_t estimateManifestSize(std::size_t additional_entries = 0) {
+    return static_cast<ManifestImpl&>(*this).estimateManifestSizeImpl(
+        additional_entries);
+  }
+
+  /*
+   * After the call to encode, users MUST call clear before adding data
+   * to the manifest.
+   */
+  Manifest& encode() { return static_cast<ManifestImpl&>(*this).encodeImpl(); }
+
+  Manifest& decode() {
+    Manifest::decoder_.decode();
+
+    manifest_type_ = decoder_.getManifestType();
+    hash_algorithm_ = decoder_.getHashAlgorithm();
+    is_last_ = decoder_.getIsFinalManifest();
+
+    return static_cast<ManifestImpl&>(*this).decodeImpl();
+  }
+
+  static std::size_t getManifestHeaderSize() {
+    return Encoder::getManifestHeaderSize();
+  }
+
+  Manifest& setManifestType(ManifestType type) {
+    manifest_type_ = type;
+    encoder_.setManifestType(manifest_type_);
+    return *this;
+  }
+
+  Manifest& setHashAlgorithm(HashAlgorithm hash_algorithm) {
+    hash_algorithm_ = hash_algorithm;
+    encoder_.setHashAlgorithm(hash_algorithm_);
+    return *this;
+  }
+
+  HashAlgorithm getHashAlgorithm() { return hash_algorithm_; }
+
+  ManifestType getManifestType() const { return manifest_type_; }
+
+  bool isFinalManifest() const { return is_last_; }
+
+  Manifest& setVersion(ManifestVersion version) {
+    encoder_.setVersion(version);
+    return *this;
+  }
+
+  Manifest& setFinalBlockNumber(std::uint32_t final_block_number) {
+    encoder_.setFinalBlockNumber(final_block_number);
+    return *this;
+  }
+
+  uint32_t getFinalBlockNumber() const {
+    return decoder_.getFinalBlockNumber();
+  }
+
+  ManifestVersion getVersion() const { return decoder_.getVersion(); }
+
+  Manifest& setFinalManifest(bool is_final_manifest) {
+    encoder_.setIsFinalManifest(is_final_manifest);
+    is_last_ = is_final_manifest;
+    return *this;
+  }
+
+  Manifest& clear() {
+    encoder_.clear();
+    decoder_.clear();
+    return *this;
+  }
+
+  void setSignatureSize(std::size_t size_bits) {
+    Packet::setSignatureSize(size_bits);
+    encoder_.update();
+  }
+
+  typename Base::Ptr&& getPacket() { return std::move(packet_); }
+
+ protected:
+  typename Base::Ptr packet_;
+  ManifestType manifest_type_;
+  HashAlgorithm hash_algorithm_;
+  bool is_last_;
+
+  Encoder encoder_;
+  Decoder decoder_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format.h b/libtransport/src/hicn/transport/core/manifest_format.h
new file mode 100755 (executable)
index 0000000..1dcf013
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/crypto_hasher.h>
+
+#include <cinttypes>
+#include <type_traits>
+#include <unordered_map>
+
+namespace transport {
+
+namespace core {
+
+enum class ManifestFields : uint8_t {
+  VERSION,
+  HASH_ALGORITHM,
+  SEGMENT_CALCULATION_STRATEGY,
+  FINAL_MANIFEST,
+  NAME_HASH_LIST,
+  BASE_NAME
+};
+
+enum class ManifestVersion : uint8_t {
+  VERSION_1 = 1,
+};
+
+enum class ManifestType : uint8_t {
+  INLINE_MANIFEST = 1,
+  FINAL_CHUNK_NUMBER = 2,
+  FLIC_MANIFEST = 3,
+};
+
+enum class HashAlgorithm : uint8_t {
+  SHA_256 = static_cast<uint8_t>(utils::CryptoHashType::SHA_256),
+  SHA_512 = static_cast<uint8_t>(utils::CryptoHashType::SHA_512),
+  CRC32C = static_cast<uint8_t>(utils::CryptoHashType::CRC32C),
+};
+
+enum class NextSegmentCalculationStrategy : uint8_t {
+  INCREMENTAL = 1,
+};
+
+template <typename T>
+struct format_traits {
+  using Encoder = typename T::Encoder;
+  using Decoder = typename T::Decoder;
+  using HashType = typename T::HashType;
+  using HashList = typename T::HashList;
+};
+
+class Packet;
+
+template <typename Implementation>
+class ManifestEncoder {
+ public:
+  virtual ~ManifestEncoder() = default;
+
+  ManifestEncoder encode() {
+    return static_cast<Implementation&>(*this).encodeImpl();
+  }
+
+  ManifestEncoder& clear() {
+    return static_cast<Implementation&>(*this).clearImpl();
+  }
+
+  ManifestEncoder& setManifestType(ManifestType type) {
+    return static_cast<Implementation&>(*this).setManifestTypeImpl(type);
+  }
+
+  ManifestEncoder& setHashAlgorithm(HashAlgorithm hash) {
+    return static_cast<Implementation&>(*this).setHashAlgorithmImpl(hash);
+  }
+
+  ManifestEncoder& setFinalChunkNumber(uint32_t final_chunk) {
+    return static_cast<Implementation&>(*this).setFinalChunkImpl(final_chunk);
+  }
+
+  ManifestEncoder& setNextSegmentCalculationStrategy(
+      NextSegmentCalculationStrategy strategy) {
+    return static_cast<Implementation&>(*this)
+        .setNextSegmentCalculationStrategyImpl(strategy);
+  }
+
+  template <
+      typename T,
+      typename = std::enable_if_t<std::is_same<
+          std::remove_const_t<std::remove_reference_t<T>>, core::Name>::value>>
+  ManifestEncoder& setBaseName(T&& name) {
+    return static_cast<Implementation&>(*this).setBaseNameImpl(name);
+  }
+
+  template <typename Hash>
+  ManifestEncoder& addSuffixAndHash(uint32_t suffix, Hash&& hash) {
+    return static_cast<Implementation&>(*this).addSuffixAndHashImpl(
+        suffix, std::forward<Hash&&>(hash));
+  }
+
+  ManifestEncoder& setIsFinalManifest(bool is_last) {
+    return static_cast<Implementation&>(*this).setIsFinalManifestImpl(is_last);
+  }
+
+  ManifestEncoder& setVersion(ManifestVersion version) {
+    return static_cast<Implementation&>(*this).setVersionImpl(version);
+  }
+
+  std::size_t estimateSerializedLength(std::size_t number_of_entries) {
+    return static_cast<Implementation&>(*this).estimateSerializedLengthImpl(
+        number_of_entries);
+  }
+
+  ManifestEncoder& update() {
+    return static_cast<Implementation&>(*this).updateImpl();
+  }
+
+  ManifestEncoder& setFinalBlockNumber(std::uint32_t final_block_number) {
+    return static_cast<Implementation&>(*this).setFinalBlockNumberImpl(
+        final_block_number);
+  }
+
+  static std::size_t getManifestHeaderSize() {
+    return Implementation::getManifestHeaderSizeImpl();
+  }
+};
+
+template <typename Implementation>
+class ManifestDecoder {
+ public:
+  virtual ~ManifestDecoder() = default;
+
+  ManifestDecoder& clear() {
+    return static_cast<Implementation&>(*this).clearImpl();
+  }
+
+  void decode() { static_cast<Implementation&>(*this).decodeImpl(); }
+
+  ManifestType getManifestType() const {
+    return static_cast<const Implementation&>(*this).getManifestTypeImpl();
+  }
+
+  HashAlgorithm getHashAlgorithm() const {
+    return static_cast<const Implementation&>(*this).getHashAlgorithmImpl();
+  }
+
+  uint32_t getFinalChunkNumber() const {
+    return static_cast<const Implementation&>(*this).getFinalChunkImpl();
+  }
+
+  NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() const {
+    return static_cast<const Implementation&>(*this)
+        .getNextSegmentCalculationStrategyImpl();
+  }
+
+  core::Name getBaseName() const {
+    return static_cast<const Implementation&>(*this).getBaseNameImpl();
+  }
+
+  auto getSuffixHashList() {
+    return static_cast<Implementation&>(*this).getSuffixHashListImpl();
+  }
+
+  bool getIsFinalManifest() const {
+    return static_cast<const Implementation&>(*this).getIsFinalManifestImpl();
+  }
+
+  ManifestVersion getVersion() const {
+    return static_cast<const Implementation&>(*this).getVersionImpl();
+  }
+
+  std::size_t estimateSerializedLength(std::size_t number_of_entries) const {
+    return static_cast<const Implementation&>(*this)
+        .estimateSerializedLengthImpl(number_of_entries);
+  }
+
+  uint32_t getFinalBlockNumber() const {
+    return static_cast<const Implementation&>(*this).getFinalBlockNumberImpl();
+  }
+};
+
+}  // namespace core
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.cc b/libtransport/src/hicn/transport/core/manifest_format_fixed.cc
new file mode 100755 (executable)
index 0000000..f26f20a
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/utils/endianess.h>
+#include <hicn/transport/utils/literals.h>
+
+namespace transport {
+
+namespace core {
+
+// TODO use preallocated pool of membufs
+FixedManifestEncoder::FixedManifestEncoder(Packet& packet)
+    : packet_(packet),
+      max_size_(Packet::default_mtu - packet_.headerSize()),
+      manifest_(
+          utils::MemBuf::create(Packet::default_mtu - packet_.headerSize())),
+      manifest_header_(
+          reinterpret_cast<ManifestHeader*>(manifest_->writableData())),
+      manifest_entries_(reinterpret_cast<ManifestEntry*>(
+          manifest_->writableData() + sizeof(ManifestHeader))),
+      current_entry_(0) {}
+
+FixedManifestEncoder::~FixedManifestEncoder() {}
+
+FixedManifestEncoder& FixedManifestEncoder::encodeImpl() {
+  packet_.appendPayload(std::move(manifest_));
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::clearImpl() {
+  manifest_ = utils::MemBuf::create(Packet::default_mtu - packet_.headerSize());
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setHashAlgorithmImpl(
+    HashAlgorithm algorithm) {
+  manifest_header_->hash_algorithm = static_cast<uint8_t>(algorithm);
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setManifestTypeImpl(
+    ManifestType manifest_type) {
+  manifest_header_->manifest_type = static_cast<uint8_t>(manifest_type);
+  return *this;
+}
+
+FixedManifestEncoder&
+FixedManifestEncoder::setNextSegmentCalculationStrategyImpl(
+    NextSegmentCalculationStrategy strategy) {
+  manifest_header_->next_segment_strategy = static_cast<uint8_t>(strategy);
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setBaseNameImpl(
+    const core::Name& base_name) {
+  base_name.copyToDestination(
+      reinterpret_cast<uint8_t*>(&manifest_header_->prefix[0]), false);
+  manifest_header_->flags.ipv6 =
+      base_name.getAddressFamily() == AF_INET6 ? 1_U8 : 0_U8;
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::addSuffixAndHashImpl(
+    uint32_t suffix, const utils::CryptoHash& hash) {
+  auto _hash = hash.getDigest<std::uint8_t>();
+  addSuffixHashBytes(suffix, _hash.data(), _hash.length());
+  return *this;
+}
+
+void FixedManifestEncoder::addSuffixHashBytes(uint32_t suffix,
+                                              const uint8_t* hash,
+                                              std::size_t length) {
+  manifest_entries_[current_entry_].suffix = utils::hton(suffix);
+  //  std::copy(hash, hash + length,
+  //            manifest_entries_[current_entry_].hash);
+  std::memcpy(
+      reinterpret_cast<uint8_t*>(manifest_entries_[current_entry_].hash), hash,
+      length);
+
+  manifest_header_->number_of_entries++;
+  current_entry_++;
+
+  if (TRANSPORT_EXPECT_FALSE(estimateSerializedLengthImpl() > max_size_)) {
+    throw errors::RuntimeException("Manifest size exceeded the packet MTU!");
+  }
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setIsFinalManifestImpl(
+    bool is_last) {
+  manifest_header_->flags.is_last = static_cast<uint8_t>(is_last);
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setVersionImpl(
+    ManifestVersion version) {
+  manifest_header_->version = static_cast<uint8_t>(version);
+  return *this;
+}
+
+std::size_t FixedManifestEncoder::estimateSerializedLengthImpl(
+    std::size_t additional_entries) {
+  return sizeof(ManifestHeader) +
+         (manifest_header_->number_of_entries + additional_entries) *
+             sizeof(ManifestEntry);
+}
+
+FixedManifestEncoder& FixedManifestEncoder::updateImpl() {
+  max_size_ = Packet::default_mtu - packet_.headerSize();
+  manifest_header_ = reinterpret_cast<ManifestHeader*>(
+      const_cast<uint8_t*>(packet_.getPayload().data()));
+  manifest_entries_ = reinterpret_cast<ManifestEntry*>(
+      const_cast<uint8_t*>(packet_.getPayload().data()) +
+      sizeof(ManifestHeader));
+  return *this;
+}
+
+FixedManifestEncoder& FixedManifestEncoder::setFinalBlockNumberImpl(
+    std::uint32_t final_block_number) {
+  manifest_header_->final_block_number = utils::hton(final_block_number);
+  return *this;
+}
+
+std::size_t FixedManifestEncoder::getManifestHeaderSizeImpl() {
+  return sizeof(ManifestHeader);
+}
+
+FixedManifestDecoder::FixedManifestDecoder(Packet& packet)
+    : packet_(packet),
+      manifest_header_(reinterpret_cast<ManifestHeader*>(
+          const_cast<uint8_t*>(packet_.getPayload().data()))),
+      manifest_entries_(reinterpret_cast<ManifestEntry*>(
+          const_cast<uint8_t*>(packet_.getPayload().data()) +
+          sizeof(ManifestHeader))) {}
+
+FixedManifestDecoder::~FixedManifestDecoder() {}
+
+void FixedManifestDecoder::decodeImpl() {
+  std::size_t packet_size = packet_.payloadSize();
+
+  if (packet_size < sizeof(ManifestHeader) ||
+      packet_size < estimateSerializedLengthImpl()) {
+    throw errors::RuntimeException(
+        "The packet does not match expected manifest size.");
+  }
+}
+
+FixedManifestDecoder& FixedManifestDecoder::clearImpl() { return *this; }
+
+ManifestType FixedManifestDecoder::getManifestTypeImpl() const {
+  return static_cast<ManifestType>(manifest_header_->manifest_type);
+}
+
+HashAlgorithm FixedManifestDecoder::getHashAlgorithmImpl() const {
+  return static_cast<HashAlgorithm>(manifest_header_->hash_algorithm);
+}
+
+NextSegmentCalculationStrategy
+FixedManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+  return static_cast<NextSegmentCalculationStrategy>(
+      manifest_header_->next_segment_strategy);
+}
+
+typename Fixed::SuffixList FixedManifestDecoder::getSuffixHashListImpl() {
+  typename Fixed::SuffixList hash_list;
+
+  for (int i = 0; i < manifest_header_->number_of_entries; i++) {
+    hash_list.insert(hash_list.end(),
+                     std::make_pair(utils::ntoh(manifest_entries_[i].suffix),
+                                    reinterpret_cast<uint8_t*>(
+                                        &manifest_entries_[i].hash[0])));
+  }
+
+  return hash_list;
+}
+
+core::Name FixedManifestDecoder::getBaseNameImpl() const {
+  if (static_cast<bool>(manifest_header_->flags.ipv6)) {
+    return core::Name(AF_INET6,
+                      reinterpret_cast<uint8_t*>(&manifest_header_->prefix));
+  } else {
+    return core::Name(AF_INET,
+                      reinterpret_cast<uint8_t*>(&manifest_header_->prefix));
+  }
+}
+
+bool FixedManifestDecoder::getIsFinalManifestImpl() const {
+  return static_cast<bool>(manifest_header_->flags.is_last);
+}
+
+ManifestVersion FixedManifestDecoder::getVersionImpl() const {
+  return static_cast<ManifestVersion>(manifest_header_->version);
+}
+
+std::size_t FixedManifestDecoder::estimateSerializedLengthImpl(
+    std::size_t additional_entries) const {
+  return sizeof(ManifestHeader) +
+         (additional_entries + manifest_header_->number_of_entries) *
+             sizeof(ManifestEntry);
+}
+
+uint32_t FixedManifestDecoder::getFinalBlockNumberImpl() const {
+  return utils::ntoh(manifest_header_->final_block_number);
+}
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_fixed.h b/libtransport/src/hicn/transport/core/manifest_format_fixed.h
new file mode 100755 (executable)
index 0000000..66825e2
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/packet.h>
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+//   0                   1                   2                   3
+//   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |Version| MType |HashAlg|NextStr|     Flags     |NumberOfEntries|
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                       Final Block Number                      |
+//  +---------------------------------------------------------------|
+//  |                                                               |
+//  +                                                               +
+//  |                                                               |
+//  +                             Prefix                            +
+//  |                                                               |
+//  +                                                               +
+//  |                                                               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                             Suffix                            |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  |                           Hash Value                          |
+//  |                                                               |
+//  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class FixedManifestEncoder;
+class FixedManifestDecoder;
+class Packet;
+
+struct Fixed {
+  using Encoder = FixedManifestEncoder;
+  using Decoder = FixedManifestDecoder;
+  using HashType = utils::CryptoHash;
+  using SuffixList = std::list<std::pair<std::uint32_t, std::uint8_t*>>;
+};
+
+struct Flags {
+  std::uint8_t ipv6 : 1;
+  std::uint8_t is_last : 1;
+  std::uint8_t unused : 6;
+};
+
+struct ManifestEntry {
+  std::uint32_t suffix;
+  std::uint32_t hash[8];
+};
+
+struct ManifestHeader {
+  std::uint8_t version : 4;
+  std::uint8_t manifest_type : 4;
+  std::uint8_t hash_algorithm : 4;
+  std::uint8_t next_segment_strategy : 4;
+  Flags flags;
+  std::uint8_t number_of_entries;
+  std::uint32_t final_block_number;
+  std::uint32_t prefix[4];
+  ManifestEntry entries[0];
+};
+
+static const constexpr std::uint8_t manifest_version = 1;
+
+class FixedManifestEncoder : public ManifestEncoder<FixedManifestEncoder> {
+ public:
+  FixedManifestEncoder(Packet& packet);
+
+  ~FixedManifestEncoder();
+
+  FixedManifestEncoder& encodeImpl();
+
+  FixedManifestEncoder& clearImpl();
+
+  FixedManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+  FixedManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+  FixedManifestEncoder& setNextSegmentCalculationStrategyImpl(
+      NextSegmentCalculationStrategy strategy);
+
+  FixedManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+  FixedManifestEncoder& addSuffixAndHashImpl(uint32_t suffix,
+                                             const utils::CryptoHash& hash);
+
+  FixedManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+  FixedManifestEncoder& setVersionImpl(ManifestVersion version);
+
+  std::size_t estimateSerializedLengthImpl(std::size_t additional_entries = 0);
+
+  FixedManifestEncoder& updateImpl();
+
+  FixedManifestEncoder& setFinalBlockNumberImpl(
+      std::uint32_t final_block_number);
+
+  static std::size_t getManifestHeaderSizeImpl();
+
+ private:
+  void addSuffixHashBytes(uint32_t suffix, const uint8_t* hash,
+                          std::size_t length);
+
+  Packet& packet_;
+  std::size_t max_size_;
+  std::unique_ptr<utils::MemBuf> manifest_;
+  ManifestHeader* manifest_header_;
+  ManifestEntry* manifest_entries_;
+  std::size_t current_entry_;
+};
+
+class FixedManifestDecoder : public ManifestDecoder<FixedManifestDecoder> {
+ public:
+  FixedManifestDecoder(Packet& packet);
+
+  ~FixedManifestDecoder();
+
+  void decodeImpl();
+
+  FixedManifestDecoder& clearImpl();
+
+  ManifestType getManifestTypeImpl() const;
+
+  HashAlgorithm getHashAlgorithmImpl() const;
+
+  NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+  typename Fixed::SuffixList getSuffixHashListImpl();
+
+  core::Name getBaseNameImpl() const;
+
+  bool getIsFinalManifestImpl() const;
+
+  std::size_t estimateSerializedLengthImpl(
+      std::size_t additional_entries = 0) const;
+
+  ManifestVersion getVersionImpl() const;
+
+  uint32_t getFinalBlockNumberImpl() const;
+
+ private:
+  Packet& packet_;
+  ManifestHeader* manifest_header_;
+  ManifestEntry* manifest_entries_;
+};
+
+}  // namespace core
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.cc
new file mode 100755 (executable)
index 0000000..512cdba
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/portability/transport_portability.h>
+
+#include <array>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+
+template <typename T>
+TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) {
+  if (pointer == nullptr) {
+    throw errors::NullPointerException();
+  }
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE void setValueToJson(Json::Value& root, EnumType value) {
+  root[JSONKey<EnumType>::key] = static_cast<uint8_t>(value);
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(const Json::Value& root) {
+  return static_cast<EnumType>(root[JSONKey<EnumType>::key].asUInt());
+};
+
+}  // namespace
+
+JSONManifestEncoder::JSONManifestEncoder(Packet& packet) : packet_(packet) {}
+
+JSONManifestEncoder::~JSONManifestEncoder() {}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::encodeImpl() {
+  Json::StreamWriterBuilder writer_builder;
+  Json::StreamWriter* fast_writer = writer_builder.newStreamWriter();
+
+  asio::streambuf strbuf;
+  strbuf.prepare(1500);
+  std::ostream stream(&strbuf);
+  fast_writer->write(root_, &stream);
+
+  const uint8_t* buffer = asio::buffer_cast<const uint8_t*>(strbuf.data());
+
+  packet_.setPayload(buffer, strbuf.size());
+
+  delete fast_writer;
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() {
+  root_.clear();
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) {
+  setValueToJson(root_, algorithm);
+  return *this;
+}
+
+JSONManifestEncoder& JSONManifestEncoder::setManifestTypeImpl(
+    ManifestType manifest_type) {
+  setValueToJson(root_, manifest_type);
+  return *this;
+}
+
+JSONManifestEncoder& JSONManifestEncoder::setNextSegmentCalculationStrategyImpl(
+    NextSegmentCalculationStrategy strategy) {
+  setValueToJson(root_, strategy);
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) {
+  root_[JSONKey<core::Name>::key] = base_name.toString().c_str();
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix,
+                                          const utils::CryptoHash& hash) {
+  throw errors::NotImplementedException();
+  //  Json::Value value(Json::arrayValue);
+  //  value.append(Json::Value(suffix));
+  //  value.append(Json::Value(Json::Value::UInt64 (hash)));
+  //  root_[JSONKey<SuffixHashList>::key].append(value);
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) {
+  root_[JSONKey<bool>::final_manifest] = is_last;
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setVersionImpl(ManifestVersion version) {
+  setValueToJson(root_, version);
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setSuffixHashListImpl(
+    const typename JSON::SuffixList& name_hash_list) {
+  throw errors::NotImplementedException();
+  //  for (auto &suffix : name_hash_list) {
+  //    addSuffixAndHashImpl(suffix.first, suffix.second);
+  //  }
+  //
+  //  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestEncoder::estimateSerializedLengthImpl(
+    std::size_t number_of_entries) {
+  Json::StreamWriterBuilder writer_builder;
+  Json::StreamWriter* fast_writer = writer_builder.newStreamWriter();
+
+  asio::streambuf strbuf;
+  strbuf.prepare(1500);
+  std::ostream stream(&strbuf);
+  fast_writer->write(root_, &stream);
+
+  return strbuf.size();
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::updateImpl() {
+  throw errors::NotImplementedException();
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setFinalBlockNumberImpl(std::uint32_t final_block_number) {
+  throw errors::NotImplementedException();
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestEncoder::getManifestHeaderSizeImpl() {
+  return 0;
+}
+
+JSONManifestDecoder::JSONManifestDecoder(Packet& packet) : packet_(packet) {}
+
+JSONManifestDecoder::~JSONManifestDecoder() {}
+
+TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl() {
+  auto array = packet_.getPayload();
+  auto payload = array.data();
+  auto payload_size = array.length();
+
+  Json::CharReaderBuilder reader_builder;
+  Json::CharReader* reader = reader_builder.newCharReader();
+  std::string errors;
+
+  if (!reader->parse((char*)payload, (char*)payload + payload_size, &root_,
+                     &errors)) {
+    TRANSPORT_LOGE("Error parsing manifest!");
+    TRANSPORT_LOGE("%s", errors.c_str());
+
+    delete reader;
+
+    throw errors::MalformedPacketException();
+  }
+
+  delete reader;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() {
+  root_.clear();
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestType
+JSONManifestDecoder::getManifestTypeImpl() const {
+  return getValueFromJson<ManifestType>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE HashAlgorithm
+JSONManifestDecoder::getHashAlgorithmImpl() const {
+  return getValueFromJson<HashAlgorithm>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy
+JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+  return getValueFromJson<NextSegmentCalculationStrategy>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE typename JSON::SuffixList
+JSONManifestDecoder::getSuffixHashListImpl() {
+  throw errors::NotImplementedException();
+  //  SuffixHashList hash_list;
+  //
+  //  Json::Value &array = root_[JSONKey<SuffixHashList>::key];
+  //
+  //  for (Json::Value::ArrayIndex i = 0;
+  //       i != array.size();
+  //       i++) {
+  //    hash_list[array[i][0].asUInt()] = array[i][1].asUInt64();
+  //  }
+  //
+  //  return hash_list;
+}
+
+TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl()
+    const {
+  return core::Name(root_[JSONKey<core::Name>::key].asCString());
+}
+
+TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl()
+    const {
+  return root_[JSONKey<bool>::final_manifest].asBool();
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestVersion
+JSONManifestDecoder::getVersionImpl() const {
+  return getValueFromJson<ManifestVersion>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t
+JSONManifestDecoder::getFinalBlockNumberImpl() const {
+  return 0;
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h b/libtransport/src/hicn/transport/core/manifest_format_json_jsoncpp.h
new file mode 100755 (executable)
index 0000000..39f0cf3
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+#if defined(__APPLE__) || defined(__ANDROID__)
+#include <json/json.h>
+#else
+#include <jsoncpp/json/json.h>
+#endif /* __APPLE__  || __ANDROID__*/
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+class JSONManifestEncoder;
+class JSONManifestDecoder;
+class Packet;
+
+struct JSON {
+  using Encoder = JSONManifestEncoder;
+  using Decoder = JSONManifestDecoder;
+  using HashType = utils::CryptoHash;
+  using SuffixList = std::unordered_map<std::uint32_t, std::uint8_t*>;
+};
+
+template <typename T>
+struct JSONKey;
+
+template <>
+struct JSONKey<ManifestVersion> {
+  static const constexpr char* key = "manifest_version";
+};
+
+template <>
+struct JSONKey<HashAlgorithm> {
+  static const constexpr char* key = "hash_algorithm";
+};
+
+template <>
+struct JSONKey<ManifestType> {
+  static const constexpr char* key = "manifest_type";
+};
+
+template <>
+struct JSONKey<NextSegmentCalculationStrategy> {
+  static const constexpr char* key = "next_segment_strategy";
+};
+
+template <>
+struct JSONKey<typename JSON::SuffixList> {
+  static const constexpr char* key = "suffix_hash_list";
+};
+
+template <>
+struct JSONKey<core::Name> {
+  static const constexpr char* key = "base_name";
+};
+
+template <>
+struct JSONKey<bool> {
+  static const constexpr char* final_manifest = "final_manifest";
+};
+
+class JSONManifestEncoder : public ManifestEncoder<JSONManifestEncoder> {
+ public:
+  JSONManifestEncoder(Packet& packet);
+
+  ~JSONManifestEncoder() override;
+
+  JSONManifestEncoder& encodeImpl();
+
+  JSONManifestEncoder& clearImpl();
+
+  JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+  JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+  JSONManifestEncoder& setNextSegmentCalculationStrategyImpl(
+      NextSegmentCalculationStrategy strategy);
+
+  JSONManifestEncoder& setSuffixHashListImpl(
+      const typename JSON::SuffixList& name_hash_list);
+
+  JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+  JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix,
+                                            const utils::CryptoHash& hash);
+
+  JSONManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+  JSONManifestEncoder& setVersionImpl(ManifestVersion version);
+
+  std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries);
+
+  JSONManifestEncoder& updateImpl();
+
+  JSONManifestEncoder& setFinalBlockNumberImpl(
+      std::uint32_t final_block_number);
+
+  static std::size_t getManifestHeaderSizeImpl();
+
+ private:
+  Packet& packet_;
+  Json::Value root_;
+};
+
+class JSONManifestDecoder : public ManifestDecoder<JSONManifestDecoder> {
+ public:
+  JSONManifestDecoder(Packet& packet);
+
+  ~JSONManifestDecoder() override;
+
+  void decodeImpl();
+
+  JSONManifestDecoder& clearImpl();
+
+  ManifestType getManifestTypeImpl() const;
+
+  HashAlgorithm getHashAlgorithmImpl() const;
+
+  uint32_t getFinalChunkImpl() const;
+
+  NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+  typename JSON::SuffixList getSuffixHashListImpl();
+
+  core::Name getBaseNameImpl() const;
+
+  bool getIsFinalManifestImpl() const;
+
+  std::size_t estimateSerializedLengthImpl(std::size_t number_of_entries) const;
+
+  ManifestVersion getVersionImpl() const;
+
+  uint32_t getFinalBlockNumberImpl() const;
+
+ private:
+  Packet& packet_;
+  Json::Value root_;
+};
+
+}  // namespace core
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.cc
new file mode 100755 (executable)
index 0000000..d0365d2
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format_json_libparc_deprecated.h>
+#include <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/transport_portability.h>
+
+extern "C" {
+#include <parc/algol/parc_Memory.h>
+}
+
+namespace transport {
+
+namespace core {
+
+namespace {
+
+template <typename T>
+TRANSPORT_ALWAYS_INLINE void checkPointer(T* pointer) {
+  if (pointer == nullptr) {
+    throw errors::NullPointerException();
+  }
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE void setValueToJson(PARCJSON* root, EnumType value) {
+  parcJSON_AddInteger(root, JSONKey<EnumType>::key,
+                      static_cast<int64_t>(value));
+}
+
+template <typename EnumType>
+TRANSPORT_ALWAYS_INLINE EnumType getValueFromJson(PARCJSON* root) {
+  checkPointer(root);
+
+  PARCJSONValue* value = parcJSON_GetValueByName(root, JSONKey<EnumType>::key);
+
+  EnumType ret = static_cast<EnumType>(parcJSONValue_GetInteger(value));
+  // parcJSONValue_Release(&value);
+
+  return ret;
+};
+
+}  // namespace
+
+JSONManifestEncoder::JSONManifestEncoder() : root_(parcJSON_Create()) {
+  parcJSON_Acquire(root_);
+}
+
+JSONManifestEncoder::~JSONManifestEncoder() {
+  if (root_) {
+    parcJSON_Release(&root_);
+  }
+}
+
+TRANSPORT_ALWAYS_INLINE SONManifestEncoder& JSONManifestEncoder::encodeImpl(
+    Packet& packet) {
+  char* json_string = parcJSON_ToString(root_);
+  packet.setPayload(reinterpret_cast<uint8_t*>(json_string),
+                    std::strlen(json_string));
+  parcMemory_Deallocate(&json_string);
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder& JSONManifestEncoder::clearImpl() {
+  if (root_) {
+    parcJSON_Release(&root_);
+  }
+
+  root_ = parcJSON_Create();
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setHashAlgorithmImpl(HashAlgorithm algorithm) {
+  setValueToJson(root_, algorithm);
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setManifestTypeImpl(ManifestType manifest_type) {
+  setValueToJson(root_, manifest_type);
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setNextSegmentCalculationStrategyImpl(
+    NextSegmentCalculationStrategy strategy) {
+  setValueToJson(root_, strategy);
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setBaseNameImpl(const core::Name& base_name) {
+  parcJSON_AddString(root_, JSONKey<core::Name>::key,
+                     base_name.toString().c_str());
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::addSuffixAndHashImpl(uint32_t suffix,
+                                          utils::CryptoHash& hash) {
+  throw errors::NotImplementedException();
+  //  PARCJSONValue *value = parcJSON_GetValueByName(root_,
+  //                                                 JSONKey<SuffixHashList>::key);
+  //
+  //  // Create the pair to store in the array.
+  //  // It will be segment number + Hash of the segment
+  //  PARCJSONArray * pair = parcJSONArray_Create();
+  //
+  //  PARCJSONValue *v = parcJSONValue_CreateFromInteger(suffix);
+  //  parcJSONArray_AddValue(pair, v);
+  //  parcJSONValue_Release(&v);
+  //
+  //  v = parcJSONValue_CreateFromInteger(hash);
+  //  parcJSONArray_AddValue(pair, v);
+  //  parcJSONValue_Release(&v);
+  //
+  //  if (value == nullptr /* || !parcJSONValue_IsArray(value) */) {
+  //    // Create the array
+  //    PARCJSONArray *array = parcJSONArray_Create();
+  //    parcJSON_AddArray(root_,
+  //                      JSONKey<SuffixHashList>::key,
+  //                      array);
+  //    parcJSONArray_Release(&array);
+  //
+  //    value = parcJSON_GetValueByName(root_, JSONKey<SuffixHashList>::key);
+  //  }
+  //
+  //  v = parcJSONValue_CreateFromJSONArray(pair);
+  //  parcJSONArray_AddValue(parcJSONValue_GetArray(value), v);
+  //  parcJSONValue_Release(&v);
+  //
+  //  parcJSONArray_Release(&pair);
+  //  // parcJSONValue_Release(&value);
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setIsFinalManifestImpl(bool is_last) {
+  parcJSON_AddBoolean(root_, JSONKey<bool>::final_manifest, is_last);
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestEncoder&
+JSONManifestEncoder::setSuffixHashListImpl(
+    const SuffixHashList& name_hash_list) {
+  for (auto& suffix : name_hash_list) {
+    addSuffixAndHashImpl(suffix.first, suffix.second);
+  }
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::JSONManifestDecoder()
+    : root_(nullptr) {}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder::~JSONManifestDecoder() {
+  if (root_) {
+    parcJSON_Release(&root_);
+  }
+}
+
+TRANSPORT_ALWAYS_INLINE void JSONManifestDecoder::decodeImpl(
+    const uint8_t* payload, std::size_t payload_size) {
+  PARCBuffer* b = parcBuffer_Wrap(const_cast<uint8_t*>(payload), payload_size,
+                                  0, payload_size);
+  clearImpl();
+
+  root_ = parcJSON_ParseBuffer(b);
+  parcBuffer_Release(&b);
+
+  char* str = parcJSON_ToString(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE JSONManifestDecoder& JSONManifestDecoder::clearImpl() {
+  if (root_) {
+    parcJSON_Release(&root_);
+  }
+
+  return *this;
+}
+
+TRANSPORT_ALWAYS_INLINE ManifestType
+JSONManifestDecoder::getManifestTypeImpl() const {
+  return getValueFromJson<ManifestType>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE HashAlgorithm
+JSONManifestDecoder::getHashAlgorithmImpl() const {
+  return getValueFromJson<HashAlgorithm>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE NextSegmentCalculationStrategy
+JSONManifestDecoder::getNextSegmentCalculationStrategyImpl() const {
+  return getValueFromJson<NextSegmentCalculationStrategy>(root_);
+}
+
+TRANSPORT_ALWAYS_INLINE SuffixHashList
+JSONManifestDecoder::getSuffixHashListImpl() {
+  throw errors::NotImplementedException();
+  //  SuffixHashList hash_list;
+  //
+  //  char * str = parcJSON_ToString(root_);
+  //
+  //  PARCJSONValue *value = parcJSON_GetValueByName(root_,
+  //                                                 JSONKey<SuffixHashList>::key);
+  //
+  //  if (value == nullptr || !parcJSONValue_IsArray(value)) {
+  //    throw errors::RuntimeException("Manifest does not contain suffix-hash
+  //    list");
+  //  }
+  //
+  //  PARCJSONArray *array = parcJSONValue_GetArray(value);
+  //  std::size_t array_size = parcJSONArray_GetLength(array);
+  //
+  //  for (std::size_t i = 0; i < array_size; i++) {
+  //    PARCJSONValue *v = parcJSONArray_GetValue(array, i);
+  //    checkPointer(v);
+  //    PARCJSONArray *a = parcJSONValue_GetArray(v);
+  //    PARCJSONValue *_suffix = parcJSONArray_GetValue(a, 0);
+  //    PARCJSONValue *_hash = parcJSONArray_GetValue(a, 1);
+  //
+  //    uint32_t value1 =
+  //    static_cast<uint32_t>(parcJSONValue_GetInteger(_suffix)); uint64_t
+  //    value2 = static_cast<uint64_t>(parcJSONValue_GetInteger(_hash));
+  //
+  //    hash_list[static_cast<uint32_t>(parcJSONValue_GetInteger(_suffix))] =
+  //        static_cast<uint64_t>(parcJSONValue_GetInteger(_hash));
+  //
+  ////    parcJSONValue_Release(&_hash);
+  ////    parcJSONValue_Release(&_suffix);
+  ////    parcJSONArray_Release(&a);
+  ////    parcJSONValue_Release(&v);
+  //  }
+  //
+  ////  parcJSONArray_Release(&array);
+  ////  parcJSONValue_Release(&value);
+  //
+  //  char * str2 = parcJSON_ToString(root_);
+  //
+  //  return hash_list;
+}
+
+TRANSPORT_ALWAYS_INLINE core::Name JSONManifestDecoder::getBaseNameImpl()
+    const {
+  checkPointer(root_);
+  PARCJSONValue* value =
+      parcJSON_GetValueByName(root_, JSONKey<core::Name>::key);
+
+  PARCBuffer* b = parcJSONValue_GetString(value);
+  char* string = parcBuffer_ToString(b);
+
+  core::Name ret(string);
+
+  // parcJSONValue_Release(&value);
+  parcMemory_Deallocate(&string);
+
+  return ret;
+}
+
+TRANSPORT_ALWAYS_INLINE bool JSONManifestDecoder::getIsFinalManifestImpl() {
+  checkPointer(root_);
+  PARCJSONValue* value =
+      parcJSON_GetValueByName(root_, JSONKey<bool>::final_manifest);
+
+  bool ret = parcJSONValue_GetBoolean(value);
+
+  // parcJSONValue_Release(&value);
+
+  return ret;
+}
+
+TRANSPORT_ALWAYS_INLINE std::size_t
+JSONManifestDecoder::estimateSerializedLengthImpl(
+    std::size_t number_of_entries) {
+  return 0;
+}
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h b/libtransport/src/hicn/transport/core/manifest_format_json_libparc_deprecated.h
new file mode 100755 (executable)
index 0000000..28c6c1b
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+
+extern "C" {
+#include <parc/algol/parc_JSON.h>
+}
+
+#include <string>
+
+namespace transport {
+
+namespace core {
+
+class JSONManifestEncoder;
+class JSONManifestDecoder;
+class Packet;
+
+struct JSON {
+  using Encoder = JSONManifestEncoder;
+  using Decoder = JSONManifestDecoder;
+};
+
+template <typename T>
+struct JSONKey;
+
+template <>
+struct JSONKey<HashAlgorithm> {
+  static const constexpr char* key = "hash_algorithm";
+};
+
+template <>
+struct JSONKey<ManifestType> {
+  static const constexpr char* key = "manifest_type";
+};
+
+template <>
+struct JSONKey<NextSegmentCalculationStrategy> {
+  static const constexpr char* key = "next_segment_strategy";
+};
+
+template <>
+struct JSONKey<NameHashList> {
+  static const constexpr char* key = "name_hash_list";
+};
+
+template <>
+struct JSONKey<SuffixHashList> {
+  static const constexpr char* key = "suffix_hash_list";
+};
+
+template <>
+struct JSONKey<core::Name> {
+  static const constexpr char* key = "base_name";
+};
+
+template <>
+struct JSONKey<bool> {
+  static const constexpr char* final_manifest = "final_manifest";
+};
+
+// template <>
+// struct JSONKey<base_name> {
+//  static const std::string key = "name_hash_list";
+//};
+
+// namespace JSONManifestEncoding {
+//  static const std::string base_name = "base_name";
+//  static const std::string final_chunk_number = "final_chunk_number";
+//  static const std::string hash_algorithm = "hash_algorithm";
+//  static const std::string manifest_type = "manifest_type";
+//  static const std::string name_hash_list = "name_hash_list";
+//  static const std::string next_segment_strategy = "next_segment_strategy";
+//}
+
+class JSONManifestEncoder : public ManifestEncoder<JSONManifestEncoder> {
+ public:
+  JSONManifestEncoder();
+
+  ~JSONManifestEncoder();
+
+  JSONManifestEncoder& encodeImpl(Packet& packet);
+
+  JSONManifestEncoder& clearImpl();
+
+  JSONManifestEncoder& setManifestTypeImpl(ManifestType manifest_type);
+
+  JSONManifestEncoder& setHashAlgorithmImpl(HashAlgorithm algorithm);
+
+  JSONManifestEncoder& setNextSegmentCalculationStrategyImpl(
+      NextSegmentCalculationStrategy strategy);
+
+  JSONManifestEncoder& setSuffixHashListImpl(
+      const SuffixHashList& name_hash_list);
+
+  JSONManifestEncoder& setBaseNameImpl(const core::Name& base_name);
+
+  JSONManifestEncoder& addSuffixAndHashImpl(uint32_t suffix, uint64_t hash);
+
+  JSONManifestEncoder& setIsFinalManifestImpl(bool is_last);
+
+ private:
+  PARCJSON* root_;
+};
+
+class JSONManifestDecoder : public ManifestDecoder<JSONManifestDecoder> {
+ public:
+  JSONManifestDecoder();
+
+  ~JSONManifestDecoder();
+
+  void decodeImpl(const uint8_t* payload, std::size_t payload_size);
+
+  JSONManifestDecoder& clearImpl();
+
+  ManifestType getManifestTypeImpl() const;
+
+  HashAlgorithm getHashAlgorithmImpl() const;
+
+  uint32_t getFinalChunkImpl() const;
+
+  NextSegmentCalculationStrategy getNextSegmentCalculationStrategyImpl() const;
+
+  SuffixHashList getSuffixHashListImpl();
+
+  core::Name getBaseNameImpl() const;
+
+  bool getIsFinalManifestImpl();
+
+ private:
+  PARCJSON* root_;
+};
+
+}  // namespace core
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/manifest_inline.h b/libtransport/src/hicn/transport/core/manifest_inline.h
new file mode 100755 (executable)
index 0000000..fd1a9ab
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest.h>
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <set>
+
+namespace transport {
+
+namespace core {
+
+template <typename Base, typename FormatTraits>
+class ManifestInline
+    : public Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>> {
+  using ManifestBase =
+      Manifest<Base, FormatTraits, ManifestInline<Base, FormatTraits>>;
+  using HashType = typename FormatTraits::HashType;
+  using SuffixList = typename FormatTraits::SuffixList;
+
+ public:
+  ManifestInline() : ManifestBase() {}
+
+  ManifestInline(const core::Name& name) : ManifestBase(name) {}
+
+  template <typename T>
+  ManifestInline(T&& base) : ManifestBase(std::forward<T&&>(base)) {}
+
+  static TRANSPORT_ALWAYS_INLINE ManifestInline* createManifest(
+      const core::Name& manifest_name, ManifestVersion version,
+      ManifestType type, HashAlgorithm algorithm, bool is_last,
+      const Name& base_name, NextSegmentCalculationStrategy strategy,
+      std::size_t signature_size) {
+    auto manifest = new ManifestInline(manifest_name);
+    manifest->setSignatureSize(signature_size);
+    manifest->setVersion(version);
+    manifest->setManifestType(type);
+    manifest->setHashAlgorithm(algorithm);
+    manifest->setFinalManifest(is_last);
+    manifest->setBaseName(base_name);
+    manifest->setNextSegmentCalculationStrategy(strategy);
+
+    return manifest;
+  }
+
+  ManifestInline& encodeImpl() {
+    ManifestBase::encoder_.encode();
+    return *this;
+  }
+
+  ManifestInline& decodeImpl() {
+    base_name_ = ManifestBase::decoder_.getBaseName();
+    next_segment_strategy_ =
+        ManifestBase::decoder_.getNextSegmentCalculationStrategy();
+    suffix_hash_map_ = ManifestBase::decoder_.getSuffixHashList();
+
+    return *this;
+  }
+
+  std::size_t estimateManifestSizeImpl(std::size_t additional_entries = 0) {
+    return ManifestBase::encoder_.estimateSerializedLength(additional_entries);
+  }
+
+  ManifestInline& setBaseName(const Name& name) {
+    base_name_ = name;
+    ManifestBase::encoder_.setBaseName(base_name_);
+    return *this;
+  }
+
+  const Name& getBaseName() { return base_name_; }
+
+  ManifestInline& addSuffixHash(uint32_t suffix, const HashType& hash) {
+    ManifestBase::encoder_.addSuffixAndHash(suffix, hash);
+    return *this;
+  }
+
+  // Call this function only after the decode function!
+  const SuffixList& getSuffixList() { return suffix_hash_map_; }
+
+  ManifestInline& setNextSegmentCalculationStrategy(
+      NextSegmentCalculationStrategy strategy) {
+    next_segment_strategy_ = strategy;
+    ManifestBase::encoder_.setNextSegmentCalculationStrategy(
+        next_segment_strategy_);
+    return *this;
+  }
+
+  NextSegmentCalculationStrategy getNextSegmentCalculationStrategy() {
+    return next_segment_strategy_;
+  }
+
+ private:
+  core::Name base_name_;
+  NextSegmentCalculationStrategy next_segment_strategy_;
+  SuffixList suffix_hash_map_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.c b/libtransport/src/hicn/transport/core/memif_binary_api.c
new file mode 100755 (executable)
index 0000000..b443b51
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/memif_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+// uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
+
+/* Declare message IDs */
+#include <memif/memif_msg_enum.h>
+
+#define vl_msg_name_crc_list
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+#define vl_typedefs
+#define vl_endianfun
+#define vl_print(handle, ...)
+#define vl_printfun
+#define vl_api_version(n, v) static u32 api_version = (v);
+#define vl_msg_name_crc_list
+#include <memif/memif_all_api_h.h>
+#undef vl_msg_name_crc_list
+#undef vl_api_version
+#undef vl_printfun
+#undef vl_endianfun
+#undef vl_typedefs
+
+/* define message structures */
+#define vl_typedefs
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_memif_api_reply_msg         \
+  _(MEMIF_CREATE_REPLY, memif_create_reply) \
+  _(MEMIF_DELETE_REPLY, memif_delete_reply) \
+  _(MEMIF_DETAILS, memif_details)
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t *api) {
+  // Dump all the memif interfaces and return the next to the largest memif id
+  vl_api_memif_dump_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+
+  M(MEMIF_DUMP, mp);
+  api->vpp_api->user_param = malloc(sizeof(uint32_t));
+  *(uint32_t *)(api->vpp_api->user_param) = 0;
+  global_pointers_map[global_pointers_map_index] = api;
+  mp->context = global_pointers_map_index++;
+  global_pointers_map_index %= POINTER_MAP_SIZE;
+
+  vpp_binary_api_send_request(api->vpp_api, mp);
+
+  vpp_binary_api_send_receive_ping(api->vpp_api);
+
+  uint32_t ret = *(uint32_t *)(api->vpp_api->user_param);
+  free(api->vpp_api->user_param);
+
+  return ret;
+}
+
+static void vl_api_memif_details_t_handler(vl_api_memif_details_t *mp) {
+  vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+  uint32_t *last_memif_id = binary_api->vpp_api->user_param;
+  uint32_t current_memif_id = clib_net_to_host_u32(mp->id);
+  if (current_memif_id >= *last_memif_id) {
+    *last_memif_id = current_memif_id + 1;
+  }
+}
+
+int memif_binary_api_create_memif(vpp_plugin_binary_api_t *api,
+                                  memif_create_params_t *input_params,
+                                  memif_output_params_t *output_params) {
+  vl_api_memif_create_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+
+  if (input_params->socket_id == ~0) {
+    // invalid socket-id
+    return -1;
+  }
+
+  if (!is_pow2(input_params->ring_size)) {
+    // ring size must be power of 2
+    return -1;
+  }
+
+  if (input_params->rx_queues > 255 || input_params->rx_queues < 1) {
+    // rx queue must be between 1 - 255
+    return -1;
+  }
+
+  if (input_params->tx_queues > 255 || input_params->tx_queues < 1) {
+    // tx queue must be between 1 - 255
+    return -1;
+  }
+
+  api->vpp_api->user_param = output_params;
+
+  /* Construct the API message */
+  M(MEMIF_CREATE, mp);
+
+  global_pointers_map[global_pointers_map_index] = api;
+  mp->context = global_pointers_map_index++;
+  global_pointers_map_index %= POINTER_MAP_SIZE;
+
+  mp->role = input_params->role;
+  mp->mode = input_params->mode;
+  mp->rx_queues = input_params->rx_queues;
+  mp->tx_queues = input_params->tx_queues;
+  mp->id = clib_host_to_net_u32(input_params->id);
+  mp->socket_id = clib_host_to_net_u32(input_params->socket_id);
+  mp->ring_size = clib_host_to_net_u32(input_params->ring_size);
+  mp->buffer_size = clib_host_to_net_u16(input_params->buffer_size);
+
+  int ret = vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+  if (ret < 0) {
+    return ret;
+  }
+
+  return vpp_binary_api_set_int_state(api->vpp_api, output_params->sw_if_index,
+                                      UP);
+}
+int memif_binary_api_delete_memif(vpp_plugin_binary_api_t *api,
+                                  uint32_t sw_if_index) {
+  vl_api_memif_delete_t *mp;
+  vpp_plugin_binary_api_t *hm = api;
+
+  /* Construct the API message */
+  M(MEMIF_DELETE, mp);
+
+  global_pointers_map[global_pointers_map_index] = api;
+  mp->context = global_pointers_map_index++;
+  global_pointers_map_index %= POINTER_MAP_SIZE;
+
+  mp->sw_if_index = htonl(sw_if_index);
+
+  return vpp_binary_api_send_request_wait_reply(api->vpp_api, mp);
+}
+
+static void vl_api_memif_create_reply_t_handler(
+    vl_api_memif_create_reply_t *mp) {
+  vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+  memif_output_params_t *params = binary_api->vpp_api->user_param;
+
+  binary_api->vpp_api->ret_val = ntohl(mp->retval);
+  params->sw_if_index = clib_net_to_host_u32(mp->sw_if_index);
+
+  TRANSPORT_LOGI("ret :%d", binary_api->vpp_api->ret_val);
+
+  vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static void vl_api_memif_delete_reply_t_handler(
+    vl_api_memif_delete_reply_t *mp) {
+  vpp_plugin_binary_api_t *binary_api = global_pointers_map[mp->context];
+
+  binary_api->vpp_api->ret_val = ntohl(mp->retval);
+
+  vpp_binary_api_unlock_waiting_thread(binary_api->vpp_api);
+}
+
+static int memif_binary_api_setup_handlers(
+    vpp_plugin_binary_api_t *binary_api) {
+  vpp_plugin_binary_api_t *sm __attribute__((unused)) = binary_api;
+#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_memif_api_reply_msg;
+#undef _
+  return 0;
+}
+
+vpp_plugin_binary_api_t *memif_binary_api_init(vpp_binary_api_t *api) {
+  vpp_plugin_binary_api_t *ret = malloc(sizeof(vpp_plugin_binary_api_t));
+  u8 *name = format(0, "memif_%08x%c", api_version, 0);
+  ret->msg_id_base = vl_client_get_first_plugin_msg_id((char *)name);
+  ret->vpp_api = api;
+  ret->my_client_index = api->my_client_index;
+  memif_binary_api_setup_handlers(ret);
+  return ret;
+}
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_binary_api.h b/libtransport/src/hicn/transport/core/memif_binary_api.h
new file mode 100755 (executable)
index 0000000..582aeb1
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/vpp_binary_api.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdint.h"
+
+typedef struct memif_create_params_s {
+  uint8_t role;
+  uint8_t mode;
+  uint8_t rx_queues;
+  uint8_t tx_queues;
+  uint32_t id;
+  uint32_t socket_id;
+  uint8_t secret[24];
+  uint32_t ring_size;
+  uint16_t buffer_size;
+  uint8_t hw_addr[6];
+} memif_create_params_t;
+
+typedef struct memif_output_params_s {
+  uint32_t sw_if_index;
+} memif_output_params_t;
+
+vpp_plugin_binary_api_t* memif_binary_api_init(vpp_binary_api_t* api);
+
+uint32_t memif_binary_api_get_next_memif_id(vpp_plugin_binary_api_t* api);
+
+int memif_binary_api_create_memif(vpp_plugin_binary_api_t* api,
+                                  memif_create_params_t* input_params,
+                                  memif_output_params_t* output_params);
+
+int memif_binary_api_delete_memif(vpp_plugin_binary_api_t* api,
+                                  uint32_t sw_if_index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_connector.cc b/libtransport/src/hicn/transport/core/memif_connector.cc
new file mode 100755 (executable)
index 0000000..7a67231
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/memif_connector.h>
+
+#ifdef __vpp__
+
+#include <sys/epoll.h>
+#include <cstdlib>
+
+#define CANCEL_TIMER 1
+
+namespace transport {
+
+namespace core {
+
+std::once_flag MemifConnector::flag_;
+utils::EpollEventReactor MemifConnector::main_event_reactor_;
+
+MemifConnector::MemifConnector(PacketReceivedCallback &&receive_callback,
+                               OnReconnect &&on_reconnect_callback,
+                               asio::io_service &io_service,
+                               std::string app_name)
+    : Connector(),
+      memif_worker_(nullptr),
+      timer_set_(false),
+      send_timer_(std::make_unique<utils::FdDeadlineTimer>(event_reactor_)),
+      io_service_(io_service),
+      work_(std::make_unique<asio::io_service::work>(io_service_)),
+      packet_counter_(0),
+      memif_connection_({}),
+      tx_buf_counter_(0),
+      is_connecting_(true),
+      is_reconnection_(false),
+      data_available_(false),
+      enable_burst_(false),
+      app_name_(app_name),
+      receive_callback_(receive_callback),
+      on_reconnect_callback_(on_reconnect_callback),
+      socket_filename_("") {
+  std::call_once(MemifConnector::flag_, &MemifConnector::init, this);
+}
+
+MemifConnector::~MemifConnector() { close(); }
+
+void MemifConnector::init() {
+  /* initialize memory interface */
+  int err = memif_init(controlFdUpdate, const_cast<char *>(app_name_.c_str()),
+                       nullptr, nullptr, nullptr);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_init: %s", memif_strerror(err));
+  }
+}
+
+void MemifConnector::connect(uint32_t memif_id, long memif_mode) {
+  TRANSPORT_LOGI("Creating memif");
+
+  memif_id_ = memif_id;
+  socket_filename_ = "/run/vpp/memif.sock";
+
+  createMemif(memif_id, memif_mode, nullptr);
+
+  while (is_connecting_) {
+    MemifConnector::main_event_reactor_.runOneEvent();
+  }
+
+  int err;
+
+  /* get interrupt queue id */
+  int fd = -1;
+  err = memif_get_queue_efd(memif_connection_.conn, 0, &fd);
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_get_queue_efd: %s", memif_strerror(err));
+    return;
+  }
+
+  // Remove fd from main epoll
+  main_event_reactor_.delFileDescriptor(fd);
+
+  // Add fd to epoll of instance
+  event_reactor_.addFileDescriptor(
+      fd, EPOLLIN, [this](const utils::Event &evt) -> int {
+        return onInterrupt(memif_connection_.conn, this, 0);
+      });
+
+  memif_worker_ = std::make_unique<std::thread>(
+      std::bind(&MemifConnector::threadMain, this));
+}
+
+int MemifConnector::createMemif(uint32_t index, uint8_t mode, char *s) {
+  memif_connection_t *c = &memif_connection_;
+
+  /* setting memif connection arguments */
+  memif_conn_args_t args;
+  memset(&args, 0, sizeof(args));
+
+  args.is_master = mode;
+  args.log2_ring_size = MEMIF_LOG2_RING_SIZE;
+  args.buffer_size = MEMIF_BUF_SIZE;
+  args.num_s2m_rings = 1;
+  args.num_m2s_rings = 1;
+  strncpy((char *)args.interface_name, IF_NAME, strlen(IF_NAME));
+  // strncpy((char *) args.instance_name, APP_NAME, strlen(APP_NAME));
+  args.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
+  args.socket_filename = (uint8_t *)socket_filename_.c_str();
+
+  TRANSPORT_LOGI("Socket filename: %s", args.socket_filename);
+
+  args.interface_id = index;
+  /* last argument for memif_create (void * private_ctx) is used by user
+     to identify connection. this context is returned with callbacks */
+  int err;
+  /* default interrupt */
+  if (s == nullptr) {
+    err = memif_create(&c->conn, &args, onConnect, onDisconnect, onInterrupt,
+                       this);
+
+    if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+      throw errors::RuntimeException(memif_strerror(err));
+    }
+  }
+
+  c->index = (uint16_t)index;
+  c->tx_qid = 0;
+  /* alloc memif buffers */
+  c->rx_buf_num = 0;
+  c->rx_bufs = static_cast<memif_buffer_t *>(
+      malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS));
+  c->tx_buf_num = 0;
+  c->tx_bufs = static_cast<memif_buffer_t *>(
+      malloc(sizeof(memif_buffer_t) * MAX_MEMIF_BUFS));
+
+  // memif_set_rx_mode (c->conn, MEMIF_RX_MODE_POLLING, 0);
+
+  return 0;
+}
+
+int MemifConnector::deleteMemif() {
+  memif_connection_t *c = &memif_connection_;
+
+  if (c->rx_bufs) {
+    free(c->rx_bufs);
+  }
+
+  c->rx_bufs = nullptr;
+  c->rx_buf_num = 0;
+
+  if (c->tx_bufs) {
+    free(c->tx_bufs);
+  }
+
+  c->tx_bufs = nullptr;
+  c->tx_buf_num = 0;
+
+  int err;
+  /* disconenct then delete memif connection */
+  err = memif_delete(&c->conn);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_delete: %s", memif_strerror(err));
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(c->conn != nullptr)) {
+    TRANSPORT_LOGI("memif delete fail");
+  }
+
+  return 0;
+}
+
+int MemifConnector::controlFdUpdate(int fd, uint8_t events) {
+  /* convert memif event definitions to epoll events */
+  if (events & MEMIF_FD_EVENT_DEL) {
+    return MemifConnector::main_event_reactor_.delFileDescriptor(fd);
+  }
+
+  uint32_t evt = 0;
+
+  if (events & MEMIF_FD_EVENT_READ) {
+    evt |= EPOLLIN;
+  }
+
+  if (events & MEMIF_FD_EVENT_WRITE) {
+    evt |= EPOLLOUT;
+  }
+
+  if (events & MEMIF_FD_EVENT_MOD) {
+    return MemifConnector::main_event_reactor_.modFileDescriptor(fd, evt);
+  }
+
+  return MemifConnector::main_event_reactor_.addFileDescriptor(
+      fd, evt, [](const utils::Event &evt) -> int {
+        uint32_t event = 0;
+        int memif_err = 0;
+
+        if (evt.events & EPOLLIN) {
+          event |= MEMIF_FD_EVENT_READ;
+        }
+
+        if (evt.events & EPOLLOUT) {
+          event |= MEMIF_FD_EVENT_WRITE;
+        }
+
+        if (evt.events & EPOLLERR) {
+          event |= MEMIF_FD_EVENT_ERROR;
+        }
+
+        memif_err = memif_control_fd_handler(evt.data.fd, event);
+
+        if (TRANSPORT_EXPECT_FALSE(memif_err != MEMIF_ERR_SUCCESS)) {
+          TRANSPORT_LOGI("memif_control_fd_handler: %s",
+                         memif_strerror(memif_err));
+        }
+
+        return 0;
+      });
+}
+
+int MemifConnector::bufferAlloc(long n, uint16_t qid) {
+  memif_connection_t *c = &memif_connection_;
+  int err;
+  uint16_t r;
+  /* set data pointer to shared memory and set buffer_len to shared mmeory
+   * buffer len */
+  err = memif_buffer_alloc(c->conn, qid, c->tx_bufs, n, &r, 2000);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGD("memif_buffer_alloc: %s", memif_strerror(err));
+  }
+
+  c->tx_buf_num += r;
+  TRANSPORT_LOGD("allocated %d/%ld buffers, %u free buffers", r, n,
+                 MAX_MEMIF_BUFS - c->tx_buf_num);
+  return r;
+}
+
+int MemifConnector::txBurst(uint16_t qid) {
+  memif_connection_t *c = &memif_connection_;
+  int err;
+  uint16_t r;
+  /* inform peer memif interface about data in shared memory buffers */
+  /* mark memif buffers as free */
+  err = memif_tx_burst(c->conn, qid, c->tx_bufs, c->tx_buf_num, &r);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err));
+  }
+
+  // err = memif_refill_queue(c->conn, qid, r, 0);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_tx_burst: %s", memif_strerror(err));
+    c->tx_buf_num -= r;
+    return -1;
+  }
+
+  TRANSPORT_LOGD("tx: %d/%u", r, c->tx_buf_num);
+  c->tx_buf_num -= r;
+  return 0;
+}
+
+void MemifConnector::sendCallback(const std::error_code &ec) {
+  if (TRANSPORT_EXPECT_TRUE(!ec && !is_connecting_)) {
+    doSend();
+  }
+
+  if (output_buffer_.size() > 0) {
+    send_timer_->expiresFromNow(std::chrono::microseconds(50));
+    send_timer_->asyncWait(
+        std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1));
+  } else {
+    timer_set_ = false;
+  }
+}
+
+void MemifConnector::processInputBuffer() {
+  Packet::MemBufPtr ptr;
+
+  while (input_buffer_.pop(ptr)) {
+    receive_callback_(std::move(ptr));
+  }
+}
+
+/* informs user about connected status. private_ctx is used by user to identify
+   connection (multiple connections WIP) */
+int MemifConnector::onConnect(memif_conn_handle_t conn, void *private_ctx) {
+  TRANSPORT_LOGI("memif connected!\n");
+  MemifConnector *connector = (MemifConnector *)private_ctx;
+  memif_refill_queue(conn, 0, -1, 0);
+  connector->is_connecting_ = false;
+
+  return 0;
+}
+
+/* informs user about disconnected status. private_ctx is used by user to
+   identify connection (multiple connections WIP) */
+int MemifConnector::onDisconnect(memif_conn_handle_t conn, void *private_ctx) {
+  TRANSPORT_LOGI("memif disconnected!");
+  MemifConnector *connector = (MemifConnector *)private_ctx;
+  //  TRANSPORT_LOGI ("Packet received: %u", connector->packet_counter_);
+  TRANSPORT_LOGI("Packet to process: %u",
+                 connector->memif_connection_.tx_buf_num);
+  return 0;
+}
+
+void MemifConnector::threadMain() { event_reactor_.runEventLoop(1); }
+
+int MemifConnector::onInterrupt(memif_conn_handle_t conn, void *private_ctx,
+                                uint16_t qid) {
+  MemifConnector *connector = (MemifConnector *)private_ctx;
+
+  memif_connection_t *c = &connector->memif_connection_;
+  int err = MEMIF_ERR_SUCCESS, ret_val;
+  uint16_t rx;
+
+  do {
+    err = memif_rx_burst(conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx);
+    ret_val = err;
+
+    if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS &&
+                               err != MEMIF_ERR_NOBUF)) {
+      TRANSPORT_LOGI("memif_rx_burst: %s", memif_strerror(err));
+      goto error;
+    }
+
+    c->rx_buf_num += rx;
+
+    if (TRANSPORT_EXPECT_TRUE(connector->io_service_.stopped())) {
+      TRANSPORT_LOGD("socket stopped: ignoring %u packets", rx);
+      goto error;
+    }
+
+    for (int i = 0; i < rx; i++) {
+      auto packet = connector->getPacket();
+      std::memcpy(packet->writableData(),
+                  reinterpret_cast<const uint8_t *>((c->rx_bufs + i)->data),
+                  (c->rx_bufs + i)->len);
+
+      if (!connector->input_buffer_.push(std::move(packet))) {
+        TRANSPORT_LOGI("Error pushing packet. Ring buffer full.");
+
+        // TODO Here we should consider the possibility to signal the congestion
+        // to the application, that would react properly (e.g. slow down
+        // message)
+      }
+    }
+
+    connector->io_service_.post(
+        std::bind(&MemifConnector::processInputBuffer, connector));
+
+    /* mark memif buffers and shared memory buffers as free */
+    /* free processed buffers */
+
+    err = memif_refill_queue(conn, qid, rx, 0);
+
+    if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+      TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err));
+    }
+
+    c->rx_buf_num -= rx;
+
+    TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx, rx,
+                   MAX_MEMIF_BUFS - rx);
+
+    //    if (connector->enable_burst_) {
+    //      connector->doSend();
+    //    }
+  } while (ret_val == MEMIF_ERR_NOBUF);
+
+  return 0;
+
+error:
+  err = memif_refill_queue(c->conn, qid, rx, 0);
+
+  if (TRANSPORT_EXPECT_FALSE(err != MEMIF_ERR_SUCCESS)) {
+    TRANSPORT_LOGI("memif_buffer_free: %s", memif_strerror(err));
+  }
+  c->rx_buf_num -= rx;
+
+  TRANSPORT_LOGD("freed %d buffers. %u/%u alloc/free buffers", rx,
+                 c->rx_buf_num, MAX_MEMIF_BUFS - c->rx_buf_num);
+  return 0;
+}
+
+// void MemifConnector::runEventsLoop() {
+//  io_service_.run();
+//}
+
+void MemifConnector::close() {
+  event_reactor_.stop();
+  io_service_.stop();
+
+  if (memif_worker_ && memif_worker_->joinable()) {
+    memif_worker_->join();
+    TRANSPORT_LOGD("Memif worker joined");
+    deleteMemif();
+  } else {
+    TRANSPORT_LOGD("Memif worker not joined");
+  }
+}
+
+void MemifConnector::enableBurst() { enable_burst_ = true; }
+
+void MemifConnector::send(const Packet::MemBufPtr &packet) {
+#ifdef CANCEL_TIMER
+  if (!timer_set_) {
+    timer_set_ = true;
+    send_timer_->expiresFromNow(std::chrono::microseconds(50));
+    send_timer_->asyncWait(
+        std::bind(&MemifConnector::sendCallback, this, std::placeholders::_1));
+  }
+#endif
+
+  {
+    utils::SpinLock::Acquire locked(write_msgs_lock_);
+    output_buffer_.push_back(packet);
+  }
+}
+
+int MemifConnector::doSend() {
+  std::size_t max = 0;
+  uint16_t n = 0;
+  std::size_t size = 0;
+
+  {
+    utils::SpinLock::Acquire locked(write_msgs_lock_);
+    size = output_buffer_.size();
+  }
+
+  do {
+    max = size < MAX_MEMIF_BUFS ? size : MAX_MEMIF_BUFS;
+
+    if (TRANSPORT_EXPECT_FALSE(
+            (n = bufferAlloc(max, memif_connection_.tx_qid)) < 0)) {
+      TRANSPORT_LOGI("Error allocating buffers.");
+      return -1;
+    }
+
+    for (uint16_t i = 0; i < n; i++) {
+      utils::SpinLock::Acquire locked(write_msgs_lock_);
+
+      auto packet = output_buffer_.front().get();
+      const utils::MemBuf *current = packet;
+      std::size_t offset = 0;
+      uint8_t *shared_buffer =
+          reinterpret_cast<uint8_t *>(memif_connection_.tx_bufs[i].data);
+      do {
+        std::memcpy(shared_buffer + offset, current->data(), current->length());
+        offset += current->length();
+        current = current->next();
+      } while (current != packet);
+
+      memif_connection_.tx_bufs[i].len = uint32_t(offset);
+
+      TRANSPORT_LOGD("Packet size : %zu", offset);
+
+      output_buffer_.pop_front();
+    }
+
+    txBurst(memif_connection_.tx_qid);
+
+    utils::SpinLock::Acquire locked(write_msgs_lock_);
+    size = output_buffer_.size();
+  } while (size > 0);
+
+  return 0;
+}
+
+void MemifConnector::state() {
+  TRANSPORT_LOGD("Event reactor map: %zu", event_reactor_.mapSize());
+  TRANSPORT_LOGD("Output buffer %zu", output_buffer_.size());
+}
+
+void MemifConnector::send(const uint8_t *packet, std::size_t len,
+                          const PacketSentCallback &packet_sent) {}
+
+}  // end namespace core
+
+}  // end namespace transport
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/memif_connector.h b/libtransport/src/hicn/transport/core/memif_connector.h
new file mode 100755 (executable)
index 0000000..24c8ac1
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/fd_deadline_timer.h>
+#include <hicn/transport/utils/ring_buffer.h>
+
+#include <asio.hpp>
+#include <deque>
+#include <mutex>
+#include <thread>
+
+#ifdef __vpp__
+
+#define _Static_assert static_assert
+
+extern "C" {
+#include <memif/libmemif.h>
+};
+
+namespace transport {
+
+namespace core {
+
+typedef struct {
+  uint16_t index;
+  /* memif conenction handle */
+  memif_conn_handle_t conn;
+  /* transmit queue id */
+  uint16_t tx_qid;
+  /* tx buffers */
+  memif_buffer_t *tx_bufs;
+  /* allocated tx buffers counter */
+  /* number of tx buffers pointing to shared memory */
+  uint16_t tx_buf_num;
+  /* rx buffers */
+  memif_buffer_t *rx_bufs;
+  /* allcoated rx buffers counter */
+  /* number of rx buffers pointing to shared memory */
+  uint16_t rx_buf_num;
+  /* interface ip address */
+  uint8_t ip_addr[4];
+} memif_connection_t;
+
+#define APP_NAME "libtransport"
+#define IF_NAME "vpp_connection"
+
+#define MAX_MEMIF_BUFS 1024
+#define MEMIF_BUF_SIZE 2048
+#define MEMIF_LOG2_RING_SIZE 11
+
+class MemifConnector : public Connector {
+ public:
+  MemifConnector(PacketReceivedCallback &&receive_callback,
+                 OnReconnect &&on_reconnect_callback,
+                 asio::io_service &io_service,
+                 std::string app_name = "Libtransport");
+
+  ~MemifConnector() override;
+
+  void send(const Packet::MemBufPtr &packet) override;
+
+  void send(const uint8_t *packet, std::size_t len,
+            const PacketSentCallback &packet_sent = 0) override;
+
+  void close() override;
+
+  void connect(uint32_t memif_id, long memif_mode);
+
+  //  void runEventsLoop();
+
+  void enableBurst() override;
+
+  void state() override;
+
+  TRANSPORT_ALWAYS_INLINE uint32_t getMemifId() { return memif_id_; };
+
+ private:
+  void init();
+
+  int doSend();
+
+  int createMemif(uint32_t index, uint8_t mode, char *s);
+
+  uint32_t getMemifConfiguration();
+
+  int deleteMemif();
+
+  static int controlFdUpdate(int fd, uint8_t events);
+
+  static int onConnect(memif_conn_handle_t conn, void *private_ctx);
+
+  static int onDisconnect(memif_conn_handle_t conn, void *private_ctx);
+
+  static int onInterrupt(memif_conn_handle_t conn, void *private_ctx,
+                         uint16_t qid);
+
+  void threadMain();
+
+  int txBurst(uint16_t qid);
+
+  int bufferAlloc(long n, uint16_t qid);
+
+  void sendCallback(const std::error_code &ec);
+
+  void processInputBuffer();
+
+ private:
+  static utils::EpollEventReactor main_event_reactor_;
+  static std::unique_ptr<std::thread> main_worker_;
+
+  int epfd;
+  std::unique_ptr<std::thread> memif_worker_;
+  utils::EpollEventReactor event_reactor_;
+  volatile bool timer_set_;
+  std::unique_ptr<utils::FdDeadlineTimer> send_timer_;
+  asio::io_service &io_service_;
+  std::unique_ptr<asio::io_service::work> work_;
+  uint32_t packet_counter_;
+  memif_connection_t memif_connection_;
+  uint16_t tx_buf_counter_;
+
+  PacketRing input_buffer_;
+  volatile bool is_connecting_;
+  volatile bool is_reconnection_;
+  bool data_available_;
+  bool enable_burst_;
+  uint32_t memif_id_;
+  uint8_t memif_mode_;
+  std::string app_name_;
+  uint16_t transmission_index_;
+  PacketReceivedCallback receive_callback_;
+  OnReconnect on_reconnect_callback_;
+  utils::SpinLock write_msgs_lock_;
+  std::string socket_filename_;
+
+  static std::once_flag flag_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/name.cc b/libtransport/src/hicn/transport/core/name.cc
new file mode 100755 (executable)
index 0000000..10c45eb
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/errors/tokenizer_exception.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+namespace transport {
+
+namespace core {
+
+Name::Name() { name_ = createEmptyName(); }
+
+Name::Name(int family, const uint8_t *ip_address, std::uint32_t suffix)
+    : name_(createEmptyName()) {
+  std::size_t length;
+  uint8_t *dst = NULL;
+
+  if (family == AF_INET) {
+    dst = name_->ip4.prefix_as_u8;
+    length = IPV4_ADDR_LEN;
+    name_->type = HNT_CONTIGUOUS_V4;
+  } else if (family == AF_INET6) {
+    dst = name_->ip6.prefix_as_u8;
+    length = IPV6_ADDR_LEN;
+    name_->type = HNT_CONTIGUOUS_V6;
+  } else {
+    throw errors::RuntimeException("Specified name family does not exist.");
+  }
+
+  std::memcpy(dst, ip_address, length);
+  *reinterpret_cast<std::uint32_t *>(dst + length) = suffix;
+}
+
+Name::Name(const char *name, uint32_t segment) {
+  name_ = createEmptyName();
+
+  if (hicn_name_create(name, segment, name_.get()) < 0) {
+    throw errors::InvalidIpAddressException();
+  }
+}
+
+Name::Name(const std::string &uri, uint32_t segment)
+    : Name(uri.c_str(), segment) {}
+
+Name::Name(const std::string &uri) {
+  utils::StringTokenizer tokenizer(uri, "|");
+  std::string ip_address;
+  std::string seq_number;
+
+  ip_address = tokenizer.nextToken();
+
+  try {
+    seq_number = tokenizer.nextToken();
+  } catch (errors::TokenizerException &e) {
+    seq_number = "0";
+  }
+
+  name_ = createEmptyName();
+
+  if (hicn_name_create(ip_address.c_str(), (uint32_t)atoi(seq_number.c_str()),
+                       name_.get()) < 0) {
+    throw errors::InvalidIpAddressException();
+  }
+}
+
+Name::Name(const Name &name, bool hard_copy) {
+  name_ = createEmptyName();
+
+  if (hard_copy) {
+    if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) {
+      throw errors::MalformedNameException();
+    }
+  } else {
+    *this->name_ = *name.name_;
+  }
+}
+
+Name::Name(Name &&name) : name_(std::move(name.name_)) {}
+
+Name &Name::operator=(const Name &name) {
+  if (hicn_name_copy(this->name_.get(), name.name_.get()) < 0) {
+    throw errors::MalformedNameException();
+  }
+
+  return *this;
+}
+
+bool Name::operator==(const Name &name) const {
+  return this->equals(name, true);
+}
+
+bool Name::operator!=(const Name &name) const {
+  return !this->operator==(name);
+}
+
+Name::operator bool() const {
+  return bool(hicn_name_empty((hicn_name_t *)name_.get()));
+}
+
+bool Name::equals(const Name &name, bool consider_segment) const {
+  return !hicn_name_compare(name_.get(), name.name_.get(), consider_segment);
+}
+
+std::string Name::toString() const {
+  char *name = new char[100];
+  int ret = hicn_name_ntop(name_.get(), name, standard_name_string_length);
+  if (ret < 0) {
+    throw errors::MalformedNameException();
+  }
+  std::string name_string(name);
+  delete[] name;
+
+  return name_string;
+}
+
+uint32_t Name::getHash32() const {
+  uint32_t hash;
+  if (hicn_name_hash((hicn_name_t *)name_.get(), &hash) < 0) {
+    throw errors::RuntimeException("Error computing the hash of the name!");
+  }
+  return hash;
+}
+
+void Name::clear() {
+  name_.reset();
+  name_ = createEmptyName();
+};
+
+Name::Type Name::getType() const { return name_->type; }
+
+uint32_t Name::getSuffix() const {
+  uint32_t ret = 0;
+  if (hicn_name_get_seq_number((hicn_name_t *)name_.get(), &ret) < 0) {
+    throw errors::RuntimeException(
+        "Impossible to retrieve the sequence number from the name.");
+  }
+  return ret;
+}
+
+Name &Name::setSuffix(uint32_t seq_number) {
+  if (hicn_name_set_seq_number(name_.get(), seq_number) < 0) {
+    throw errors::RuntimeException(
+        "Impossible to set the sequence number to the name.");
+  }
+
+  return *this;
+}
+
+std::shared_ptr<Sockaddr> Name::getAddress() const {
+  Sockaddr *ret = nullptr;
+
+  switch (name_->type) {
+    case HNT_CONTIGUOUS_V4:
+    case HNT_IOV_V4:
+      ret = (Sockaddr *)new Sockaddr4;
+      break;
+    case HNT_CONTIGUOUS_V6:
+    case HNT_IOV_V6:
+      ret = (Sockaddr *)new Sockaddr6;
+      break;
+    default:
+      throw errors::MalformedNameException();
+  }
+
+  if (hicn_name_to_sockaddr_address((hicn_name_t *)name_.get(), ret) < 0) {
+    throw errors::MalformedNameException();
+  }
+
+  return std::shared_ptr<Sockaddr>(ret);
+}
+
+ip_address_t Name::toIpAddress() const {
+  ip_address_t ret;
+  std::memset(&ret, 0, sizeof(ret));
+
+  if (hicn_name_to_ip_address(name_.get(), &ret) < 0) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  return ret;
+}
+
+int Name::getAddressFamily() const {
+  int ret = 0;
+
+  if (hicn_name_get_family(name_.get(), &ret) < 0) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  return ret;
+}
+
+void Name::copyToDestination(uint8_t *destination, bool include_suffix) const {
+  if (hicn_name_copy_to_destination(destination, name_.get(), include_suffix) <
+      0) {
+    throw errors::RuntimeException(
+        "Impossibe to copy the name into the "
+        "provided destination");
+  }
+}
+
+std::ostream &operator<<(std::ostream &os, const Name &name) {
+  const std::string &str = name.toString();
+  //  os << "core:/";
+  os << str;
+
+  return os;
+}
+
+}  // end namespace core
+
+}  // end namespace transport
+
+namespace std {
+size_t hash<transport::core::Name>::operator()(
+    const transport::core::Name &name) const {
+  return name.getHash32();
+}
+
+}  // end namespace std
diff --git a/libtransport/src/hicn/transport/core/name.h b/libtransport/src/hicn/transport/core/name.h
new file mode 100755 (executable)
index 0000000..b0da150
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <list>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+};
+
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+typedef struct sockaddr_in6 Sockaddr6;
+typedef struct sockaddr_in Sockaddr4;
+typedef struct sockaddr Sockaddr;
+
+enum class HashAlgorithm : uint8_t;
+
+class Name {
+  friend class Packet;
+  friend class ContentObject;
+  friend class Interest;
+
+  static const uint32_t standard_name_string_length = 100;
+
+ public:
+  using NameStruct = hicn_name_t;
+  using Type = hicn_name_type_t;
+
+  Name();
+
+  /**
+   * @brief Create name
+   * @param name The null-terminated URI string
+   */
+  Name(const char *name, uint32_t segment);
+
+  Name(int family, const uint8_t *ip_address, std::uint32_t suffix = 0);
+
+  Name(const std::string &uri, uint32_t segment);
+
+  Name(const std::string &uri);
+
+  Name(const Name &name, bool hard_copy = false);
+
+  Name(Name &&name);
+
+  Name &operator=(const Name &name);
+
+  bool operator==(const Name &name) const;
+
+  bool operator!=(const Name &name) const;
+
+  operator bool() const;
+
+  std::string toString() const;
+
+  bool equals(const Name &name, bool consider_segment = true) const;
+
+  uint32_t getHash32() const;
+
+  void clear();
+
+  Type getType() const;
+
+  uint32_t getSuffix() const;
+
+  std::shared_ptr<Sockaddr> getAddress() const;
+
+  Name &setSuffix(uint32_t seq_number);
+
+  ip_address_t toIpAddress() const;
+
+  void copyToDestination(uint8_t *destination,
+                         bool include_suffix = false) const;
+
+  int getAddressFamily() const;
+
+ private:
+  TRANSPORT_ALWAYS_INLINE NameStruct *getStructReference() const {
+    if (TRANSPORT_EXPECT_TRUE(name_ != nullptr)) {
+      return name_.get();
+    }
+
+    return nullptr;
+  }
+
+  static TRANSPORT_ALWAYS_INLINE std::unique_ptr<NameStruct> createEmptyName() {
+    NameStruct *name = new NameStruct;
+    name->type = HNT_UNSPEC;
+    return std::unique_ptr<NameStruct>(name);
+  };
+
+  std::unique_ptr<NameStruct> name_;
+};
+
+std::ostream &operator<<(std::ostream &os, const Name &name);
+
+}  // end namespace core
+
+}  // end namespace transport
+
+namespace std {
+template <>
+struct hash<transport::core::Name> {
+  size_t operator()(const transport::core::Name &name) const;
+};
+
+}  // end namespace std
diff --git a/libtransport/src/hicn/transport/core/packet.cc b/libtransport/src/hicn/transport/core/packet.cc
new file mode 100755 (executable)
index 0000000..74f407f
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/malformed_packet_exception.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/log.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/error.h>
+}
+
+namespace transport {
+
+namespace core {
+
+const core::Name Packet::base_name("0::0|0");
+
+Packet::Packet(Format format)
+    : packet_(utils::MemBuf::create(getHeaderSizeFromFormat(format)).release()),
+      packet_start_(packet_->writableData()),
+      header_head_(packet_.get()),
+      payload_head_(nullptr),
+      format_(format) {
+  if (hicn_packet_init_header(format, (hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Unexpected error initializing the packet.");
+  }
+
+  packet_->append(getHeaderSizeFromFormat(format_));
+}
+
+Packet::Packet(MemBufPtr &&buffer)
+    : packet_(std::move(buffer)),
+      packet_start_(packet_->writableData()),
+      header_head_(packet_.get()),
+      payload_head_(nullptr),
+      format_(getFormatFromBuffer(packet_start_)) {
+
+  auto header_size = getHeaderSizeFromFormat(format_);
+  int signature_size = 0;
+
+  if (_is_ah(format_)) {
+    signature_size = getSignatureSize();
+  }
+
+  auto payload_length = packet_->length() - header_size - signature_size;
+
+  if (!payload_length && !signature_size) {
+    return;
+  }
+
+  packet_->trimEnd(packet_->length());
+
+  if (signature_size) {
+    auto sig = packet_->cloneOne();
+    sig->advance(header_size);
+    sig->append(signature_size);
+    packet_->appendChain(std::move(sig));
+  }
+
+  if (payload_length) {
+    auto payload = packet_->cloneOne();
+    payload_head_ = payload.get();
+    payload_head_->advance(header_size + signature_size);
+    payload_head_->append(payload_length);
+    packet_->prependChain(std::move(payload));
+    packet_->append(header_size);
+  }
+
+
+}
+
+Packet::Packet(const uint8_t *buffer, std::size_t size)
+    : Packet(MemBufPtr(utils::MemBuf::copyBuffer(buffer, size).release())) {}
+
+Packet::Packet(Packet &&other)
+    : packet_(std::move(other.packet_)),
+      packet_start_(packet_->writableData()),
+      header_head_(other.header_head_),
+      payload_head_(other.payload_head_),
+      format_(other.format_) {
+  other.packet_start_ = nullptr;
+  other.header_head_ = nullptr;
+  other.payload_head_ = nullptr;
+  other.format_ = HF_UNSPEC;
+}
+
+Packet::~Packet() {
+  if (packet_->isChained()) {
+    packet_->separateChain(packet_->next(), packet_->prev());
+  }
+}
+
+std::size_t Packet::getHeaderSizeFromFormat(Format format,
+                                            size_t signature_size) {
+  std::size_t header_length;
+  hicn_packet_get_header_length_from_format(format, &header_length);
+  int is_ah = _is_ah(format);
+  return is_ah * (header_length + signature_size) + (!is_ah) * header_length;
+}
+
+std::size_t Packet::getHeaderSizeFromBuffer(Format format,
+                                            const uint8_t *buffer) {
+  size_t header_length;
+  if (hicn_packet_get_header_length(format, (hicn_header_t *)buffer,
+                                    &header_length) < 0) {
+    throw errors::MalformedPacketException();
+  }
+  return header_length;
+}
+
+bool Packet::isInterest(const uint8_t *buffer) {
+  bool is_interest = false;
+
+  if (TRANSPORT_EXPECT_FALSE(hicn_packet_test_ece((const hicn_header_t *)buffer,
+                                                  &is_interest) < 0)) {
+    throw errors::RuntimeException(
+        "Impossible to retrieve ece flag from packet");
+  }
+
+  return !is_interest;
+}
+
+Packet::Format Packet::getFormatFromBuffer(const uint8_t *buffer) {
+  Format format = HF_UNSPEC;
+
+  if (TRANSPORT_EXPECT_FALSE(
+          hicn_packet_get_format((const hicn_header_t *)buffer, &format) < 0)) {
+    throw errors::MalformedPacketException();
+  }
+
+  return format;
+}
+
+std::size_t Packet::getPayloadSizeFromBuffer(Format format,
+                                             const uint8_t *buffer) {
+  std::size_t payload_length;
+  if (TRANSPORT_EXPECT_FALSE(
+          hicn_packet_get_payload_length(format, (hicn_header_t *)buffer,
+                                         &payload_length) < 0)) {
+    throw errors::MalformedPacketException();
+  }
+
+  return payload_length;
+}
+
+std::size_t Packet::payloadSize() const {
+  return getPayloadSizeFromBuffer(format_, packet_start_);
+}
+
+std::size_t Packet::headerSize() const {
+  return getHeaderSizeFromBuffer(format_, packet_start_);
+}
+
+const uint8_t *Packet::start() const { return packet_start_; }
+
+void Packet::setLifetime(uint32_t lifetime) {
+  if (hicn_interest_set_lifetime((hicn_header_t *)packet_start_, lifetime) <
+      0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+uint32_t Packet::getLifetime() const {
+  uint32_t lifetime = 0;
+
+  if (hicn_packet_get_lifetime((hicn_header_t *)packet_start_, &lifetime) < 0) {
+    throw errors::MalformedPacketException();
+  }
+
+  return lifetime;
+}
+
+Packet &Packet::appendPayload(std::unique_ptr<utils::MemBuf> &&payload) {
+  if (!payload_head_) {
+    payload_head_ = payload.get();
+  }
+
+  header_head_->prependChain(std::move(payload));
+  updateLength();
+  return *this;
+}
+
+Packet &Packet::appendPayload(const uint8_t *buffer, std::size_t length) {
+  return appendPayload(utils::MemBuf::copyBuffer(buffer, length));
+}
+
+Packet &Packet::appendHeader(std::unique_ptr<utils::MemBuf> &&header) {
+  if (!payload_head_) {
+    header_head_->prependChain(std::move(header));
+  } else {
+    payload_head_->prependChain(std::move(header));
+  }
+
+  updateLength();
+  return *this;
+}
+
+Packet &Packet::appendHeader(const uint8_t *buffer, std::size_t length) {
+  return appendHeader(utils::MemBuf::copyBuffer(buffer, length));
+}
+
+utils::Array<uint8_t> Packet::getPayload() const {
+  if (TRANSPORT_EXPECT_FALSE(payload_head_ == nullptr)) {
+    return utils::Array<uint8_t>();
+  }
+
+  // Hopefully the payload is contiguous
+  if (TRANSPORT_EXPECT_FALSE(payload_head_->next() != header_head_)) {
+    payload_head_->gather(payloadSize());
+  }
+
+  return utils::Array<uint8_t>(payload_head_->writableData(),
+                               payload_head_->length());
+}
+
+Packet &Packet::updateLength(std::size_t length) {
+  std::size_t total_length = length;
+
+  for (utils::MemBuf *current = payload_head_;
+       current && current != header_head_; current = current->next()) {
+    total_length += current->length();
+  }
+
+  if (hicn_packet_set_payload_length(format_, (hicn_header_t *)packet_start_,
+                                     total_length) < 0) {
+    throw errors::RuntimeException("Error setting the packet payload.");
+  }
+
+  return *this;
+}
+
+PayloadType Packet::getPayloadType() const {
+  hicn_payload_type_t ret = HPT_UNSPEC;
+
+  if (hicn_packet_get_payload_type((hicn_header_t *)packet_start_, &ret) < 0) {
+    throw errors::RuntimeException("Impossible to retrieve payload type.");
+  }
+
+  return PayloadType(ret);
+}
+
+Packet &Packet::setPayloadType(PayloadType payload_type) {
+  if (hicn_packet_set_payload_type((hicn_header_t *)packet_start_,
+                                   hicn_payload_type_t(payload_type)) < 0) {
+    throw errors::RuntimeException("Error setting payload type of the packet.");
+  }
+
+  return *this;
+}
+
+Packet::Format Packet::getFormat() const {
+  if (format_ == HF_UNSPEC) {
+    if (hicn_packet_get_format((hicn_header_t *)packet_start_, &format_) < 0) {
+      throw errors::MalformedPacketException();
+    }
+  }
+
+  return format_;
+}
+
+const std::shared_ptr<utils::MemBuf> Packet::data() { return packet_; }
+
+void Packet::dump() const {
+  TRANSPORT_LOGI("The header length is: %zu", headerSize());
+  TRANSPORT_LOGI("The payload length is: %zu", payloadSize());
+  std::cerr << std::endl;
+
+  hicn_packet_dump((uint8_t *)packet_->data(), headerSize());
+  // hicn_packet_dump((uint8_t *)packet_->next()->data(), payloadSize());
+}
+
+void Packet::setSignatureSize(std::size_t size_bytes) {
+  int ret = hicn_packet_set_signature_size(
+      format_, (hicn_header_t *)packet_start_, size_bytes);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Packet without Authentication Header.");
+  }
+}
+
+std::size_t Packet::getSignatureSize() const {
+  size_t size_bytes;
+  int ret = hicn_packet_get_signature_size(
+      format_, (hicn_header_t *)packet_start_, &size_bytes);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Packet without Authentication Header.");
+  }
+
+  return size_bytes;
+}
+
+void Packet::setSignature(std::unique_ptr<utils::MemBuf> &&signature) {
+  // Check if packet already contains a signature
+  auto header = header_head_->next();
+  while (header != payload_head_) {
+    header->unlink();
+    header = header->next();
+  }
+
+  appendHeader(std::move(signature));
+}
+
+void Packet::setSignatureTimestamp(const uint64_t &timestamp) {
+  int ret = hicn_packet_set_signature_timestamp(
+    format_, (hicn_header_t *)packet_start_, timestamp);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error setting the signature timestamp.");
+  }
+}
+
+uint64_t Packet::getSignatureTimestamp() const {
+  uint64_t return_value;
+  int ret = hicn_packet_get_signature_timestamp(
+    format_, (hicn_header_t *)packet_start_, &return_value);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error getting the signature timestamp.");
+  }
+
+  return return_value;
+}
+
+void Packet::setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm) {
+  int ret = hicn_packet_set_validation_algorithm(
+  format_, (hicn_header_t *)packet_start_, uint8_t(validation_algorithm));
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error setting the validation algorithm.");
+  }
+}
+
+utils::CryptoSuite Packet::getValidationAlgorithm() const {
+  uint8_t return_value;
+  int ret = hicn_packet_get_validation_algorithm(
+    format_, (hicn_header_t *)packet_start_, &return_value);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error getting the validation algorithm.");
+  }
+
+  return utils::CryptoSuite(return_value);
+}
+
+void Packet::setKeyId(const utils::KeyId &key_id) {
+  int ret = hicn_packet_set_key_id(
+    format_, (hicn_header_t *)packet_start_, key_id.first);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error setting the key id.");
+  }
+}
+
+utils::KeyId Packet::getKeyId() const {
+  utils::KeyId return_value;
+  int ret = hicn_packet_get_key_id(
+    format_, (hicn_header_t *)packet_start_, &return_value.first, &return_value.second);
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error getting the validation algorithm.");
+  }
+
+  return return_value;
+}
+
+utils::CryptoHash Packet::computeDigest(HashAlgorithm algorithm) const {
+  utils::CryptoHasher hasher(static_cast<utils::CryptoHashType>(algorithm));
+  hasher.init();
+
+  // Copy IP+TCP/ICMP header before zeroing them
+  hicn_header_t header_copy;
+
+  hicn_packet_copy_header(format_, (hicn_header_t *)packet_start_, &header_copy,
+                          false);
+
+  const_cast<Packet *>(this)->resetForHash();
+
+  std::size_t payload_len = getPayloadSizeFromBuffer(format_, packet_start_);
+  std::size_t header_length = getHeaderSizeFromFormat(format_);
+  std::size_t signature_size = _is_ah(format_) ? getSignatureSize() : 0;
+
+  hasher.updateBytes(packet_start_,
+                     payload_len + header_length + signature_size);
+
+  hicn_packet_copy_header(format_, &header_copy, (hicn_header_t *)packet_start_,
+                          false);
+
+  return hasher.finalize();
+}
+
+void Packet::setChecksum() {
+  uint16_t partial_csum = 0;
+
+  for (utils::MemBuf *current = header_head_->next();
+       current && current != header_head_; current = current->next()) {
+    if (partial_csum != 0) {
+      partial_csum = ~partial_csum;
+    }
+    partial_csum = csum(current->data(), current->length(), partial_csum);
+  }
+  if (hicn_packet_compute_header_checksum(
+          format_, (hicn_header_t *)packet_start_, partial_csum) < 0) {
+    throw errors::MalformedPacketException();
+  }
+}
+
+bool Packet::checkIntegrity() const {
+  if (hicn_packet_check_integrity(format_, (hicn_header_t *)packet_start_) <
+      0) {
+    return false;
+  }
+
+  return true;
+}
+
+Packet &Packet::setSyn() {
+  if (hicn_packet_set_syn((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error setting syn bit in the packet.");
+  }
+
+  return *this;
+}
+
+Packet &Packet::resetSyn() {
+  if (hicn_packet_reset_syn((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error resetting syn bit in the packet.");
+  }
+
+  return *this;
+}
+
+bool Packet::testSyn() const {
+  bool res = false;
+  if (hicn_packet_test_syn((hicn_header_t *)packet_start_, &res) < 0) {
+    throw errors::RuntimeException("Error testing syn bit in the packet.");
+  }
+
+  return res;
+}
+
+Packet &Packet::setAck() {
+  if (hicn_packet_set_ack((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error setting ack bit in the packet.");
+  }
+
+  return *this;
+}
+
+Packet &Packet::resetAck() {
+  if (hicn_packet_reset_ack((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error resetting ack bit in the packet.");
+  }
+
+  return *this;
+}
+
+bool Packet::testAck() const {
+  bool res = false;
+  if (hicn_packet_test_ack((hicn_header_t *)packet_start_, &res) < 0) {
+    throw errors::RuntimeException("Error testing ack bit in the packet.");
+  }
+
+  return res;
+}
+
+Packet &Packet::setRst() {
+  if (hicn_packet_set_rst((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error setting rst bit in the packet.");
+  }
+
+  return *this;
+}
+
+Packet &Packet::resetRst() {
+  if (hicn_packet_reset_rst((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error resetting rst bit in the packet.");
+  }
+
+  return *this;
+}
+
+bool Packet::testRst() const {
+  bool res = false;
+  if (hicn_packet_test_rst((hicn_header_t *)packet_start_, &res) < 0) {
+    throw errors::RuntimeException("Error testing rst bit in the packet.");
+  }
+
+  return res;
+}
+
+Packet &Packet::setFin() {
+  if (hicn_packet_set_fin((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error setting fin bit in the packet.");
+  }
+
+  return *this;
+}
+
+Packet &Packet::resetFin() {
+  if (hicn_packet_reset_fin((hicn_header_t *)packet_start_) < 0) {
+    throw errors::RuntimeException("Error resetting fin bit in the packet.");
+  }
+
+  return *this;
+}
+
+bool Packet::testFin() const {
+  bool res = false;
+  if (hicn_packet_test_fin((hicn_header_t *)packet_start_, &res) < 0) {
+    throw errors::RuntimeException("Error testing fin bit in the packet.");
+  }
+
+  return res;
+}
+
+Packet &Packet::resetFlags() {
+  resetSyn();
+  resetAck();
+  resetRst();
+  resetFin();
+
+  return *this;
+}
+
+std::string Packet::printFlags() const {
+  std::string flags = "";
+  if (testSyn()) {
+    flags += "S";
+  }
+  if (testAck()) {
+    flags += "A";
+  }
+  if (testRst()) {
+    flags += "R";
+  }
+  if (testFin()) {
+    flags += "F";
+  }
+  return flags;
+}
+
+Packet &Packet::setSrcPort(uint16_t srcPort) {
+  if (hicn_packet_set_src_port((hicn_header_t *)packet_start_, srcPort) < 0) {
+    throw errors::RuntimeException("Error setting source port in the packet.");
+  }
+
+  return *this;
+}
+
+Packet &Packet::setDstPort(uint16_t dstPort) {
+  if (hicn_packet_set_dst_port((hicn_header_t *)packet_start_, dstPort) < 0) {
+    throw errors::RuntimeException(
+        "Error setting destination port in the packet.");
+  }
+
+  return *this;
+}
+
+uint16_t Packet::getSrcPort() const {
+  uint16_t port = 0;
+
+  if (hicn_packet_get_src_port((hicn_header_t *)packet_start_, &port) < 0) {
+    throw errors::RuntimeException("Error reading source port in the packet.");
+  }
+
+  return port;
+}
+
+uint16_t Packet::getDstPort() const {
+  uint16_t port = 0;
+
+  if (hicn_packet_get_dst_port((hicn_header_t *)packet_start_, &port) < 0) {
+    throw errors::RuntimeException(
+        "Error reading destination port in the packet.");
+  }
+
+  return port;
+}
+
+Packet &Packet::setTTL(uint8_t hops) {
+  if (hicn_packet_set_hoplimit((hicn_header_t *)packet_start_, hops) < 0) {
+    throw errors::RuntimeException("Error setting TTL.");
+  }
+
+  return *this;
+}
+
+uint8_t Packet::getTTL() const {
+  uint8_t hops = 0;
+  if (hicn_packet_get_hoplimit((hicn_header_t *)packet_start_, &hops) < 0) {
+    throw errors::RuntimeException("Error reading TTL.");
+  }
+
+  return hops;
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/packet.h b/libtransport/src/hicn/transport/core/packet.h
new file mode 100755 (executable)
index 0000000..0a56734
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/payload_type.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+#include <hicn/transport/utils/crypto_hasher.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/key_id.h>
+
+namespace utils {
+class Signer;
+class Verifier;
+}  // namespace utils
+
+namespace transport {
+
+namespace core {
+
+/*
+ * Basic IP packet, modelled as circular chain of buffers:
+ * Header = H
+ * Payload = P
+ *
+ * H_0 --> H_1 --> H_2 --> P_0 --> P_1 --> P_2
+ *  \_______________________________________|
+ */
+
+class Packet : public std::enable_shared_from_this<Packet> {
+  friend class utils::Signer;
+  friend class utils::Verifier;
+
+ public:
+  using MemBufPtr = std::shared_ptr<utils::MemBuf>;
+  using Format = hicn_format_t;
+  static constexpr size_t default_mtu = 1500;
+
+  /**
+   * Create new IP packet. Here we allocate just the header,
+   * the eventual payload will be added by prepending the payload buffer
+   * to the buffer chain whose the fist buffer is the header itself.
+   */
+  Packet(Format format = HF_UNSPEC);
+
+  /**
+   * Create new IP packet using raw buffer.
+   */
+  Packet(const uint8_t *buffer, std::size_t size);
+  Packet(MemBufPtr &&buffer);
+
+  /*
+   * Enforce zero-copy lifestyle.
+   */
+  Packet(const Packet &other) = delete;
+  Packet &operator=(const Packet &other) = delete;
+
+  /*
+   * Move constructor.
+   */
+  Packet(Packet &&other);
+
+  friend bool operator==(const Packet &l_packet, const Packet &r_packet);
+
+  virtual ~Packet();
+
+  static std::size_t getHeaderSizeFromFormat(Format format,
+                                             std::size_t signature_size = 0);
+
+  static std::size_t getHeaderSizeFromBuffer(Format format,
+                                             const uint8_t *buffer);
+
+  static std::size_t getPayloadSizeFromBuffer(Format format,
+                                              const uint8_t *buffer);
+
+  static bool isInterest(const uint8_t *buffer);
+
+  static Format getFormatFromBuffer(const uint8_t *buffer);
+
+  std::size_t payloadSize() const;
+
+  std::size_t headerSize() const;
+
+  const std::shared_ptr<utils::MemBuf> data();
+
+  const uint8_t *start() const;
+
+  virtual void setLifetime(uint32_t lifetime);
+
+  virtual uint32_t getLifetime() const;
+
+  Packet &appendPayload(const uint8_t *buffer, std::size_t length);
+
+  Packet &appendPayload(std::unique_ptr<utils::MemBuf> &&payload);
+
+  Packet &appendHeader(std::unique_ptr<utils::MemBuf> &&header);
+
+  Packet &appendHeader(const uint8_t *buffer, std::size_t length);
+
+  utils::Array<uint8_t> getPayload() const;
+
+  Packet &updateLength(std::size_t length = 0);
+
+  PayloadType getPayloadType() const;
+
+  Packet &setPayloadType(PayloadType payload_type);
+
+  Format getFormat() const;
+
+  void dump() const;
+
+  virtual void setLocator(const ip_address_t &locator) = 0;
+
+  virtual ip_address_t getLocator() const = 0;
+
+  void setSignatureSize(std::size_t size_bytes);
+
+  std::size_t getSignatureSize() const;
+
+  void setSignatureTimestamp(const uint64_t &timestamp);
+
+  uint64_t getSignatureTimestamp() const;
+
+  void setValidationAlgorithm(const utils::CryptoSuite &validation_algorithm);
+
+  utils::CryptoSuite getValidationAlgorithm() const;
+
+  void setKeyId(const utils::KeyId &key_id);
+
+  utils::KeyId getKeyId() const;
+
+  void setSignature(std::unique_ptr<utils::MemBuf> &&signature);
+
+  virtual utils::CryptoHash computeDigest(HashAlgorithm algorithm) const;
+
+  void setChecksum();
+
+  bool checkIntegrity() const;
+
+  Packet &setSyn();
+  Packet &resetSyn();
+  bool testSyn() const;
+  Packet &setAck();
+  Packet &resetAck();
+  bool testAck() const;
+  Packet &setRst();
+  Packet &resetRst();
+  bool testRst() const;
+  Packet &setFin();
+  Packet &resetFin();
+  bool testFin() const;
+  Packet &resetFlags();
+  std::string printFlags() const;
+
+  Packet &setSrcPort(uint16_t srcPort);
+  Packet &setDstPort(uint16_t dstPort);
+  uint16_t getSrcPort() const;
+  uint16_t getDstPort() const;
+
+  Packet &setTTL(uint8_t hops);
+  uint8_t getTTL() const;
+
+ private:
+  virtual void resetForHash() = 0;
+
+ protected:
+  Name name_;
+  MemBufPtr packet_;
+  uint8_t *packet_start_;
+  utils::MemBuf *header_head_;
+  utils::MemBuf *payload_head_;
+  mutable Format format_;
+
+  static const core::Name base_name;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/payload_type.h b/libtransport/src/hicn/transport/core/payload_type.h
new file mode 100755 (executable)
index 0000000..fa79db3
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace core {
+
+enum class PayloadType : uint16_t {
+  CONTENT_OBJECT = HPT_DATA,
+  MANIFEST = HPT_MANIFEST,
+};
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/pending_interest.cc b/libtransport/src/hicn/transport/core/pending_interest.cc
new file mode 100755 (executable)
index 0000000..8f6de18
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/pending_interest.h>
+
+namespace transport {
+
+namespace core {
+
+PendingInterest::PendingInterest()
+    : interest_(nullptr, nullptr), timer_(), received_(false) {}
+
+PendingInterest::PendingInterest(Interest::Ptr &&interest,
+                                 std::unique_ptr<asio::steady_timer> &&timer)
+    : interest_(std::move(interest)),
+      timer_(std::move(timer)),
+      received_(false) {}
+
+PendingInterest::~PendingInterest() {
+  // timer_.reset();
+}
+
+void PendingInterest::cancelTimer() { timer_->cancel(); }
+
+bool PendingInterest::isReceived() const { return received_; }
+
+void PendingInterest::setReceived() { received_ = true; }
+
+Interest::Ptr &&PendingInterest::getInterest() { return std::move(interest_); }
+
+void PendingInterest::setReceived(bool received) {
+  PendingInterest::received_ = received;
+}
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/pending_interest.h b/libtransport/src/hicn/transport/core/pending_interest.h
new file mode 100755 (executable)
index 0000000..cbcafb5
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/deadline_timer.h>
+
+#include <asio/steady_timer.hpp>
+
+namespace transport {
+
+namespace core {
+
+class HicnForwarderInterface;
+class VPPForwarderInterface;
+class RawSocketInterface;
+
+template <typename ForwarderInt>
+class Portal;
+
+typedef std::function<void(const std::error_code &)> TimerCallback;
+
+class PendingInterest {
+  friend class Portal<HicnForwarderInterface>;
+  friend class Portal<VPPForwarderInterface>;
+  friend class Portal<RawSocketInterface>;
+
+ public:
+  PendingInterest();
+
+  PendingInterest(Interest::Ptr &&interest,
+                  std::unique_ptr<asio::steady_timer> &&timer);
+
+  ~PendingInterest();
+
+  bool isReceived() const;
+
+  template <typename Handler>
+  TRANSPORT_ALWAYS_INLINE void startCountdown(Handler &&cb) {
+    timer_->expires_from_now(
+        std::chrono::milliseconds(interest_->getLifetime()));
+    timer_->async_wait(cb);
+  }
+
+  void cancelTimer();
+
+  void setReceived();
+
+  Interest::Ptr &&getInterest();
+
+  void setReceived(bool received);
+
+  bool isValid() const;
+
+  void setValid(bool valid);
+
+ private:
+  Interest::Ptr interest_;
+  std::unique_ptr<asio::steady_timer> timer_;
+  bool received_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/portal.h b/libtransport/src/hicn/transport/core/portal.h
new file mode 100755 (executable)
index 0000000..8802044
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/core/pending_interest.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#ifdef __vpp__
+#include <hicn/transport/core/memif_connector.h>
+#endif
+
+#include <asio.hpp>
+#include <asio/steady_timer.hpp>
+#include <future>
+#include <memory>
+#include <unordered_map>
+
+#define UNSET_CALLBACK 0
+
+namespace transport {
+
+namespace core {
+
+typedef std::unordered_map<Name, std::unique_ptr<PendingInterest>>
+    PendingInterestHashTable;
+
+template <typename PrefixType>
+class BasicBindConfig {
+  static_assert(std::is_same<Prefix, PrefixType>::value,
+                "Prefix must be a Prefix type.");
+
+  const uint32_t standard_cs_reserved = 5000;
+
+ public:
+  template <typename T>
+  BasicBindConfig(T &&prefix)
+      : prefix_(std::forward<T &&>(prefix)),
+        content_store_reserved_(standard_cs_reserved) {}
+
+  template <typename T>
+  BasicBindConfig(T &&prefix, uint32_t cs_reserved)
+      : prefix_(std::forward<T &&>(prefix)),
+        content_store_reserved_(cs_reserved) {}
+
+  TRANSPORT_ALWAYS_INLINE const PrefixType &prefix() const { return prefix_; }
+
+  TRANSPORT_ALWAYS_INLINE uint32_t csReserved() const {
+    return content_store_reserved_;
+  }
+
+ private:
+  PrefixType prefix_;
+  uint32_t content_store_reserved_;
+};
+
+using BindConfig = BasicBindConfig<Prefix>;
+
+template <typename ForwarderInt>
+class Portal {
+  static_assert(
+      std::is_base_of<ForwarderInterface<ForwarderInt,
+                                         typename ForwarderInt::ConnectorType>,
+                      ForwarderInt>::value,
+      "ForwarderInt must inherit from ForwarderInterface!");
+
+ public:
+  class ConsumerCallback {
+   public:
+    virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0;
+    virtual void onTimeout(Interest::Ptr &&i) = 0;
+  };
+
+  class ProducerCallback {
+   public:
+    virtual void onInterest(Interest::Ptr &&i) = 0;
+  };
+
+  Portal() : Portal(internal_io_service_) {
+    internal_work_ = std::make_unique<asio::io_service::work>(io_service_);
+  }
+
+  Portal(asio::io_service &io_service)
+      : io_service_(io_service),
+        is_running_(false),
+        app_name_("libtransport_application"),
+        consumer_callback_(nullptr),
+        producer_callback_(nullptr),
+        connector_(std::bind(&Portal::processIncomingMessages, this,
+                             std::placeholders::_1),
+                   std::bind(&Portal::setLocalRoutes, this), io_service_,
+                   app_name_),
+        forwarder_interface_(connector_) {}
+
+  void setConsumerCallback(ConsumerCallback *consumer_callback) {
+    consumer_callback_ = consumer_callback;
+  }
+
+  void setProducerCallback(ProducerCallback *producer_callback) {
+    producer_callback_ = producer_callback;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void setOutputInterface(
+      const std::string &output_interface) {
+    forwarder_interface_.setOutputInterface(output_interface);
+  }
+
+  TRANSPORT_ALWAYS_INLINE void connect(bool is_consumer = true) {
+    forwarder_interface_.connect(is_consumer);
+  }
+
+  ~Portal() {
+    connector_.close();
+    stopEventsLoop();
+  }
+
+  TRANSPORT_ALWAYS_INLINE bool interestIsPending(const Name &name) {
+    auto it = pending_interest_hash_table_.find(name);
+    if (it != pending_interest_hash_table_.end())
+      if (!it->second->isReceived()) return true;
+
+    return false;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void sendInterest(Interest::Ptr &&interest) {
+    const Name name(interest->getName(), true);
+
+    // Send it
+    forwarder_interface_.send(*interest);
+
+    pending_interest_hash_table_[name] = std::make_unique<PendingInterest>(
+        std::move(interest), std::make_unique<asio::steady_timer>(io_service_));
+
+    pending_interest_hash_table_[name]->startCountdown(
+        std::bind(&Portal<ForwarderInt>::timerHandler, this,
+                  std::placeholders::_1, name));
+  }
+
+  TRANSPORT_ALWAYS_INLINE void timerHandler(const std::error_code &ec,
+                                            const Name &name) {
+    if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+      return;
+    }
+
+    if (TRANSPORT_EXPECT_TRUE(!ec)) {
+      std::unordered_map<Name, std::unique_ptr<PendingInterest>>::iterator it =
+          pending_interest_hash_table_.find(name);
+      if (it != pending_interest_hash_table_.end()) {
+        std::unique_ptr<PendingInterest> ptr = std::move(it->second);
+        pending_interest_hash_table_.erase(it);
+
+        if (consumer_callback_) {
+          consumer_callback_->onTimeout(std::move(ptr->getInterest()));
+        }
+      }
+    }
+  }
+
+  TRANSPORT_ALWAYS_INLINE void bind(const BindConfig &config) {
+    connector_.enableBurst();
+    forwarder_interface_.setContentStoreSize(config.csReserved());
+    served_namespaces_.push_back(config.prefix());
+    registerRoute(served_namespaces_.back());
+  }
+
+  TRANSPORT_ALWAYS_INLINE void runEventsLoop() {
+    if (io_service_.stopped()) {
+      io_service_.reset();  // ensure that run()/poll() will do some work
+    }
+
+    is_running_ = true;
+    this->io_service_.run();
+    is_running_ = false;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void runOneEvent() {
+    if (io_service_.stopped()) {
+      io_service_.reset();  // ensure that run()/poll() will do some work
+    }
+
+    is_running_ = true;
+    this->io_service_.run_one();
+    is_running_ = false;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void sendContentObject(
+      ContentObject &content_object) {
+    forwarder_interface_.send(content_object);
+  }
+
+  TRANSPORT_ALWAYS_INLINE void stopEventsLoop() {
+    is_running_ = false;
+    internal_work_.reset();
+
+    for (auto &pend_interest : pending_interest_hash_table_) {
+      pend_interest.second->cancelTimer();
+    }
+
+    clear();
+
+    io_service_.post([this]() { io_service_.stop(); });
+  }
+
+  TRANSPORT_ALWAYS_INLINE void killConnection() { connector_.close(); }
+
+  TRANSPORT_ALWAYS_INLINE void clear() { pending_interest_hash_table_.clear();}
+
+  TRANSPORT_ALWAYS_INLINE asio::io_service &getIoService() {
+    return io_service_;
+  }
+
+  TRANSPORT_ALWAYS_INLINE std::size_t getPITSize() {
+    connector_.state();
+    return pending_interest_hash_table_.size();
+  }
+
+  TRANSPORT_ALWAYS_INLINE void registerRoute(Prefix &prefix) {
+    forwarder_interface_.registerRoute(prefix);
+  }
+
+ private:
+  TRANSPORT_ALWAYS_INLINE void processIncomingMessages(
+      Packet::MemBufPtr &&packet_buffer) {
+    if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+      return;
+    }
+
+    if (packet_buffer->data()[0] == ForwarderInt::ack_code) {
+      // Hicn forwarder message
+      processControlMessage(std::move(packet_buffer));
+      return;
+    }
+
+    bool is_interest = Packet::isInterest(packet_buffer->data());
+    Packet::Format format = Packet::getFormatFromBuffer(packet_buffer->data());
+
+    if (TRANSPORT_EXPECT_TRUE(_is_tcp(format))) {
+      if (!is_interest) {
+        processContentObject(
+            ContentObject::Ptr(new ContentObject(std::move(packet_buffer))));
+      } else {
+        processInterest(Interest::Ptr(new Interest(std::move(packet_buffer))));
+      }
+    } else {
+      TRANSPORT_LOGE("Received not supported packet. Ignoring it.");
+    }
+  }
+
+  TRANSPORT_ALWAYS_INLINE void setLocalRoutes() {
+    for (auto &name : served_namespaces_) {
+      registerRoute(name);
+    }
+  }
+
+  TRANSPORT_ALWAYS_INLINE void processInterest(Interest::Ptr &&interest) {
+    // Interest for a producer
+    if (TRANSPORT_EXPECT_TRUE(producer_callback_ != nullptr)) {
+      producer_callback_->onInterest(std::move(interest));
+    }
+  }
+
+  TRANSPORT_ALWAYS_INLINE void processContentObject(
+      ContentObject::Ptr &&content_object) {
+    PendingInterestHashTable::iterator it =
+        pending_interest_hash_table_.find(content_object->getName());
+
+    if (TRANSPORT_EXPECT_TRUE(it != pending_interest_hash_table_.end())) {
+      std::unique_ptr<PendingInterest> interest_ptr = std::move(it->second);
+      interest_ptr->cancelTimer();
+
+      if (TRANSPORT_EXPECT_TRUE(!interest_ptr->isReceived())) {
+        interest_ptr->setReceived();
+        pending_interest_hash_table_.erase(content_object->getName());
+
+        if (consumer_callback_) {
+          consumer_callback_->onContentObject(
+              std::move(interest_ptr->getInterest()),
+              std::move(content_object));
+        }
+
+      } else {
+        TRANSPORT_LOGW(
+            "Content already received (interest already satisfied).");
+      }
+    } else {
+      TRANSPORT_LOGW("No pending interests for current content (%s)",
+                     content_object->getName().toString().c_str());
+    }
+  }
+
+  TRANSPORT_ALWAYS_INLINE void processControlMessage(
+      Packet::MemBufPtr &&packet_buffer) {
+    // Control message as response to the route set by a producer.
+    // Do nothing
+  }
+
+ private:
+  asio::io_service &io_service_;
+  asio::io_service internal_io_service_;
+  std::unique_ptr<asio::io_service::work> internal_work_;
+
+  volatile bool is_running_;
+
+  std::string app_name_;
+
+  PendingInterestHashTable pending_interest_hash_table_;
+
+  ConsumerCallback *consumer_callback_;
+  ProducerCallback *producer_callback_;
+
+  typename ForwarderInt::ConnectorType connector_;
+  ForwarderInt forwarder_interface_;
+
+  std::list<Prefix> served_namespaces_;
+
+  ip_address_t locator4_;
+  ip_address_t locator6_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/prefix.cc b/libtransport/src/hicn/transport/core/prefix.cc
new file mode 100755 (executable)
index 0000000..69c2b84
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/prefix.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+extern "C" {
+#include <arpa/inet.h>
+}
+
+#include <cstring>
+#include <memory>
+#include <random>
+
+namespace transport {
+
+namespace core {
+
+Prefix::Prefix() { std::memset(&ip_address_, 0, sizeof(ip_address_t)); }
+
+Prefix::Prefix(const char *prefix) : Prefix(std::string(prefix)) {}
+
+Prefix::Prefix(std::string &&prefix) : Prefix(prefix) {}
+
+Prefix::Prefix(const std::string &prefix) {
+  utils::StringTokenizer st(prefix, "/");
+
+  std::string ip_address = st.nextToken();
+  int family = get_addr_family(ip_address.c_str());
+
+  std::string prefix_length = family == AF_INET6 ? "128" : "32";
+
+  if (st.hasMoreTokens()) {
+    prefix_length = st.nextToken();
+  }
+
+  buildPrefix(ip_address, uint16_t(atoi(prefix_length.c_str())), family);
+}
+
+Prefix::Prefix(std::string &prefix, uint16_t prefix_length) {
+  int family = get_addr_family(prefix.c_str());
+  buildPrefix(prefix, prefix_length, family);
+}
+
+Prefix::Prefix(const core::Name &content_name, uint16_t prefix_length) {
+  int family = content_name.getAddressFamily();
+
+  if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  ip_address_ = content_name.toIpAddress();
+  ip_address_.prefix_len = prefix_length;
+  ip_address_.family = family;
+}
+
+void Prefix::buildPrefix(std::string &prefix, uint16_t prefix_length,
+                         int family) {
+  if (!checkPrefixLengthAndAddressFamily(prefix_length, family)) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  int ret = inet_pton(family, prefix.c_str(), ip_address_.buffer);
+
+  if (ret != 1) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  ip_address_.prefix_len = prefix_length;
+  ip_address_.family = family;
+}
+
+std::unique_ptr<Sockaddr> Prefix::toSockaddr() {
+  Sockaddr *ret = nullptr;
+
+  switch (ip_address_.family) {
+    case AF_INET6:
+      ret = (Sockaddr *)new Sockaddr6;
+      break;
+    case AF_INET:
+      ret = (Sockaddr *)new Sockaddr4;
+      break;
+    default:
+      throw errors::InvalidIpAddressException();
+  }
+
+  if (hicn_ip_to_sockaddr_address(&ip_address_, ret) < 0) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  return std::unique_ptr<Sockaddr>(ret);
+}
+
+uint16_t Prefix::getPrefixLength() { return ip_address_.prefix_len; }
+
+Prefix &Prefix::setPrefixLength(uint16_t prefix_length) {
+  ip_address_.prefix_len = prefix_length;
+  return *this;
+}
+
+int Prefix::getAddressFamily() { return ip_address_.family; }
+
+Prefix &Prefix::setAddressFamily(int address_family) {
+  ip_address_.family = address_family;
+  return *this;
+}
+
+std::string Prefix::getNetwork() const {
+  if (!checkPrefixLengthAndAddressFamily(ip_address_.prefix_len,
+                                         ip_address_.family)) {
+    throw errors::InvalidIpAddressException();
+  }
+
+  std::size_t size =
+      ip_address_.family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+
+  std::string network(size, 0);
+
+  if (hicn_ip_ntop(&ip_address_, (char *)network.c_str(), size) < 0) {
+    throw errors::RuntimeException(
+        "Impossible to retrieve network from ip address.");
+  }
+
+  return network;
+}
+
+Name Prefix::getName() const {
+  std::string s(getNetwork());
+  return Name(s);
+}
+
+Prefix &Prefix::setNetwork(std::string &network) {
+  if (!inet_pton(AF_INET6, network.c_str(), ip_address_.buffer)) {
+    throw errors::RuntimeException("The network name is not valid.");
+  }
+
+  return *this;
+}
+
+Name Prefix::makeRandomName() const {
+  srand(time(nullptr));
+
+  if (ip_address_.family == AF_INET6) {
+    std::default_random_engine eng((std::random_device())());
+    std::uniform_int_distribution<uint32_t> idis(
+        0, std::numeric_limits<uint32_t>::max());
+    uint64_t random_number = idis(eng);
+
+    uint32_t hash_size_bits = IPV6_ADDR_LEN_BITS - ip_address_.prefix_len;
+    uint64_t ip_address[2];
+    memcpy(ip_address, ip_address_.buffer, sizeof(uint64_t));
+    memcpy(ip_address + 1, ip_address_.buffer + 8, sizeof(uint64_t));
+    std::string network(IPV6_ADDR_LEN * 3, 0);
+
+    // Let's do the magic ;)
+    int shift_size = hash_size_bits > sizeof(random_number) * 8
+                         ? sizeof(random_number) * 8
+                         : hash_size_bits;
+
+    ip_address[1] >>= shift_size;
+    ip_address[1] <<= shift_size;
+
+    ip_address[1] |= random_number >> (sizeof(uint64_t) * 8 - shift_size);
+
+    if (!inet_ntop(ip_address_.family, ip_address, (char *)network.c_str(),
+                   IPV6_ADDR_LEN * 3)) {
+      throw errors::RuntimeException(
+          "Impossible to retrieve network from ip address.");
+    }
+
+    return Name(network);
+  }
+
+  return Name();
+}
+
+bool Prefix::checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
+                                               int family) {
+  // First check the family
+  if (family != AF_INET6 && family != AF_INET) {
+    return false;
+  }
+
+  int max_addr_len_bits =
+      family == AF_INET6 ? IPV6_ADDR_LEN_BITS : IPV4_ADDR_LEN_BITS;
+
+  if (prefix_length > max_addr_len_bits) {
+    return false;
+  }
+
+  return true;
+}
+
+ip_address_t &Prefix::toIpAddressStruct() { return ip_address_; }
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/prefix.h b/libtransport/src/hicn/transport/core/prefix.h
new file mode 100755 (executable)
index 0000000..b68c6bd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/name.h>
+namespace transport {
+
+namespace core {
+
+class Prefix {
+ public:
+  Prefix();
+
+  Prefix(const char *prefix);
+
+  Prefix(const std::string &prefix);
+
+  Prefix(std::string &&prefix);
+
+  Prefix(std::string &prefix, uint16_t prefix_length);
+
+  Prefix(const core::Name &content_name, uint16_t prefix_length);
+
+  std::unique_ptr<Sockaddr> toSockaddr();
+
+  uint16_t getPrefixLength();
+
+  Prefix &setPrefixLength(uint16_t prefix_length);
+
+  std::string getNetwork() const;
+
+  Name getName() const;
+
+  Prefix &setNetwork(std::string &network);
+
+  int getAddressFamily();
+
+  Prefix &setAddressFamily(int address_family);
+
+  Name makeRandomName() const;
+
+  ip_address_t &toIpAddressStruct();
+
+ private:
+  static bool checkPrefixLengthAndAddressFamily(uint16_t prefix_length,
+                                                int family);
+
+  void buildPrefix(std::string &prefix, uint16_t prefix_length, int family);
+
+  ip_address_t ip_address_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.cc b/libtransport/src/hicn/transport/core/raw_socket_connector.cc
new file mode 100755 (executable)
index 0000000..5cfff39
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/raw_socket_connector.h>
+#include <hicn/transport/utils/conversions.h>
+#include <hicn/transport/utils/log.h>
+
+#include <net/if.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#define MY_DEST_MAC0 0x0a
+#define MY_DEST_MAC1 0x7b
+#define MY_DEST_MAC2 0x7c
+#define MY_DEST_MAC3 0x1c
+#define MY_DEST_MAC4 0x4a
+#define MY_DEST_MAC5 0x14
+
+namespace transport {
+
+namespace core {
+
+RawSocketConnector::RawSocketConnector(
+    PacketReceivedCallback &&receive_callback,
+    OnReconnect &&on_reconnect_callback, asio::io_service &io_service,
+    std::string app_name)
+    : Connector(),
+      io_service_(io_service),
+      socket_(io_service_, raw_protocol(PF_PACKET, SOCK_RAW)),
+      // resolver_(io_service_),
+      timer_(io_service_),
+      read_msg_(packet_pool_.makePtr(nullptr)),
+      data_available_(false),
+      receive_callback_(receive_callback),
+      on_reconnect_callback_(on_reconnect_callback),
+      app_name_(app_name) {
+  memset(&link_layer_address_, 0, sizeof(link_layer_address_));
+}
+
+RawSocketConnector::~RawSocketConnector() {}
+
+void RawSocketConnector::connect(const std::string &interface_name,
+                                 const std::string &mac_address_str) {
+  memset(&ethernet_header_, 0, sizeof(ethernet_header_));
+  struct ifreq ifr;
+  struct ifreq if_mac;
+  uint8_t mac_address[6];
+
+  utils::convertStringToMacAddress(mac_address_str, mac_address);
+
+  // Get interface mac address
+  int fd = static_cast<int>(socket_.native_handle());
+
+  /* Get the index of the interface to send on */
+  memset(&ifr, 0, sizeof(struct ifreq));
+  strncpy(ifr.ifr_name, interface_name.c_str(), interface_name.size());
+
+  // if (ioctl(fd, SIOCGIFINDEX, &if_idx) < 0) {
+  //     perror("SIOCGIFINDEX");
+  // }
+
+  /* Get the MAC address of the interface to send on */
+  memset(&if_mac, 0, sizeof(struct ifreq));
+  strncpy(if_mac.ifr_name, interface_name.c_str(), interface_name.size());
+  if (ioctl(fd, SIOCGIFHWADDR, &if_mac) < 0) {
+    perror("SIOCGIFHWADDR");
+    throw errors::RuntimeException("Interface does not exist");
+  }
+
+  /* Ethernet header */
+  for (int i = 0; i < 6; i++) {
+    ethernet_header_.ether_shost[i] =
+        ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[i];
+    ethernet_header_.ether_dhost[i] = mac_address[i];
+  }
+
+  /* Ethertype field */
+  ethernet_header_.ether_type = htons(ETH_P_IPV6);
+
+  strcpy(ifr.ifr_name, interface_name.c_str());
+
+  if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr)) {
+    memcpy(link_layer_address_.sll_addr, ifr.ifr_hwaddr.sa_data, 6);
+  }
+
+  // memset(&ifr, 0, sizeof(ifr));
+  // ioctl(fd, SIOCGIFFLAGS, &ifr);
+  // ifr.ifr_flags |= IFF_PROMISC;
+  // ioctl(fd, SIOCSIFFLAGS, &ifr);
+
+  link_layer_address_.sll_family = AF_PACKET;
+  link_layer_address_.sll_protocol = htons(ETH_P_ALL);
+  link_layer_address_.sll_ifindex = if_nametoindex(interface_name.c_str());
+  link_layer_address_.sll_hatype = 1;
+  link_layer_address_.sll_halen = 6;
+
+  // startConnectionTimer();
+  doConnect();
+  doRecvPacket();
+}
+
+void RawSocketConnector::state() { return; }
+
+void RawSocketConnector::send(const uint8_t *packet, std::size_t len,
+                              const PacketSentCallback &packet_sent) {
+  // asio::async_write(socket_, asio::buffer(packet, len),
+  //                   [packet_sent] (std::error_code ec,
+  //                                  std::size_t /*length*/) {
+  //                     packet_sent();
+  //                   });
+}
+
+void RawSocketConnector::send(const Packet::MemBufPtr &packet) {
+  // Packet &p = const_cast<Packet &>(packet);
+  // p.setTcpChecksum();
+
+  // if (!p.checkIntegrity()) {
+  //   TRANSPORT_LOGW("Sending message with wrong checksum!!!");
+  // }
+
+  // std::shared_ptr<const Packet> ptr;
+  // try {
+  //   ptr = packet.shared_from_this();
+  // } catch (std::bad_weak_ptr& exc) {
+  //   TRANSPORT_LOGW("Sending interest which has not been created using a
+  //   shared PTR! A copy will be made."); ptr =
+  //   std::shared_ptr<Packet>(packet.clone());
+  // }
+
+  io_service_.post([this, packet]() {
+    bool write_in_progress = !output_buffer_.empty();
+    output_buffer_.push_back(std::move(packet));
+    if (!write_in_progress) {
+      doSendPacket();
+    } else {
+      // Tell the handle connect it has data to write
+      data_available_ = true;
+    }
+  });
+}
+
+void RawSocketConnector::close() {
+  io_service_.post([this]() { socket_.close(); });
+}
+
+void RawSocketConnector::doSendPacket() {
+  auto packet = output_buffer_.front().get();
+  auto array = std::vector<asio::const_buffer>();
+
+  const utils::MemBuf *current = packet;
+  do {
+    array.push_back(asio::const_buffer(current->data(), current->length()));
+    current = current->next();
+  } while (current != packet);
+
+  socket_.async_send(
+      std::move(array),
+      [this /*, packet*/](std::error_code ec, std::size_t bytes_transferred) {
+        if (TRANSPORT_EXPECT_TRUE(!ec)) {
+          output_buffer_.pop_front();
+          if (!output_buffer_.empty()) {
+            doSendPacket();
+          }
+        } else {
+          TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+        }
+      });
+}
+
+void RawSocketConnector::doRecvPacket() {
+  read_msg_ = std::move(getPacket());
+  socket_.async_receive(
+      asio::buffer(read_msg_->writableData(), packet_size),
+      [this](std::error_code ec, std::size_t bytes_transferred) mutable {
+        if (!ec) {
+          // Ignore packets that are not for us
+          uint8_t *dst_mac_address = const_cast<uint8_t *>(read_msg_->data());
+          if (!std::memcmp(dst_mac_address, ethernet_header_.ether_shost,
+                           ETHER_ADDR_LEN)) {
+            read_msg_->append(bytes_transferred);
+            read_msg_->trimStart(sizeof(struct ether_header));
+            receive_callback_(std::move(read_msg_));
+          }
+        } else {
+          TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+        }
+        doRecvPacket();
+      });
+}
+
+void RawSocketConnector::doConnect() {
+  socket_.bind(raw_endpoint(&link_layer_address_, sizeof(link_layer_address_)));
+}
+
+void RawSocketConnector::enableBurst() { return; }
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_connector.h b/libtransport/src/hicn/transport/core/raw_socket_connector.h
new file mode 100755 (executable)
index 0000000..5e39efa
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/name.h>
+
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <asio.hpp>
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+using asio::generic::raw_protocol;
+using raw_endpoint = asio::generic::basic_endpoint<raw_protocol>;
+
+class RawSocketConnector : public Connector {
+ public:
+  RawSocketConnector(PacketReceivedCallback &&receive_callback,
+                     OnReconnect &&reconnect_callback,
+                     asio::io_service &io_service,
+                     std::string app_name = "Libtransport");
+
+  ~RawSocketConnector() override;
+
+  void send(const Packet::MemBufPtr &packet) override;
+
+  void send(const uint8_t *packet, std::size_t len,
+            const PacketSentCallback &packet_sent = 0) override;
+
+  void close() override;
+
+  void enableBurst() override;
+
+  void connect(const std::string &interface_name,
+               const std::string &mac_address_str);
+
+  void state() override;
+
+ private:
+  void doConnect();
+
+  void doRecvPacket();
+
+  void doSendPacket();
+
+ private:
+  asio::io_service &io_service_;
+  raw_protocol::socket socket_;
+
+  struct ether_header ethernet_header_;
+
+  struct sockaddr_ll link_layer_address_;
+
+  asio::steady_timer timer_;
+
+  utils::ObjectPool<utils::MemBuf>::Ptr read_msg_;
+
+  bool data_available_;
+
+  PacketReceivedCallback receive_callback_;
+  OnReconnect on_reconnect_callback_;
+  std::string app_name_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.cc b/libtransport/src/hicn/transport/core/raw_socket_interface.cc
new file mode 100755 (executable)
index 0000000..37aaff7
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/raw_socket_interface.h>
+#include <hicn/transport/utils/linux.h>
+
+#include <fstream>
+
+namespace transport {
+
+namespace core {
+
+static std::string config_folder_path = "/etc/transport/interface.conf.d";
+
+RawSocketInterface::RawSocketInterface(RawSocketConnector &connector)
+    : ForwarderInterface<RawSocketInterface, RawSocketConnector>(connector) {}
+
+RawSocketInterface::~RawSocketInterface() {}
+
+void RawSocketInterface::connect(bool is_consumer) {
+  std::string complete_filename =
+      config_folder_path + std::string("/") + output_interface_;
+
+  std::ifstream is(complete_filename);
+  std::string interface;
+
+  if (is) {
+    is >> remote_mac_address_;
+  }
+
+  // Get interface ip address
+  struct sockaddr_in6 address;
+  utils::retrieveInterfaceAddress(output_interface_, &address);
+  inet6_address_.family = address.sin6_family;
+
+  std::memcpy(inet6_address_.buffer, &address.sin6_addr,
+              sizeof(address.sin6_addr));
+  connector_.connect(output_interface_, remote_mac_address_);
+}
+
+void RawSocketInterface::registerRoute(Prefix &prefix) { return; }
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/raw_socket_interface.h b/libtransport/src/hicn/transport/core/raw_socket_interface.h
new file mode 100755 (executable)
index 0000000..c030af6
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/core/raw_socket_connector.h>
+
+#include <atomic>
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class RawSocketInterface
+    : public ForwarderInterface<RawSocketInterface, RawSocketConnector> {
+ public:
+  typedef RawSocketConnector ConnectorType;
+
+  RawSocketInterface(RawSocketConnector &connector);
+
+  ~RawSocketInterface();
+
+  void connect(bool is_consumer);
+
+  void registerRoute(Prefix &prefix);
+
+  std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+  static constexpr std::uint16_t interface_mtu = 1500;
+  std::string remote_mac_address_;
+};
+
+}  // namespace core
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/core/socket_connector.cc b/libtransport/src/hicn/transport/core/socket_connector.cc
new file mode 100755 (executable)
index 0000000..332b87e
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/socket_connector.h>
+#include <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/log.h>
+#include <hicn/transport/utils/object_pool.h>
+
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+class NetworkMessage {
+ public:
+  static constexpr std::size_t fixed_header_length = 10;
+
+  static std::size_t decodeHeader(const uint8_t *packet) {
+    // General checks
+    // CCNX Control packet format
+    uint8_t first_byte = packet[0];
+    uint8_t ip_format = (packet[0] & 0xf0) >> 4;
+
+    if (TRANSPORT_EXPECT_FALSE(first_byte == 102)) {
+      // Get packet length
+      return 44;
+    } else if (TRANSPORT_EXPECT_TRUE(ip_format == 6 || ip_format == 4)) {
+      Packet::Format format = Packet::getFormatFromBuffer(packet);
+      return Packet::getHeaderSizeFromBuffer(format, packet) +
+             Packet::getPayloadSizeFromBuffer(format, packet);
+    }
+
+    return 0;
+  }
+};
+}  // namespace
+
+SocketConnector::SocketConnector(PacketReceivedCallback &&receive_callback,
+                                 OnReconnect &&on_reconnect_callback,
+                                 asio::io_service &io_service,
+                                 std::string app_name)
+    : Connector(),
+      io_service_(io_service),
+      socket_(io_service_),
+      resolver_(io_service_),
+      timer_(io_service_),
+      read_msg_(packet_pool_.makePtr(nullptr)),
+      is_connecting_(false),
+      is_reconnection_(false),
+      data_available_(false),
+      receive_callback_(receive_callback),
+      on_reconnect_callback_(on_reconnect_callback),
+      app_name_(app_name) {}
+
+SocketConnector::~SocketConnector() {}
+
+void SocketConnector::connect(std::string ip_address, std::string port) {
+  endpoint_iterator_ = resolver_.resolve(
+      {ip_address, port, asio::ip::resolver_query_base::numeric_service});
+
+  startConnectionTimer();
+  doConnect();
+}
+
+void SocketConnector::state() { return; }
+
+void SocketConnector::send(const uint8_t *packet, std::size_t len,
+                           const PacketSentCallback &packet_sent) {
+  asio::async_write(socket_, asio::buffer(packet, len),
+                    [packet_sent](std::error_code ec, std::size_t /*length*/) {
+                      packet_sent();
+                    });
+}
+
+void SocketConnector::send(const Packet::MemBufPtr &packet) {
+  io_service_.post([this, packet]() {
+    bool write_in_progress = !output_buffer_.empty();
+    output_buffer_.push_back(std::move(packet));
+    if (TRANSPORT_EXPECT_FALSE(!is_connecting_)) {
+      if (!write_in_progress) {
+        doWrite();
+      }
+    } else {
+      // Tell the handle connect it has data to write
+      data_available_ = true;
+    }
+  });
+}
+
+void SocketConnector::close() {
+  io_service_.post([this]() { socket_.close(); });
+}
+
+void SocketConnector::doWrite() {
+  // TODO improve this piece of code for sending many buffers togethers
+  // if list contains more than one packet
+  auto packet = output_buffer_.front().get();
+  auto array = std::vector<asio::const_buffer>();
+
+  const utils::MemBuf *current = packet;
+  do {
+    array.push_back(asio::const_buffer(current->data(), current->length()));
+    current = current->next();
+  } while (current != packet);
+
+  asio::async_write(
+      socket_, std::move(array),
+      [this /*, packet*/](std::error_code ec, std::size_t length) {
+        if (TRANSPORT_EXPECT_TRUE(!ec)) {
+          output_buffer_.pop_front();
+          if (!output_buffer_.empty()) {
+            doWrite();
+          }
+        } else {
+          TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+          tryReconnect();
+        }
+      });
+}
+
+void SocketConnector::doReadBody(std::size_t body_length) {
+  asio::async_read(
+      socket_, asio::buffer(read_msg_->writableTail(), body_length),
+      asio::transfer_exactly(body_length),
+      [this](std::error_code ec, std::size_t length) {
+        read_msg_->append(length);
+        if (TRANSPORT_EXPECT_TRUE(!ec)) {
+          receive_callback_(std::move(read_msg_));
+          doReadHeader();
+        } else {
+          TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+          tryReconnect();
+        }
+      });
+}
+
+void SocketConnector::doReadHeader() {
+  read_msg_ = getPacket();
+  asio::async_read(
+      socket_,
+      asio::buffer(read_msg_->writableData(),
+                   NetworkMessage::fixed_header_length),
+      asio::transfer_exactly(NetworkMessage::fixed_header_length),
+      [this](std::error_code ec, std::size_t length) {
+        if (TRANSPORT_EXPECT_TRUE(!ec)) {
+          read_msg_->append(NetworkMessage::fixed_header_length);
+          std::size_t body_length = 0;
+          if ((body_length = NetworkMessage::decodeHeader(read_msg_->data())) >
+              0) {
+            doReadBody(body_length - length);
+          } else {
+            TRANSPORT_LOGE("Decoding error. Ignoring packet.");
+          }
+        } else {
+          TRANSPORT_LOGE("%d %s", ec.value(), ec.message().c_str());
+          tryReconnect();
+        }
+      });
+}
+
+void SocketConnector::tryReconnect() {
+  if (!is_connecting_) {
+    TRANSPORT_LOGE("Connection lost. Trying to reconnect...\n");
+    is_connecting_ = true;
+    is_reconnection_ = true;
+    io_service_.post([this]() {
+      socket_.close();
+      startConnectionTimer();
+      doConnect();
+    });
+  }
+}
+
+void SocketConnector::doConnect() {
+  asio::async_connect(socket_, endpoint_iterator_,
+                      [this](std::error_code ec, tcp::resolver::iterator) {
+                        if (!ec) {
+                          timer_.cancel();
+                          is_connecting_ = false;
+                          asio::ip::tcp::no_delay noDelayOption(true);
+                          socket_.set_option(noDelayOption);
+                          doReadHeader();
+
+                          if (data_available_) {
+                            data_available_ = false;
+                            doWrite();
+                          }
+
+                          if (is_reconnection_) {
+                            is_reconnection_ = false;
+                            TRANSPORT_LOGI("Connection recovered!\n");
+                            on_reconnect_callback_();
+                          }
+                        } else {
+                          sleep(1);
+                          doConnect();
+                        }
+                      });
+}
+
+bool SocketConnector::checkConnected() { return !is_connecting_; }
+
+void SocketConnector::enableBurst() { return; }
+
+void SocketConnector::startConnectionTimer() {
+  timer_.expires_from_now(std::chrono::seconds(60));
+  timer_.async_wait(
+      std::bind(&SocketConnector::handleDeadline, this, std::placeholders::_1));
+}
+
+void SocketConnector::handleDeadline(const std::error_code &ec) {
+  if (!ec) {
+    io_service_.post([this]() {
+      socket_.close();
+      TRANSPORT_LOGE("Error connecting. Is the forwarder running?\n");
+      io_service_.stop();
+    });
+  }
+}
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/socket_connector.h b/libtransport/src/hicn/transport/core/socket_connector.h
new file mode 100755 (executable)
index 0000000..d7a05aa
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/connector.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <asio.hpp>
+#include <deque>
+
+namespace transport {
+namespace core {
+
+using asio::ip::tcp;
+
+class SocketConnector : public Connector {
+ public:
+  SocketConnector(PacketReceivedCallback &&receive_callback,
+                  OnReconnect &&reconnect_callback,
+                  asio::io_service &io_service,
+                  std::string app_name = "Libtransport");
+
+  ~SocketConnector() override;
+
+  void send(const Packet::MemBufPtr &packet) override;
+
+  void send(const uint8_t *packet, std::size_t len,
+            const PacketSentCallback &packet_sent = 0) override;
+
+  void close() override;
+
+  void enableBurst() override;
+
+  void connect(std::string ip_address = "127.0.0.1", std::string port = "9695");
+
+  void state() override;
+
+ private:
+  void doConnect();
+
+  void doReadHeader();
+
+  void doReadBody(std::size_t body_length);
+
+  void doWrite();
+
+  bool checkConnected();
+
+ private:
+  void handleDeadline(const std::error_code &ec);
+
+  void startConnectionTimer();
+
+  void tryReconnect();
+
+  asio::io_service &io_service_;
+  asio::ip::tcp::socket socket_;
+  asio::ip::tcp::resolver resolver_;
+  asio::ip::tcp::resolver::iterator endpoint_iterator_;
+  asio::steady_timer timer_;
+
+  utils::ObjectPool<utils::MemBuf>::Ptr read_msg_;
+
+  bool is_connecting_;
+  bool is_reconnection_;
+  bool data_available_;
+
+  PacketReceivedCallback receive_callback_;
+  OnReconnect on_reconnect_callback_;
+  std::string app_name_;
+};
+
+}  // end namespace core
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/core/test/CMakeLists.txt b/libtransport/src/hicn/transport/core/test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..48c50e9
--- /dev/null
@@ -0,0 +1,10 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+    test_core_manifest)
+
+foreach(test ${TestsExpectedToPass})
+  AddTest(${test})
+endforeach()
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/test/test_core_manifest.cc b/libtransport/src/hicn/transport/core/test/test_core_manifest.cc
new file mode 100755 (executable)
index 0000000..58563d8
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2017-2019 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 <gtest/gtest.h>
+
+#include "../manifest_format_fixed.h"
+#include "../manifest_inline.h"
+
+#include <test.h>
+#include <random>
+#include <vector>
+
+namespace transport {
+
+namespace core {
+
+namespace {
+// The fixture for testing class Foo.
+class ManifestTest : public ::testing::Test {
+ protected:
+  using ContentObjectManifest = ManifestInline<ContentObject, Fixed>;
+
+  ManifestTest() : name_("b001::123|321"), manifest1_(name_) {
+    // You can do set-up work for each test here.
+  }
+
+  virtual ~ManifestTest() {
+    // You can do clean-up work that doesn't throw exceptions here.
+  }
+
+  // If the constructor and destructor are not enough for setting up
+  // and cleaning up each test, you can define the following methods:
+
+  virtual void SetUp() {
+    // Code here will be called immediately after the constructor (right
+    // before each test).
+  }
+
+  virtual void TearDown() {
+    // Code here will be called immediately after each test (right
+    // before the destructor).
+  }
+
+  Name name_;
+  ContentObjectManifest manifest1_;
+
+  std::vector<uint8_t> manifest_payload = {
+      0x11, 0x11, 0x01, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xad  // , 0x00, 0x00,
+                                                            // 0x00, 0x45, 0xa3,
+                                                            // 0xd1, 0xf2, 0x2b,
+                                                            // 0x94, 0x41, 0x22,
+                                                            // 0xc9, 0x00, 0x00,
+                                                            // 0x00, 0x44, 0xa3,
+                                                            // 0xd1, 0xf2, 0x2b,
+                                                            // 0x94, 0x41, 0x22,
+                                                            // 0xc8
+  };
+};
+
+}  // namespace
+
+TEST_F(ManifestTest, ManifestCreate) {
+  ContentObjectManifest manifest2(name_);
+  ContentObjectManifest manifest3 = manifest2;
+
+  EXPECT_EQ(manifest1_, manifest2);
+  EXPECT_EQ(manifest1_, manifest3);
+}
+
+TEST_F(ManifestTest, ManifestCreateFromBase) {
+  ContentObject content_object(name_);
+  content_object.setPayload(manifest_payload.data(), manifest_payload.size());
+  ContentObjectManifest manifest(std::move(content_object));
+
+  auto manifest4 = ContentObjectManifest::createManifest(
+      name_, core::ManifestVersion::VERSION_1,
+      core::ManifestType::INLINE_MANIFEST, HashAlgorithm::SHA_256, true,
+      core::Name("b001::dead"),
+      core::NextSegmentCalculationStrategy::INCREMENTAL, 128);
+
+  manifest4->encode();
+  manifest4->dump();
+  manifest.dump();
+
+  EXPECT_EQ(manifest1_, manifest);
+  //  EXPECT_EQ(manifest1_, manifest3);
+}
+
+TEST_F(ManifestTest, SetLastManifest) {
+  manifest1_.clear();
+
+  manifest1_.setFinalManifest(true);
+  manifest1_.encode();
+  manifest1_.decode();
+  bool fcn = manifest1_.isFinalManifest();
+
+  ASSERT_TRUE(fcn);
+}
+
+TEST_F(ManifestTest, SetManifestType) {
+  manifest1_.clear();
+
+  ManifestType type1 = ManifestType::INLINE_MANIFEST;
+  ManifestType type2 = ManifestType::FLIC_MANIFEST;
+
+  manifest1_.setManifestType(type1);
+  manifest1_.encode();
+  manifest1_.decode();
+  ManifestType type_returned1 = manifest1_.getManifestType();
+
+  manifest1_.clear();
+
+  manifest1_.setManifestType(type2);
+  manifest1_.encode();
+  manifest1_.decode();
+  ManifestType type_returned2 = manifest1_.getManifestType();
+
+  ASSERT_EQ(type1, type_returned1);
+  ASSERT_EQ(type2, type_returned2);
+}
+
+TEST_F(ManifestTest, SetHashAlgorithm) {
+  manifest1_.clear();
+
+  HashAlgorithm hash1 = HashAlgorithm::SHA_512;
+  HashAlgorithm hash2 = HashAlgorithm::CRC32C;
+  HashAlgorithm hash3 = HashAlgorithm::SHA_256;
+
+  manifest1_.setHashAlgorithm(hash1);
+  manifest1_.encode();
+  manifest1_.decode();
+  HashAlgorithm type_returned1 = manifest1_.getHashAlgorithm();
+
+  manifest1_.clear();
+
+  manifest1_.setHashAlgorithm(hash2);
+  manifest1_.encode();
+  manifest1_.decode();
+  HashAlgorithm type_returned2 = manifest1_.getHashAlgorithm();
+
+  manifest1_.clear();
+
+  manifest1_.setHashAlgorithm(hash3);
+  manifest1_.encode();
+  manifest1_.decode();
+  HashAlgorithm type_returned3 = manifest1_.getHashAlgorithm();
+
+  ASSERT_EQ(hash1, type_returned1);
+  ASSERT_EQ(hash2, type_returned2);
+  ASSERT_EQ(hash3, type_returned3);
+}
+
+TEST_F(ManifestTest, SetNextSegmentCalculationStrategy) {
+  manifest1_.clear();
+
+  NextSegmentCalculationStrategy strategy1 =
+      NextSegmentCalculationStrategy::INCREMENTAL;
+
+  manifest1_.setNextSegmentCalculationStrategy(strategy1);
+  manifest1_.encode();
+  manifest1_.decode();
+  NextSegmentCalculationStrategy type_returned1 =
+      manifest1_.getNextSegmentCalculationStrategy();
+
+  ASSERT_EQ(strategy1, type_returned1);
+}
+
+TEST_F(ManifestTest, SetBaseName) {
+  manifest1_.clear();
+
+  core::Name base_name("b001::dead");
+  manifest1_.setBaseName(base_name);
+  manifest1_.encode();
+  manifest1_.decode();
+  core::Name ret_name = manifest1_.getBaseName();
+
+  ASSERT_EQ(base_name, ret_name);
+}
+
+TEST_F(ManifestTest, SetSuffixList) {
+  manifest1_.clear();
+
+  core::Name base_name("b001::dead");
+
+  using random_bytes_engine =
+      std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
+                                   unsigned char>;
+  random_bytes_engine rbe;
+
+  std::default_random_engine eng((std::random_device())());
+  std::uniform_int_distribution<uint64_t> idis(
+      0, std::numeric_limits<uint32_t>::max());
+
+  auto entries = new std::pair<uint32_t, utils::CryptoHash>[3];
+  uint32_t suffixes[3];
+  std::vector<unsigned char> data[3];
+
+  for (int i = 0; i < 3; i++) {
+    data[i].resize(32);
+    std::generate(std::begin(data[i]), std::end(data[i]), std::ref(rbe));
+    suffixes[i] = idis(eng);
+    entries[i] = std::make_pair(
+        suffixes[i], utils::CryptoHash(data[i].data(), data[i].size(),
+                                       utils::CryptoHashType::SHA_256));
+    manifest1_.addSuffixHash(entries[i].first, entries[i].second);
+  }
+
+  manifest1_.setBaseName(base_name);
+
+  manifest1_.encode();
+  manifest1_.decode();
+
+  core::Name ret_name = manifest1_.getBaseName();
+
+  // auto & hash_list = manifest1_.getSuffixHashList();
+
+  bool cond;
+  int i = 0;
+
+  // for (auto & item : manifest1_.getSuffixList()) {
+  //   auto hash = manifest1_.getHash(suffixes[i]);
+  //   cond = utils::CryptoHash::compareBinaryDigest(hash,
+  //                                                 entries[i].second.getDigest<uint8_t>().data(),
+  //                                                 entries[i].second.getType());
+  //   ASSERT_TRUE(cond);
+  //   i++;
+  // }
+
+  ASSERT_EQ(base_name, ret_name);
+
+  delete[] entries;
+}
+
+TEST_F(ManifestTest, EstimateSize) {
+  manifest1_.clear();
+
+  HashAlgorithm hash1 = HashAlgorithm::SHA_256;
+  NextSegmentCalculationStrategy strategy1 =
+      NextSegmentCalculationStrategy::INCREMENTAL;
+  ManifestType type1 = ManifestType::INLINE_MANIFEST;
+  core::Name base_name1("b001:abcd:fede:baba:cece:d0d0:face:dead");
+
+  manifest1_.setFinalManifest(true);
+  manifest1_.setBaseName(base_name1);
+  manifest1_.setNextSegmentCalculationStrategy(strategy1);
+  manifest1_.setHashAlgorithm(hash1);
+  manifest1_.setManifestType(type1);
+
+  std::default_random_engine eng((std::random_device())());
+  std::uniform_int_distribution<uint64_t> idis(
+      0, std::numeric_limits<uint64_t>::max());
+
+  using random_bytes_engine =
+      std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
+                                   unsigned char>;
+  random_bytes_engine rbe;
+
+  while (manifest1_.estimateManifestSize(1) < 1440) {
+    uint32_t suffix = static_cast<std::uint32_t>(idis(eng));
+    std::vector<unsigned char> data(32);
+    std::generate(std::begin(data), std::end(data), std::ref(rbe));
+    auto hash = utils::CryptoHash(data.data(), data.size(),
+                                  utils::CryptoHashType::SHA_256);
+    manifest1_.addSuffixHash(suffix, hash);
+  }
+
+  manifest1_.encode();
+  manifest1_.decode();
+
+  manifest1_.dump();
+
+  ASSERT_GT(manifest1_.estimateManifestSize(), 0);
+  ASSERT_LT(manifest1_.estimateManifestSize(), 1500);
+}
+
+}  // namespace core
+
+}  // namespace transport
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.c b/libtransport/src/hicn/transport/core/vpp_binary_api.c
new file mode 100755 (executable)
index 0000000..ab23d3c
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/vpp_binary_api.h>
+#include <hicn/transport/core/vpp_binary_api_internal.h>
+#include <hicn/transport/utils/log.h>
+
+#include <vat/vat.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include <vnet/ip/ip.h>
+#include <vppinfra/error.h>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <vpp/api/vpe_msg_enum.h>
+
+#define vl_typedefs
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+#define vl_endianfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+#define vl_print(handle, ...)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
+/* Get CRC codes of the messages */
+#define vl_msg_name_crc_list
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_msg_name_crc_list
+
+// #define vl_api_version(n,v) static u32 vpe_api_version = (v);
+// #include <vpp/api/vpe.api.h>
+// #undef vl_api_version
+
+#define POINTER_MAP_SIZE 32
+static void *global_pointers_map[POINTER_MAP_SIZE];
+static uint8_t global_pointers_map_index = 0;
+
+/*
+ * Table of message reply handlers, must include boilerplate handlers
+ * we just generated
+ */
+#define foreach_memif_api_reply_msg         \
+  _(MEMIF_CREATE_REPLY, memif_create_reply) \
+  _(MEMIF_DELETE_REPLY, memif_delete_reply) \
+  _(MEMIF_DETAILS, memif_details)
+
+/**
+ * @brief Generic VPP request structure.
+ */
+typedef struct __attribute__((packed)) vl_generic_request_s {
+  u16 _vl_msg_id;
+  u32 client_index;
+  u32 context;
+} vl_generic_request_t;
+
+/**
+ * @brief Generic VPP reply structure (response with a single message).
+ */
+typedef struct __attribute__((packed)) vl_generic_reply_s {
+  u16 _vl_msg_id;
+  u32 context;
+  i32 retval;
+} vl_generic_reply_t;
+
+static void vl_api_control_ping_reply_t_handler(
+    vl_api_control_ping_reply_t *mp) {
+  // Just unblock main thread
+  vpp_binary_api_t *binary_api = global_pointers_map[mp->context];
+  binary_api->ret_val = ntohl(mp->retval);
+  vpp_binary_api_unlock_waiting_thread(binary_api);
+}
+
+static void vl_api_sw_interface_set_flags_reply_t_handler(
+    vl_api_control_ping_reply_t *mp) {
+  // Unblock main thread setting reply message status code
+  vpp_binary_api_t *binary_api = global_pointers_map[mp->context];
+  binary_api->ret_val = ntohl(mp->retval);
+  vpp_binary_api_unlock_waiting_thread(binary_api);
+}
+
+static int vpp_connect_to_vlib(vpp_binary_api_t *binary_api, char *name) {
+  clib_mem_init_thread_safe(0, 256 << 20);
+  if (vl_client_connect_to_vlib("/vpe-api", name, 32) < 0) {
+    return -1;
+  }
+
+  binary_api->vl_input_queue = binary_api->api_main->shmem_hdr->vl_input_queue;
+  binary_api->my_client_index = binary_api->api_main->my_client_index;
+
+  return 0;
+}
+
+vpp_binary_api_t *vpp_binary_api_init(const char *app_name) {
+  vpp_binary_api_t *ret = malloc(sizeof(vpp_binary_api_t));
+  ret->api_main = &api_main;
+  ret->vlib_main = &vlib_global_main;
+
+  vpp_connect_to_vlib(ret, (char *)app_name);
+  ret->semaphore = sem_open(app_name, O_CREAT, 0, 0);
+
+  return ret;
+}
+
+void vpp_binary_api_destroy(vpp_binary_api_t *api) {
+  sem_close(api->semaphore);
+  free(api);
+  vl_client_disconnect_from_vlib();
+}
+
+void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t *api) {
+  sem_post(api->semaphore);
+}
+
+void vpp_binary_api_send_receive_ping(vpp_binary_api_t *api) {
+  /* Use a control ping for synchronization */
+
+  /* Get the control ping ID */
+#define _(id, n, crc) \
+  const char *id##_CRC __attribute__((unused)) = #n "_" #crc;
+  foreach_vl_msg_name_crc_vpe;
+#undef _
+
+  int ping_reply_id =
+      vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_REPLY_CRC));
+  vl_msg_api_set_handlers(ping_reply_id, "control_ping_reply",
+                          vl_api_control_ping_reply_t_handler, vl_noop_handler,
+                          vl_api_control_ping_reply_t_endian,
+                          vl_api_control_ping_reply_t_print,
+                          sizeof(vl_api_control_ping_reply_t), 1);
+
+  vl_api_control_ping_t *mp_ping;
+  mp_ping = vl_msg_api_alloc_as_if_client(sizeof(*mp_ping));
+  mp_ping->_vl_msg_id = clib_host_to_net_u16(
+      vl_msg_api_get_msg_index((u8 *)(VL_API_CONTROL_PING_CRC)));
+  mp_ping->client_index = api->my_client_index;
+
+  global_pointers_map[global_pointers_map_index] = api;
+  mp_ping->context = global_pointers_map_index++;
+  global_pointers_map_index %= POINTER_MAP_SIZE;
+
+  TRANSPORT_LOGI("Sending ping id %u", mp_ping->_vl_msg_id);
+
+  vpp_binary_api_send_request_wait_reply(api, mp_ping);
+}
+
+int vpp_binary_api_set_int_state(vpp_binary_api_t *api, uint32_t sw_index,
+                                 link_state_t state) {
+#define _(id, n, crc) \
+  const char *id##_CRC __attribute__((unused)) = #n "_" #crc;
+  foreach_vl_msg_name_crc_vpe;
+#undef _
+
+  int sw_interface_set_flags_reply_id = VL_API_SW_INTERFACE_SET_FLAGS_REPLY;
+  vl_msg_api_set_handlers(
+      sw_interface_set_flags_reply_id, "sw_interface_set_flags_reply",
+      vl_api_sw_interface_set_flags_reply_t_handler, vl_noop_handler,
+      vl_api_sw_interface_set_flags_reply_t_endian,
+      vl_api_sw_interface_set_flags_reply_t_print,
+      sizeof(vl_api_sw_interface_set_flags_reply_t), 1);
+
+  vl_api_sw_interface_set_flags_t *mp;
+  mp = vl_msg_api_alloc_as_if_client(sizeof(*mp));
+  mp->_vl_msg_id = clib_host_to_net_u16(VL_API_SW_INTERFACE_SET_FLAGS);
+  mp->client_index = api->my_client_index;
+  mp->sw_if_index = clib_host_to_net_u32(sw_index);
+  mp->admin_up_down = (u8)state;
+
+  global_pointers_map[global_pointers_map_index] = api;
+  mp->context = global_pointers_map_index++;
+  global_pointers_map_index %= POINTER_MAP_SIZE;
+
+  TRANSPORT_LOGI("Sending set int flags id %u", mp->_vl_msg_id);
+
+  return vpp_binary_api_send_request_wait_reply(api, mp);
+}
+
+void vpp_binary_api_send_request(vpp_binary_api_t *api, void *request) {
+  vl_generic_request_t *req = NULL;
+
+  req = (vl_generic_request_t *)request;
+  TRANSPORT_LOGI("Sending a request to VPP (id=%d).\n", ntohs(req->_vl_msg_id));
+
+  S(api, req);
+}
+
+int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t *api,
+                                           void *request) {
+  vpp_binary_api_send_request(api, request);
+
+  sem_wait(api->semaphore);
+
+  return api->ret_val;
+}
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api.h b/libtransport/src/hicn/transport/core/vpp_binary_api.h
new file mode 100755 (executable)
index 0000000..1eb10e7
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct vpp_binary_api vpp_binary_api_t;
+typedef struct vpp_plugin_binary_api vpp_plugin_binary_api_t;
+
+typedef enum link_state_s { UP = 1, DOWN = 0 } link_state_t;
+
+/**
+ * @brief Instantiate a new vpp_binary_api_t data structure and
+ *        connect the application to the local VPP forwarder.
+ */
+vpp_binary_api_t* vpp_binary_api_init(const char* app_name);
+
+/**
+ * @brief Destroy the vpp_binary_api_t and disconnect from VPP.
+ */
+void vpp_binary_api_destroy(vpp_binary_api_t* api);
+
+void vpp_binary_api_send_receive_ping(vpp_binary_api_t* api);
+
+int vpp_binary_api_set_int_state(vpp_binary_api_t* api, uint32_t sw_index,
+                                 link_state_t state);
+
+/**
+ * @brief Send request to VPP and wait for reply.
+ */
+int vpp_binary_api_send_request_wait_reply(vpp_binary_api_t* api,
+                                           void* request);
+
+void vpp_binary_api_unlock_waiting_thread(vpp_binary_api_t* api);
+
+void vpp_binary_api_send_request(vpp_binary_api_t* api, void* request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h b/libtransport/src/hicn/transport/core/vpp_binary_api_internal.h
new file mode 100755 (executable)
index 0000000..22b665e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <semaphore.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+struct vpp_binary_api {
+  api_main_t *api_main;
+  u32 my_client_index;
+  unix_shared_memory_queue_t *vl_input_queue;
+  vlib_main_t *vlib_main;
+  sem_t *semaphore;
+  u32 ping_id;
+  int ret_val;
+  void *user_param;
+};
+
+struct vpp_plugin_binary_api {
+  vpp_binary_api_t *vpp_api;
+  u16 msg_id_base;
+  u32 my_client_index;
+};
+
+#define M(T, mp)                                          \
+  do {                                                    \
+    mp = vl_msg_api_alloc_as_if_client(sizeof(*mp));      \
+    memset(mp, 0, sizeof(*mp));                           \
+    mp->_vl_msg_id = ntohs(VL_API_##T + hm->msg_id_base); \
+    mp->client_index = hm->my_client_index;               \
+  } while (0);
+
+#define S(api, mp) (vl_msg_api_send_shmem(api->vl_input_queue, (u8 *)&mp))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __vpp__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.cc
new file mode 100755 (executable)
index 0000000..3a748c8
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/hicn_binary_api.h>
+#include <hicn/transport/core/memif_binary_api.h>
+#include <hicn/transport/core/vpp_forwarder_interface.h>
+
+typedef enum { MASTER = 0, SLAVE = 1 } memif_role_t;
+
+#define MEMIF_DEFAULT_RING_SIZE 2048
+#define MEMIF_DEFAULT_RX_QUEUES 1
+#define MEMIF_DEFAULT_TX_QUEUES 1
+#define MEMIF_DEFAULT_BUFFER_SIZE 2048
+
+namespace transport {
+
+namespace core {
+
+vpp_binary_api_t *VPPForwarderInterface::api_ = nullptr;
+vpp_plugin_binary_api_t *VPPForwarderInterface::memif_api_ = nullptr;
+vpp_plugin_binary_api_t *VPPForwarderInterface::hicn_api_ = nullptr;
+std::mutex VPPForwarderInterface::global_lock_;
+
+VPPForwarderInterface::VPPForwarderInterface(MemifConnector &connector)
+    : ForwarderInterface<VPPForwarderInterface, MemifConnector>(connector),
+      sw_if_index_(~0),
+      face_id_(~0) {}
+
+VPPForwarderInterface::~VPPForwarderInterface() {}
+
+/**
+ * @brief Create a memif interface in the local VPP forwarder.
+ */
+uint32_t VPPForwarderInterface::getMemifConfiguration() {
+  memif_create_params_t input_params = {0};
+
+  memif_id_ =
+      memif_binary_api_get_next_memif_id(VPPForwarderInterface::memif_api_);
+
+  input_params.id = memif_id_;
+  input_params.role = memif_role_t::MASTER;
+  input_params.mode = memif_interface_mode_t::MEMIF_INTERFACE_MODE_IP;
+  input_params.rx_queues = MEMIF_DEFAULT_RX_QUEUES;
+  input_params.tx_queues = MEMIF_DEFAULT_TX_QUEUES;
+  input_params.ring_size = MEMIF_DEFAULT_RING_SIZE;
+  input_params.buffer_size = MEMIF_DEFAULT_BUFFER_SIZE;
+
+  memif_output_params_t output_params = {0};
+
+  if (memif_binary_api_create_memif(VPPForwarderInterface::memif_api_,
+                                    &input_params, &output_params) < 0) {
+    throw errors::RuntimeException(
+        "Error creating memif interface in the local VPP forwarder.");
+  }
+
+  return output_params.sw_if_index;
+}
+
+void VPPForwarderInterface::consumerConnection() {
+  hicn_consumer_input_params input = {0};
+  hicn_consumer_output_params output;
+
+  std::memset(&output, 0, sizeof(hicn_consumer_output_params));
+
+  input.swif = sw_if_index_;
+
+  if (int ret = hicn_binary_api_register_cons_app(
+                    VPPForwarderInterface::hicn_api_, &input, &output) < 0) {
+    throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+  }
+
+  inet_address_.family = AF_INET;
+  inet_address_.prefix_len = output.src4.prefix_length;
+  std::memcpy(inet_address_.buffer, output.src4.ip4.as_u8, IPV4_ADDR_LEN);
+
+  inet6_address_.family = AF_INET6;
+  inet6_address_.prefix_len = output.src6.prefix_length;
+  std::memcpy(inet6_address_.buffer, output.src6.ip6.as_u8, IPV6_ADDR_LEN);
+}
+
+void VPPForwarderInterface::producerConnection() {
+  // Producer connection will be set when we set the first route.
+}
+
+void VPPForwarderInterface::connect(bool is_consumer) {
+  std::lock_guard<std::mutex> connection_lock(global_lock_);
+
+  srand(time(NULL));
+  int secret = rand() % (1 << 10);
+  std::stringstream app_name;
+  app_name << "Libtransport_" << secret;
+
+  if (!VPPForwarderInterface::memif_api_) {
+    VPPForwarderInterface::api_ = vpp_binary_api_init(app_name.str().c_str());
+  }
+
+  VPPForwarderInterface::memif_api_ =
+      memif_binary_api_init(VPPForwarderInterface::api_);
+
+  sw_if_index_ = getMemifConfiguration();
+
+  VPPForwarderInterface::hicn_api_ =
+      hicn_binary_api_init(VPPForwarderInterface::api_);
+  if (is_consumer) {
+    consumerConnection();
+  }
+
+  connector_.connect(memif_id_, 0);
+}
+
+void VPPForwarderInterface::registerRoute(Prefix &prefix) {
+  auto &addr = prefix.toIpAddressStruct();
+
+  if (face_id_ == uint32_t(~0)) {
+    hicn_producer_input_params input;
+    std::memset(&input, 0, sizeof(input));
+
+    hicn_producer_output_params output;
+    std::memset(&output, 0, sizeof(output));
+
+    // Here we have to ask to the actual connector what is the
+    // memif_id, since this function should be called after the
+    // memif creation.
+    input.swif = sw_if_index_;
+    input.prefix.ip6.as_u64[0] = addr.as_u64[0];
+    input.prefix.ip6.as_u64[1] = addr.as_u64[1];
+    input.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4;
+    input.prefix.prefix_length = addr.prefix_len;
+    input.cs_reserved = content_store_reserved_;
+
+    if (int ret = hicn_binary_api_register_prod_app(
+                      VPPForwarderInterface::hicn_api_, &input, &output) < 0) {
+      throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+    }
+
+    if (addr.family == AF_INET6) {
+      inet6_address_.prefix_len = output.prod_addr.prefix_length;
+      std::memcpy(inet6_address_.buffer, output.prod_addr.ip6.as_u8,
+                  IPV6_ADDR_LEN);
+    } else {
+      inet_address_.prefix_len = output.prod_addr.prefix_length;
+      // The ipv4 is written in the last 4 bytes of the ipv6 address, so we need
+      // to copy from the byte 12
+      std::memcpy(inet_address_.buffer, output.prod_addr.ip6.as_u8 + 12,
+                  IPV4_ADDR_LEN);
+    }
+
+    face_id_ = output.face_id;
+  } else {
+    hicn_producer_set_route_params params;
+    params.prefix.ip6.as_u64[0] = addr.as_u64[0];
+    params.prefix.ip6.as_u64[1] = addr.as_u64[1];
+    params.prefix.type = addr.family == AF_INET6 ? IP_TYPE_IP6 : IP_TYPE_IP4;
+    params.prefix.prefix_length = addr.prefix_len;
+    params.face_id = face_id_;
+
+    if (int ret = hicn_binary_api_register_route(
+                      VPPForwarderInterface::hicn_api_, &params) < 0) {
+      throw errors::RuntimeException(hicn_binary_api_get_error_string(ret));
+    }
+  }
+}
+
+}  // namespace core
+
+}  // namespace transport
+
+#endif
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h b/libtransport/src/hicn/transport/core/vpp_forwarder_interface.h
new file mode 100755 (executable)
index 0000000..322cd1f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+
+#ifdef __vpp__
+
+#include <hicn/transport/core/forwarder_interface.h>
+#include <hicn/transport/core/memif_connector.h>
+#include <hicn/transport/core/prefix.h>
+
+#include <deque>
+
+namespace transport {
+
+namespace core {
+
+class VPPForwarderInterface
+    : public ForwarderInterface<VPPForwarderInterface, MemifConnector> {
+ public:
+  VPPForwarderInterface(MemifConnector &connector);
+
+  typedef MemifConnector ConnectorType;
+
+  ~VPPForwarderInterface();
+
+  void connect(bool is_consumer);
+
+  void registerRoute(Prefix &prefix);
+
+  TRANSPORT_ALWAYS_INLINE std::uint16_t getMtu() { return interface_mtu; }
+
+ private:
+  uint32_t getMemifConfiguration();
+
+  void consumerConnection();
+
+  void producerConnection();
+
+  static vpp_binary_api_t *api_;
+  static vpp_plugin_binary_api_t *memif_api_;
+  static vpp_plugin_binary_api_t *hicn_api_;
+  uint32_t memif_id_;
+  uint32_t sw_if_index_;
+  uint32_t face_id_;
+  static std::mutex global_lock_;
+  static constexpr std::uint16_t interface_mtu = 1500;
+};
+
+}  // namespace core
+
+}  // namespace transport
+
+#endif
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/CMakeLists.txt b/libtransport/src/hicn/transport/errors/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1c19a90
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/not_implemented_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/invalid_ip_address_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/malformed_name_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/errors.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/malformed_packet_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/runtime_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/tokenizer_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/null_pointer_exception.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/malformed_ahpacket_exception.h
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/errors.h b/libtransport/src/hicn/transport/errors/errors.h
new file mode 100755 (executable)
index 0000000..512e357
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/errors/invalid_ip_address_exception.h>
+#include <hicn/transport/errors/malformed_name_exception.h>
+#include <hicn/transport/errors/malformed_packet_exception.h>
+#include <hicn/transport/errors/not_implemented_exception.h>
+#include <hicn/transport/errors/null_pointer_exception.h>
+#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/errors/tokenizer_exception.h>
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h b/libtransport/src/hicn/transport/errors/invalid_ip_address_exception.h
new file mode 100755 (executable)
index 0000000..60226f5
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class InvalidIpAddressException : public std::runtime_error {
+ public:
+  InvalidIpAddressException() : std::runtime_error("") {}
+
+  virtual char const *what() const noexcept override {
+    return "Malformed IP address.";
+  }
+};
+
+}  // end namespace errors
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h b/libtransport/src/hicn/transport/errors/malformed_ahpacket_exception.h
new file mode 100755 (executable)
index 0000000..f0cfe0b
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class MalformedAHPacketException : public std::runtime_error {
+ public:
+  MalformedAHPacketException() : std::runtime_error("") {}
+
+  virtual char const *what() const noexcept override {
+    return "Malformed AH packet.";
+  }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/malformed_name_exception.h b/libtransport/src/hicn/transport/errors/malformed_name_exception.h
new file mode 100755 (executable)
index 0000000..4ef45d2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class MalformedNameException : public std::runtime_error {
+ public:
+  MalformedNameException() : std::runtime_error("") {}
+
+  virtual char const *what() const noexcept override {
+    return "Malformed IP address.";
+  }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/malformed_packet_exception.h b/libtransport/src/hicn/transport/errors/malformed_packet_exception.h
new file mode 100755 (executable)
index 0000000..ec5c97e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class MalformedPacketException : public std::runtime_error {
+ public:
+  MalformedPacketException() : std::runtime_error("") {}
+
+  char const *what() const noexcept override { return "Malformed IP packet."; }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/not_implemented_exception.h b/libtransport/src/hicn/transport/errors/not_implemented_exception.h
new file mode 100755 (executable)
index 0000000..e986916
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class NotImplementedException : public std::logic_error {
+ public:
+  NotImplementedException() : std::logic_error("") {}
+  virtual char const *what() const noexcept override {
+    return "Function not yet implemented.";
+  }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/null_pointer_exception.h b/libtransport/src/hicn/transport/errors/null_pointer_exception.h
new file mode 100755 (executable)
index 0000000..bd06485
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class NullPointerException : public std::runtime_error {
+ public:
+  NullPointerException() : std::runtime_error("") {}
+
+  char const *what() const noexcept override {
+    return "Null pointer exception.";
+  }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/errors/runtime_exception.h b/libtransport/src/hicn/transport/errors/runtime_exception.h
new file mode 100755 (executable)
index 0000000..ba5128a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+namespace errors {
+
+class RuntimeException : public std::runtime_error {
+ public:
+  RuntimeException() : std::runtime_error("") {}
+
+  RuntimeException(std::string what) : runtime_error(what){};
+};
+
+}  // end namespace errors
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/errors/tokenizer_exception.h b/libtransport/src/hicn/transport/errors/tokenizer_exception.h
new file mode 100755 (executable)
index 0000000..76eda83
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdexcept>
+
+namespace errors {
+
+class TokenizerException : public std::logic_error {
+ public:
+  TokenizerException() : std::logic_error("") {}
+
+  virtual char const *what() const noexcept override {
+    return "No more tokens available.";
+  }
+};
+
+}  // end namespace errors
diff --git a/libtransport/src/hicn/transport/http/CMakeLists.txt b/libtransport/src/hicn/transport/http/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..ddcf1fd
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/request.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/response.cc)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/client_connection.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/request.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/server_publisher.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/server_acceptor.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/default_values.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/facade.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/response.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/message.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/callbacks.h
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/callbacks.h b/libtransport/src/hicn/transport/http/callbacks.h
new file mode 100755 (executable)
index 0000000..5ca5fcb
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/server_publisher.h>
+
+#include <functional>
+#include <memory>
+
+namespace transport {
+
+namespace http {
+
+enum class RC : uint8_t {
+  SUCCESS,
+  CONTENT_PUBLISHED,
+  ERR_UNDEFINED,
+};
+
+using OnHttpRequest =
+    std::function<void(std::shared_ptr<HTTPServerPublisher>&, const uint8_t*,
+                       std::size_t, int request_id)>;
+using DeadlineTimerCallback = std::function<void(const std::error_code& e)>;
+using ReceiveCallback = std::function<void(const std::vector<uint8_t>&)>;
+using OnPayloadCallback = std::function<RC(
+    const std::error_code& ec, const core::Name& name,
+    const std::shared_ptr<utils::SharableVector<uint8_t>>& payload)>;
+using ContentSentCallback =
+    std::function<void(const std::error_code&, const core::Name&)>;
+
+}  // namespace http
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/client_connection.cc b/libtransport/src/hicn/transport/http/client_connection.cc
new file mode 100755 (executable)
index 0000000..d4207bb
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/http/client_connection.h>
+#include <hicn/transport/utils/hash.h>
+
+#define DEFAULT_BETA 0.99
+#define DEFAULT_GAMMA 0.07
+
+namespace transport {
+
+namespace http {
+
+using namespace transport;
+
+HTTPClientConnection::HTTPClientConnection()
+    : consumer_(TransportProtocolAlgorithms::RAAQM, io_service_),
+      response_(std::make_shared<HTTPResponse>()),
+      timer_(nullptr) {
+  consumer_.setSocketOption(
+      ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
+      (ConsumerContentObjectVerificationCallback)std::bind(
+          &HTTPClientConnection::verifyData, this, std::placeholders::_1,
+          std::placeholders::_2));
+
+  consumer_.setSocketOption(
+      ConsumerCallbacksOptions::CONTENT_RETRIEVED,
+      (ConsumerContentCallback)std::bind(
+          &HTTPClientConnection::processPayload, this, std::placeholders::_1,
+          std::placeholders::_2, std::placeholders::_3));
+
+  consumer_.connect();
+  std::shared_ptr<typename ConsumerSocket::Portal> portal;
+  consumer_.getSocketOption(GeneralTransportOptions::PORTAL, portal);
+  timer_ = std::make_unique<asio::steady_timer>(portal->getIoService());
+}
+
+HTTPClientConnection &HTTPClientConnection::get(
+    const std::string &url, HTTPHeaders headers, HTTPPayload payload,
+    std::shared_ptr<HTTPResponse> response) {
+  return sendRequest(url, HTTPMethod::GET, headers, payload, response);
+}
+
+HTTPClientConnection &HTTPClientConnection::sendRequest(
+    const std::string &url, HTTPMethod method, HTTPHeaders headers,
+    HTTPPayload payload, std::shared_ptr<HTTPResponse> response) {
+  if (!response) {
+    response = response_;
+  }
+
+  auto start = std::chrono::steady_clock::now();
+  HTTPRequest request(method, url, headers, payload);
+  std::string name = sendRequestGetReply(request, response);
+  auto end = std::chrono::steady_clock::now();
+
+  TRANSPORT_LOGI(
+      "%s %s [%s] duration: %llu [usec] %zu [bytes]\n",
+      method_map[method].c_str(), url.c_str(), name.c_str(),
+      (unsigned long long)std::chrono::duration_cast<std::chrono::microseconds>(
+          end - start)
+          .count(),
+      response->size());
+
+  return *this;
+}
+
+std::string HTTPClientConnection::sendRequestGetReply(
+    const HTTPRequest &request, std::shared_ptr<HTTPResponse> &response) {
+  const std::string &request_string = request.getRequestString();
+  const std::string &locator = request.getLocator();
+
+  // Hash it
+
+  uint32_t locator_hash =
+      utils::hash::fnv32_buf(locator.c_str(), locator.size());
+  uint64_t request_hash =
+      utils::hash::fnv64_buf(request_string.c_str(), request_string.size());
+
+  consumer_.setSocketOption(
+      ConsumerCallbacksOptions::INTEREST_OUTPUT,
+      (ConsumerInterestCallback)std::bind(
+          &HTTPClientConnection::processLeavingInterest, this,
+          std::placeholders::_1, std::placeholders::_2, request_string));
+
+  // Send content to producer piggybacking it through first interest (to fix)
+
+  response->clear();
+
+  // Factor hicn name using hash
+
+  std::stringstream stream;
+
+  stream << std::hex << http::default_values::ipv6_first_word << ":";
+
+  for (uint16_t *word = (uint16_t *)&locator_hash;
+       std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash));
+       word++) {
+    stream << ":" << std::hex << *word;
+  }
+
+  for (uint16_t *word = (uint16_t *)&request_hash;
+       std::size_t(word) < (std::size_t(&request_hash) + sizeof(request_hash));
+       word++) {
+    stream << ":" << std::hex << *word;
+  }
+
+  stream << "|0";
+
+  consumer_.consume(Name(stream.str()), *response);
+
+  consumer_.stop();
+
+  return stream.str();
+}
+
+HTTPResponse &&HTTPClientConnection::response() {
+  // response_->parse();
+  return std::move(*response_);
+}
+
+void HTTPClientConnection::processPayload(ConsumerSocket &c,
+                                          std::size_t bytes_transferred,
+                                          const std::error_code &ec) {
+  if (ec) {
+    TRANSPORT_LOGE("Download failed!!");
+  }
+}
+
+bool HTTPClientConnection::verifyData(
+    ConsumerSocket &c, const core::ContentObject &contentObject) {
+  if (contentObject.getPayloadType() == PayloadType::CONTENT_OBJECT) {
+    TRANSPORT_LOGI("VERIFY CONTENT\n");
+  } else if (contentObject.getPayloadType() == PayloadType::MANIFEST) {
+    TRANSPORT_LOGI("VERIFY MANIFEST\n");
+  }
+
+  return true;
+}
+
+void HTTPClientConnection::processLeavingInterest(
+    ConsumerSocket &c, const core::Interest &interest, std::string &payload) {
+  //  if (interest.getName().getSuffix() == 0) {
+  Interest &int2 = const_cast<Interest &>(interest);
+  int2.appendPayload((uint8_t *)payload.data(), payload.size());
+  //  }
+}
+
+ConsumerSocket &HTTPClientConnection::getConsumer() { return consumer_; }
+
+HTTPClientConnection &HTTPClientConnection::stop() {
+  // This is thread safe and can be called from another thread
+  consumer_.stop();
+
+  return *this;
+}
+
+HTTPClientConnection &HTTPClientConnection::setTimeout(
+    const std::chrono::seconds &timeout) {
+  timer_->cancel();
+  timer_->expires_from_now(timeout);
+  timer_->async_wait([this](std::error_code ec) {
+    if (!ec) {
+      consumer_.stop();
+    }
+  });
+
+  return *this;
+}
+
+HTTPClientConnection &HTTPClientConnection::setCertificate(
+    const std::string &cert_path) {
+  if (consumer_.setSocketOption(GeneralTransportOptions::CERTIFICATE,
+                                cert_path) == SOCKET_OPTION_NOT_SET) {
+    throw errors::RuntimeException("Error setting the certificate.");
+  }
+
+  return *this;
+}
+
+}  // namespace http
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/http/client_connection.h b/libtransport/src/hicn/transport/http/client_connection.h
new file mode 100755 (executable)
index 0000000..f6e1fa0
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/default_values.h>
+#include <hicn/transport/http/request.h>
+#include <hicn/transport/http/response.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/utils/uri.h>
+
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+using namespace interface;
+using namespace core;
+
+class HTTPClientConnection {
+ public:
+  HTTPClientConnection();
+
+  HTTPClientConnection &get(const std::string &url, HTTPHeaders headers = {},
+                            HTTPPayload payload = {},
+                            std::shared_ptr<HTTPResponse> response = nullptr);
+
+  HTTPClientConnection &sendRequest(
+      const std::string &url, HTTPMethod method, HTTPHeaders headers = {},
+      HTTPPayload payload = {},
+      std::shared_ptr<HTTPResponse> response = nullptr);
+
+  HTTPResponse &&response();
+
+  HTTPClientConnection &stop();
+
+  interface::ConsumerSocket &getConsumer();
+
+  HTTPClientConnection &setTimeout(const std::chrono::seconds &timeout);
+
+  HTTPClientConnection &setCertificate(const std::string &cert_path);
+
+ private:
+  void processPayload(interface::ConsumerSocket &c,
+                      std::size_t bytes_transferred, const std::error_code &ec);
+
+  std::string sendRequestGetReply(const HTTPRequest &request,
+                                  std::shared_ptr<HTTPResponse> &response);
+
+  bool verifyData(interface::ConsumerSocket &c,
+                  const core::ContentObject &contentObject);
+
+  void processLeavingInterest(interface::ConsumerSocket &c,
+                              const core::Interest &interest,
+                              std::string &payload);
+
+  asio::io_service io_service_;
+
+  ConsumerSocket consumer_;
+
+  std::shared_ptr<HTTPResponse> response_;
+
+  std::unique_ptr<asio::steady_timer> timer_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/default_values.h b/libtransport/src/hicn/transport/http/default_values.h
new file mode 100755 (executable)
index 0000000..2d5a6b8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace transport {
+
+namespace http {
+
+namespace default_values {
+
+const uint16_t ipv6_first_word = 0xb001;  // Network byte order
+
+}  // namespace default_values
+
+}  // namespace http
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/http/facade.h b/libtransport/src/hicn/transport/http/facade.h
new file mode 100755 (executable)
index 0000000..31c2d1b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/transport_http_client_connection.h>
+#include <hicn/transport/http/transport_http_server_acceptor.h>
+#include <hicn/transport/http/transport_http_server_publisher.h>
+
+namespace libl4 = transport;
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/message.h b/libtransport/src/hicn/transport/http/message.h
new file mode 100755 (executable)
index 0000000..7d4485c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+#define HTTP_VERSION "1.1"
+
+namespace transport {
+
+namespace http {
+
+typedef enum { GET, POST, PUT, PATCH, DELETE } HTTPMethod;
+
+static std::map<HTTPMethod, std::string> method_map = {
+    {GET, "GET"},     {POST, "POST"},     {PUT, "PUT"},
+    {PATCH, "PATCH"}, {DELETE, "DELETE"},
+};
+
+typedef std::map<std::string, std::string> HTTPHeaders;
+typedef std::vector<uint8_t> HTTPPayload;
+
+class HTTPMessage {
+ public:
+  virtual ~HTTPMessage() = default;
+
+  virtual const HTTPHeaders &getHeaders() = 0;
+
+  virtual const HTTPPayload &getPayload() = 0;
+
+  virtual const std::string &getHttpVersion() const = 0;
+
+ protected:
+  HTTPHeaders headers_;
+  HTTPPayload payload_;
+  std::string http_version_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/request.cc b/libtransport/src/hicn/transport/http/request.cc
new file mode 100755 (executable)
index 0000000..7a63b4f
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/http/request.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace transport {
+
+namespace http {
+
+// std::map<HTTPMethod, std::string> method_map
+
+HTTPRequest::HTTPRequest(HTTPMethod method, const std::string &url,
+                         const HTTPHeaders &headers,
+                         const HTTPPayload &payload) {
+  utils::Uri uri;
+  uri.parse(url);
+
+  path_ = uri.getPath();
+  query_string_ = uri.getQueryString();
+  protocol_ = uri.getProtocol();
+  locator_ = uri.getLocator();
+  port_ = uri.getPort();
+  http_version_ = HTTP_VERSION;
+
+  headers_ = headers;
+  payload_ = payload;
+
+  std::transform(locator_.begin(), locator_.end(), locator_.begin(), ::tolower);
+
+  std::transform(protocol_.begin(), protocol_.end(), protocol_.begin(),
+                 ::tolower);
+
+  std::stringstream stream;
+  stream << method_map[method] << " " << uri.getPath() << " HTTP/"
+         << HTTP_VERSION << "\r\n";
+  for (auto &item : headers) {
+    stream << item.first << ": " << item.second << "\r\n";
+  }
+  stream << "\r\n";
+
+  if (payload.size() > 0) {
+    stream << payload.data();
+  }
+
+  request_string_ = stream.str();
+}
+
+const std::string &HTTPRequest::getPort() const { return port_; }
+
+const std::string &HTTPRequest::getLocator() const { return locator_; }
+
+const std::string &HTTPRequest::getProtocol() const { return protocol_; }
+
+const std::string &HTTPRequest::getPath() const { return path_; }
+
+const std::string &HTTPRequest::getQueryString() const { return query_string_; }
+
+const HTTPHeaders &HTTPRequest::getHeaders() { return headers_; }
+
+const HTTPPayload &HTTPRequest::getPayload() { return payload_; }
+
+const std::string &HTTPRequest::getRequestString() const {
+  return request_string_;
+}
+
+const std::string &HTTPRequest::getHttpVersion() const { return http_version_; }
+
+}  // namespace http
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/request.h b/libtransport/src/hicn/transport/http/request.h
new file mode 100755 (executable)
index 0000000..88d67d4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/message.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPRequest : public HTTPMessage {
+ public:
+  HTTPRequest(HTTPMethod method, const std::string &url,
+              const HTTPHeaders &headers, const HTTPPayload &payload);
+
+  const std::string &getQueryString() const;
+
+  const std::string &getPath() const;
+
+  const std::string &getProtocol() const;
+
+  const std::string &getLocator() const;
+
+  const std::string &getPort() const;
+
+  const std::string &getRequestString() const;
+
+  const HTTPHeaders &getHeaders() override;
+
+  const HTTPPayload &getPayload() override;
+
+  const std::string &getHttpVersion() const override;
+
+ private:
+  std::string query_string_, path_, protocol_, locator_, port_;
+  std::string request_string_;
+  HTTPHeaders headers_;
+  HTTPPayload payload_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/response.cc b/libtransport/src/hicn/transport/http/response.cc
new file mode 100755 (executable)
index 0000000..0aa9aff
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/errors/errors.h>
+#include <hicn/transport/http/response.h>
+
+#include <algorithm>
+
+#include <cstring>
+
+namespace transport {
+
+namespace http {
+
+HTTPResponse::HTTPResponse() {}
+
+HTTPResponse::HTTPResponse(const HTTPHeaders &headers,
+                           const HTTPPayload &payload) {
+  headers_ = headers;
+  payload_ = payload;
+}
+
+const HTTPHeaders &HTTPResponse::getHeaders() {
+  parse();
+  return headers_;
+}
+
+const HTTPPayload &HTTPResponse::getPayload() {
+  parse();
+  return payload_;
+}
+
+bool HTTPResponse::parseHeaders() {
+  const char *crlf2 = "\r\n\r\n";
+  auto it =
+      std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+  if (it != end()) {
+    std::stringstream ss;
+    ss.str(std::string(begin(), it));
+
+    std::string line;
+    getline(ss, line);
+    std::istringstream line_s(line);
+    std::string _http_version;
+    std::string http_version;
+
+    line_s >> _http_version;
+    std::size_t separator;
+    if ((separator = _http_version.find('/')) != std::string::npos) {
+      if (_http_version.substr(0, separator) != "HTTP") {
+        return false;
+      }
+      http_version_ =
+          line.substr(separator + 1, _http_version.length() - separator - 1);
+    } else {
+      return false;
+    }
+
+    std::string status_code, status_string;
+
+    line_s >> status_code_;
+    line_s >> status_string;
+
+    auto _it = std::search(line.begin(), line.end(), status_string.begin(),
+                           status_string.end());
+
+    status_string_ = std::string(_it, line.end() - 1);
+
+    std::size_t param_end;
+    std::size_t value_start;
+    while (getline(ss, line)) {
+      if ((param_end = line.find(':')) != std::string::npos) {
+        value_start = param_end + 1;
+        if ((value_start) < line.size()) {
+          if (line[value_start] == ' ') {
+            value_start++;
+          }
+          if (value_start < line.size()) {
+            headers_[line.substr(0, param_end)] =
+                line.substr(value_start, line.size() - value_start - 1);
+          }
+        }
+      } else {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+void HTTPResponse::parse() {
+  if (!parseHeaders()) {
+    throw errors::RuntimeException("Malformed HTTP response");
+  }
+
+  if (payload_.empty()) {
+    const char *crlf2 = "\r\n\r\n";
+    auto it =
+        std::search(this->begin(), this->end(), crlf2, crlf2 + strlen(crlf2));
+
+    if (it != this->end()) {
+      erase(begin(), it + strlen(crlf2));
+      payload_ = std::move(*dynamic_cast<std::vector<uint8_t> *>(this));
+    }
+  }
+}
+
+const std::string &HTTPResponse::getStatusCode() const { return status_code_; }
+
+const std::string &HTTPResponse::getStatusString() const {
+  return status_string_;
+}
+
+const std::string &HTTPResponse::getHttpVersion() const {
+  return http_version_;
+}
+
+}  // namespace http
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/response.h b/libtransport/src/hicn/transport/http/response.h
new file mode 100755 (executable)
index 0000000..e7dec8c
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/message.h>
+#include <hicn/transport/utils/array.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPResponse : public HTTPMessage, public utils::SharableVector<uint8_t> {
+ public:
+  HTTPResponse(const HTTPHeaders &headers, const HTTPPayload &payload);
+
+  HTTPResponse();
+
+  const HTTPHeaders &getHeaders() override;
+
+  const HTTPPayload &getPayload() override;
+
+  const std::string &getStatusCode() const;
+
+  const std::string &getStatusString() const;
+
+  const std::string &getHttpVersion() const override;
+
+  void parse();
+
+ private:
+  bool parseHeaders();
+
+ private:
+  std::string status_code_;
+  std::string status_string_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/http/server_acceptor.cc b/libtransport/src/hicn/transport/http/server_acceptor.cc
new file mode 100755 (executable)
index 0000000..717dfb6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/http/server_acceptor.h>
+#include <hicn/transport/utils/hash.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace transport {
+
+namespace http {
+
+HTTPServerAcceptor::HTTPServerAcceptor(std::string &&server_locator,
+                                       OnHttpRequest callback)
+    : HTTPServerAcceptor(server_locator, callback) {}
+
+HTTPServerAcceptor::HTTPServerAcceptor(std::string &server_locator,
+                                       OnHttpRequest callback)
+    : callback_(callback) {
+  utils::Uri uri;
+
+  uri.parseProtocolAndLocator(server_locator);
+  std::string protocol = uri.getProtocol();
+  std::string locator = uri.getLocator();
+
+  std::transform(locator.begin(), locator.end(), locator.begin(), ::tolower);
+
+  std::transform(protocol.begin(), protocol.end(), protocol.begin(), ::tolower);
+
+  if (protocol != "http") {
+    throw errors::RuntimeException(
+        "Malformed server_locator. The locator format should be in the form "
+        "http://locator");
+  }
+
+  uint32_t locator_hash =
+      utils::hash::fnv32_buf(locator.c_str(), locator.size());
+
+  std::stringstream stream;
+  stream << std::hex << http::default_values::ipv6_first_word << ":0000";
+
+  for (uint16_t *word = (uint16_t *)&locator_hash;
+       std::size_t(word) < (std::size_t(&locator_hash) + sizeof(locator_hash));
+       word++) {
+    stream << ":" << std::hex << *word;
+  }
+
+  stream << "::0";
+
+  std::string network = stream.str();
+
+  core::Prefix acceptor_namespace(network, 64);
+
+  std::string producer_identity = "acceptor_producer";
+  acceptor_producer_ = std::make_shared<ProducerSocket>(
+      io_service_); /*,
+                                 utils::Identity::generateIdentity(producer_identity));*/
+  acceptor_producer_->registerPrefix(acceptor_namespace);
+}
+
+void HTTPServerAcceptor::listen(bool async) {
+  acceptor_producer_->setSocketOption(
+      ProducerCallbacksOptions::INTEREST_INPUT,
+      (ProducerInterestCallback)bind(
+          &HTTPServerAcceptor::processIncomingInterest, this,
+          std::placeholders::_1, std::placeholders::_2));
+  acceptor_producer_->connect();
+
+  if (!async) {
+    acceptor_producer_->serveForever();
+  }
+}
+
+void HTTPServerAcceptor::processIncomingInterest(ProducerSocket &p,
+                                                 const Interest &interest) {
+  // Temporary solution. With
+  utils::Array<uint8_t> payload = interest.getPayload();
+
+  int request_id = utils::hash::fnv32_buf(payload.data(), payload.length());
+
+  if (publishers_.find(request_id) != publishers_.end()) {
+    if (publishers_[request_id]) {
+      publishers_[request_id]->getProducer().onInterest(interest);
+      return;
+    }
+  }
+
+  publishers_[request_id] =
+      std::make_shared<HTTPServerPublisher>(interest.getName());
+  callback_(publishers_[request_id], (uint8_t *)payload.data(),
+            payload.length(), request_id);
+}
+
+std::map<int, std::shared_ptr<HTTPServerPublisher>>
+    &HTTPServerAcceptor::getPublishers() {
+  return publishers_;
+}
+
+}  // namespace http
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_acceptor.h b/libtransport/src/hicn/transport/http/server_acceptor.h
new file mode 100755 (executable)
index 0000000..5499624
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/callbacks.h>
+#include <hicn/transport/http/default_values.h>
+#include <hicn/transport/http/request.h>
+#include <hicn/transport/http/server_publisher.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+#include <functional>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+class HTTPServerAcceptor {
+  friend class HTTPServerPublisher;
+
+ public:
+  HTTPServerAcceptor(std::string &&server_locator, OnHttpRequest callback);
+  HTTPServerAcceptor(std::string &server_locator, OnHttpRequest callback);
+
+  void listen(bool async);
+
+  std::map<int, std::shared_ptr<HTTPServerPublisher>> &getPublishers();
+
+  //  void asyncSendResponse();
+
+  //  HTTPClientConnection& get(std::string &url, HTTPHeaders headers = {},
+  //  HTTPPayload payload = {});
+  //
+  //  HTTPResponse&& response();
+
+ private:
+  void processIncomingInterest(ProducerSocket &p, const Interest &interest);
+
+  OnHttpRequest callback_;
+  asio::io_service io_service_;
+  std::shared_ptr<ProducerSocket> acceptor_producer_;
+
+  std::map<int, std::shared_ptr<HTTPServerPublisher>> publishers_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_publisher.cc b/libtransport/src/hicn/transport/http/server_publisher.cc
new file mode 100755 (executable)
index 0000000..012f360
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/http/server_publisher.h>
+#include <hicn/transport/utils/literals.h>
+
+namespace transport {
+
+namespace http {
+
+HTTPServerPublisher::HTTPServerPublisher(const core::Name &content_name)
+    : content_name_(content_name, true) {
+  std::string identity = "acceptor_producer";
+  producer_ = std::make_unique<ProducerSocket>(io_service_);
+  //                                                          utils::Identity::generateIdentity(identity));
+  core::Prefix publisher_prefix(content_name_, 128);
+  producer_->registerPrefix(publisher_prefix);
+}
+
+HTTPServerPublisher::~HTTPServerPublisher() {
+  if (timer_) {
+    this->timer_->cancel();
+  }
+}
+
+HTTPServerPublisher &HTTPServerPublisher::attachPublisher() {
+  // Create a new publisher
+  producer_->setSocketOption(GeneralTransportOptions::DATA_PACKET_SIZE,
+                             1410_U32);
+  producer_->connect();
+  return *this;
+}
+
+HTTPServerPublisher &HTTPServerPublisher::setTimeout(
+    const std::chrono::milliseconds &timeout, bool timeout_renewal) {
+  std::shared_ptr<typename ProducerSocket::Portal> portal;
+  producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal);
+  timer_ =
+      std::make_unique<asio::steady_timer>(portal->getIoService(), timeout);
+
+  wait_callback_ = [this](const std::error_code &e) {
+    if (!e) {
+      producer_->stop();
+    }
+  };
+
+  if (timeout_renewal) {
+    interest_enter_callback_ = [this, timeout](ProducerSocket &p,
+                                               const Interest &interest) {
+      this->timer_->cancel();
+      this->timer_->expires_from_now(timeout);
+      this->timer_->async_wait(wait_callback_);
+    };
+
+    producer_->setSocketOption(
+        ProducerCallbacksOptions::CACHE_HIT,
+        (ProducerInterestCallback)interest_enter_callback_);
+  }
+
+  timer_->async_wait(wait_callback_);
+
+  return *this;
+}
+
+void HTTPServerPublisher::publishContent(
+    const uint8_t *buf, size_t buffer_size,
+    std::chrono::milliseconds content_lifetime, bool is_last) {
+  if (producer_) {
+    producer_->setSocketOption(
+        GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+        static_cast<uint32_t>(content_lifetime.count()));
+    producer_->produce(content_name_, buf, buffer_size, is_last);
+    //    producer_->setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+    //                                [this](ProducerSocket &p, const
+    //                                core::Interest &interest){
+    //                                  producer_->stop();
+    //                                });
+  }
+}
+
+template <typename Handler>
+void HTTPServerPublisher::asyncPublishContent(
+    const uint8_t *buf, size_t buffer_size,
+    std::chrono::milliseconds content_lifetime, Handler &&handler,
+    bool is_last) {
+  if (producer_) {
+    producer_->setSocketOption(
+        GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+        static_cast<uint32_t>(content_lifetime.count()));
+    producer_->asyncProduce(content_name_, buf, buffer_size,
+                            std::forward<Handler>(handler), is_last);
+  }
+}
+
+void HTTPServerPublisher::serveClients() { producer_->serveForever(); }
+
+void HTTPServerPublisher::stop() {
+  std::shared_ptr<typename ProducerSocket::Portal> portal_ptr;
+  producer_->getSocketOption(GeneralTransportOptions::PORTAL, portal_ptr);
+  portal_ptr->getIoService().stop();
+}
+
+ProducerSocket &HTTPServerPublisher::getProducer() { return *producer_; }
+
+void HTTPServerPublisher::setPublisherName(std::string &name,
+                                           std::string &mask) {
+  // Name represents the last 64 bits of the ipv6 address.
+  // It is an ipv6 address with the first 64 bits set to 0
+  uint16_t i;
+  std::string s = content_name_.toString();
+  std::shared_ptr<core::Sockaddr> sockaddr = content_name_.getAddress();
+  in6_addr name_ipv6 = ((core::Sockaddr6 *)sockaddr.get())->sin6_addr;
+
+  in6_addr bitmask, new_address, _name;
+
+  if (inet_pton(AF_INET6, mask.c_str(), &bitmask) != 1) {
+    throw errors::RuntimeException("Error during conversion to ipv6 address.");
+  }
+
+  if (inet_pton(AF_INET6, name.c_str(), &_name) != 1) {
+    throw errors::RuntimeException("Error during conversion to ipv6 address.");
+  }
+
+  for (i = 0; i < sizeof(new_address.s6_addr); i++) {
+    new_address.s6_addr[i] = name_ipv6.s6_addr[i] & bitmask.s6_addr[i];
+  }
+
+  for (i = 0; i < sizeof(new_address.s6_addr); i++) {
+    new_address.s6_addr[i] |= _name.s6_addr[i] & ~bitmask.s6_addr[i];
+  }
+
+  // Effectively change the name
+  char str[INET6_ADDRSTRLEN];
+  inet_ntop(AF_INET6, &new_address, str, INET6_ADDRSTRLEN);
+  std::string str2(str);
+
+  core::Name new_name(str2, 0);
+
+  // If the new name differs from the one required by the consumer part, send a
+  // manifest
+  if (!new_name.equals(content_name_, false)) {
+    // Publish manifest pointing to the new name
+
+    auto manifest =
+        std::make_shared<ContentObjectManifest>(content_name_.setSuffix(0));
+
+    content_name_ = core::Name(str2, 0);
+
+    //    manifest->setNameList(content_name_);
+    manifest->setLifetime(4000 * 1000);
+    manifest->encode();
+    producer_->produce(*manifest);
+
+    core::Prefix ns(content_name_, 128);
+    producer_->registerPrefix(ns);
+  }
+}
+
+}  // namespace http
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/http/server_publisher.h b/libtransport/src/hicn/transport/http/server_publisher.h
new file mode 100755 (executable)
index 0000000..91f7e43
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/http/default_values.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+
+#include <functional>
+#include <vector>
+
+namespace transport {
+
+namespace http {
+
+using namespace interface;
+using namespace core;
+
+class HTTPServerPublisher {
+ public:
+  HTTPServerPublisher(const core::Name &content_name);
+
+  ~HTTPServerPublisher();
+
+  void publishContent(const uint8_t *buf, size_t buffer_size,
+                      std::chrono::milliseconds content_lifetime, bool is_last);
+
+  template <typename Handler>
+  void asyncPublishContent(const uint8_t *buf, size_t buffer_size,
+                           std::chrono::milliseconds content_lifetime,
+                           Handler &&handler, bool is_last);
+
+  void serveClients();
+
+  void stop();
+
+  ProducerSocket &getProducer();
+
+  HTTPServerPublisher &setTimeout(const std::chrono::milliseconds &timeout,
+                                  bool timeout_renewal);
+
+  HTTPServerPublisher &attachPublisher();
+
+  void setPublisherName(std::string &name, std::string &mask);
+
+ private:
+  Name content_name_;
+  std::unique_ptr<asio::steady_timer> timer_;
+  asio::io_service io_service_;
+  std::unique_ptr<ProducerSocket> producer_;
+  ProducerInterestCallback interest_enter_callback_;
+  utils::UserCallback wait_callback_;
+
+  utils::SharableVector<uint8_t> receive_buffer_;
+};
+
+}  // end namespace http
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/CMakeLists.txt b/libtransport/src/hicn/transport/interfaces/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..cbf371b
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_consumer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/async_transport.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/full_duplex_socket.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/publication_options.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_default_values.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_options_keys.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/full_duplex_socket.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_consumer.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_socket_producer.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_producer.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/socket_consumer.cc
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/async_transport.h b/libtransport/src/hicn/transport/interfaces/async_transport.h
new file mode 100755 (executable)
index 0000000..492b4ec
--- /dev/null
@@ -0,0 +1,640 @@
+
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/publication_options.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <sys/uio.h>
+#include <memory>
+
+namespace transport {
+
+namespace interface {
+
+/*
+ * flags given by the application for write* calls
+ */
+enum class WriteFlags : uint32_t {
+  NONE = 0x00,
+  /*
+   * Whether to delay the output until a subsequent non-corked write.
+   * (Note: may not be supported in all subclasses or on all platforms.)
+   */
+  CORK = 0x01,
+  /*
+   * for a socket that has ACK latency enabled, it will cause the kernel
+   * to fire a TCP ESTATS event when the last byte of the given write call
+   * will be acknowledged.
+   */
+  EOR = 0x02,
+  /*
+   * this indicates that only the write side of socket should be shutdown
+   */
+  WRITE_SHUTDOWN = 0x04,
+  /*
+   * use msg zerocopy if allowed
+   */
+  WRITE_MSG_ZEROCOPY = 0x08,
+};
+
+/*
+ * union operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator|(WriteFlags a, WriteFlags b) {
+  return static_cast<WriteFlags>(static_cast<uint32_t>(a) |
+                                 static_cast<uint32_t>(b));
+}
+
+/*
+ * compound assignment union operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags &operator|=(WriteFlags &a, WriteFlags b) {
+  a = a | b;
+  return a;
+}
+
+/*
+ * intersection operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator&(WriteFlags a, WriteFlags b) {
+  return static_cast<WriteFlags>(static_cast<uint32_t>(a) &
+                                 static_cast<uint32_t>(b));
+}
+
+/*
+ * compound assignment intersection operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags &operator&=(WriteFlags &a, WriteFlags b) {
+  a = a & b;
+  return a;
+}
+
+/*
+ * exclusion parameter
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags operator~(WriteFlags a) {
+  return static_cast<WriteFlags>(~static_cast<uint32_t>(a));
+}
+
+/*
+ * unset operator
+ */
+TRANSPORT_ALWAYS_INLINE WriteFlags unSet(WriteFlags a, WriteFlags b) {
+  return a & ~b;
+}
+
+/*
+ * inclusion operator
+ */
+TRANSPORT_ALWAYS_INLINE bool isSet(WriteFlags a, WriteFlags b) {
+  return (a & b) == b;
+}
+
+class ConnectCallback {
+ public:
+  virtual ~ConnectCallback() = default;
+
+  /**
+   * connectSuccess() will be invoked when the connection has been
+   * successfully established.
+   */
+  virtual void connectSuccess() noexcept = 0;
+
+  /**
+   * connectErr() will be invoked if the connection attempt fails.
+   *
+   * @param ex        An exception describing the error that occurred.
+   */
+  virtual void connectErr(const std::error_code ec) noexcept = 0;
+};
+
+/**
+ * AsyncSocket defines an asynchronous API for streaming I/O.
+ *
+ * This class provides an API to for asynchronously waiting for data
+ * on a streaming transport, and for asynchronously sending data.
+ *
+ * The APIs for reading and writing are intentionally asymmetric.  Waiting for
+ * data to read is a persistent API: a callback is installed, and is notified
+ * whenever new data is available.  It continues to be notified of new events
+ * until it is uninstalled.
+ *
+ * AsyncSocket does not provide read timeout functionality, because it
+ * typically cannot determine when the timeout should be active.  Generally, a
+ * timeout should only be enabled when processing is blocked waiting on data
+ * from the remote endpoint.  For server-side applications, the timeout should
+ * not be active if the server is currently processing one or more outstanding
+ * requests on this transport.  For client-side applications, the timeout
+ * should not be active if there are no requests pending on the transport.
+ * Additionally, if a client has multiple pending requests, it will ususally
+ * want a separate timeout for each request, rather than a single read timeout.
+ *
+ * The write API is fairly intuitive: a user can request to send a block of
+ * data, and a callback will be informed once the entire block has been
+ * transferred to the kernel, or on error.  AsyncSocket does provide a send
+ * timeout, since most callers want to give up if the remote end stops
+ * responding and no further progress can be made sending the data.
+ */
+class AsyncSocket {
+ public:
+  /**
+   * Close the transport.
+   *
+   * This gracefully closes the transport, waiting for all pending write
+   * requests to complete before actually closing the underlying transport.
+   *
+   * If a read callback is set, readEOF() will be called immediately.  If there
+   * are outstanding write requests, the close will be delayed until all
+   * remaining writes have completed.  No new writes may be started after
+   * close() has been called.
+   */
+  virtual void close() = 0;
+
+  /**
+   * Close the transport immediately.
+   *
+   * This closes the transport immediately, dropping any outstanding data
+   * waiting to be written.
+   *
+   * If a read callback is set, readEOF() will be called immediately.
+   * If there are outstanding write requests, these requests will be aborted
+   * and writeError() will be invoked immediately on all outstanding write
+   * callbacks.
+   */
+  virtual void closeNow() = 0;
+
+  /**
+   * Perform a half-shutdown of the write side of the transport.
+   *
+   * The caller should not make any more calls to write() or writev() after
+   * shutdownWrite() is called.  Any future write attempts will fail
+   * immediately.
+   *
+   * Not all transport types support half-shutdown.  If the underlying
+   * transport does not support half-shutdown, it will fully shutdown both the
+   * read and write sides of the transport.  (Fully shutting down the socket is
+   * better than doing nothing at all, since the caller may rely on the
+   * shutdownWrite() call to notify the other end of the connection that no
+   * more data can be read.)
+   *
+   * If there is pending data still waiting to be written on the transport,
+   * the actual shutdown will be delayed until the pending data has been
+   * written.
+   *
+   * Note: There is no corresponding shutdownRead() equivalent.  Simply
+   * uninstall the read callback if you wish to stop reading.  (On TCP sockets
+   * at least, shutting down the read side of the socket is a no-op anyway.)
+   */
+  virtual void shutdownWrite() = 0;
+
+  /**
+   * Perform a half-shutdown of the write side of the transport.
+   *
+   * shutdownWriteNow() is identical to shutdownWrite(), except that it
+   * immediately performs the shutdown, rather than waiting for pending writes
+   * to complete.  Any pending write requests will be immediately failed when
+   * shutdownWriteNow() is called.
+   */
+  virtual void shutdownWriteNow() = 0;
+
+  /**
+   * Determine if transport is open and ready to read or write.
+   *
+   * Note that this function returns false on EOF; you must also call error()
+   * to distinguish between an EOF and an error.
+   *
+   * @return  true iff the transport is open and ready, false otherwise.
+   */
+  virtual bool good() const = 0;
+
+  /**
+   * Determine if the transport is readable or not.
+   *
+   * @return  true iff the transport is readable, false otherwise.
+   */
+  virtual bool readable() const = 0;
+
+  /**
+   * Determine if the transport is writable or not.
+   *
+   * @return  true iff the transport is writable, false otherwise.
+   */
+  virtual bool writable() const {
+    // By default return good() - leave it to implementers to override.
+    return good();
+  }
+
+  /**
+   * Determine if the there is pending data on the transport.
+   *
+   * @return  true iff the if the there is pending data, false otherwise.
+   */
+  virtual bool isPending() const { return readable(); }
+
+  /**
+   * Determine if transport is connected to the endpoint
+   *
+   * @return  false iff the transport is connected, otherwise true
+   */
+  virtual bool connected() const = 0;
+
+  /**
+   * Determine if an error has occurred with this transport.
+   *
+   * @return  true iff an error has occurred (not EOF).
+   */
+  virtual bool error() const = 0;
+
+  // /**
+  //  * Attach the transport to a EventBase.
+  //  *
+  //  * This may only be called if the transport is not currently attached to a
+  //  * EventBase (by an earlier call to detachEventBase()).
+  //  *
+  //  * This method must be invoked in the EventBase's thread.
+  //  */
+  // virtual void attachEventBase(EventBase* eventBase) = 0;
+
+  // /**
+  //  * Detach the transport from its EventBase.
+  //  *
+  //  * This may only be called when the transport is idle and has no reads or
+  //  * writes pending.  Once detached, the transport may not be used again
+  //  until
+  //  * it is re-attached to a EventBase by calling attachEventBase().
+  //  *
+  //  * This method must be called from the current EventBase's thread.
+  //  */
+  // virtual void detachEventBase() = 0;
+
+  // /**
+  //  * Determine if the transport can be detached.
+  //  *
+  //  * This method must be called from the current EventBase's thread.
+  //  */
+  // virtual bool isDetachable() const = 0;
+
+  /**
+   * Set the send timeout.
+   *
+   * If write requests do not make any progress for more than the specified
+   * number of milliseconds, fail all pending writes and close the transport.
+   *
+   * If write requests are currently pending when setSendTimeout() is called,
+   * the timeout interval is immediately restarted using the new value.
+   *
+   * @param milliseconds  The timeout duration, in milliseconds.  If 0, no
+   *                      timeout will be used.
+   */
+  virtual void setSendTimeout(uint32_t milliseconds) = 0;
+
+  /**
+   * Get the send timeout.
+   *
+   * @return Returns the current send timeout, in milliseconds.  A return value
+   *         of 0 indicates that no timeout is set.
+   */
+  virtual uint32_t getSendTimeout() const = 0;
+
+  virtual void connect(ConnectCallback *callback,
+                       const core::Prefix &prefix_) = 0;
+
+  // /**
+  //  * Get the address of the local endpoint of this transport.
+  //  *
+  //  * This function may throw AsyncSocketException on error.
+  //  *
+  //  * @param address  The local address will be stored in the specified
+  //  *                 SocketAddress.
+  //  */
+  // virtual void getLocalAddress(* address) const = 0;
+
+  virtual size_t getAppBytesWritten() const = 0;
+  virtual size_t getRawBytesWritten() const = 0;
+  virtual size_t getAppBytesReceived() const = 0;
+  virtual size_t getRawBytesReceived() const = 0;
+
+  class BufferCallback {
+   public:
+    virtual ~BufferCallback() {}
+    virtual void onEgressBuffered() = 0;
+    virtual void onEgressBufferCleared() = 0;
+  };
+
+  ~AsyncSocket() = default;
+};
+
+class AsyncAcceptor {
+ public:
+  class AcceptCallback {
+   public:
+    virtual ~AcceptCallback() = default;
+
+    /**
+     * connectionAccepted() is called whenever a new client connection is
+     * received.
+     *
+     * The AcceptCallback will remain installed after connectionAccepted()
+     * returns.
+     *
+     * @param fd          The newly accepted client socket.  The AcceptCallback
+     *                    assumes ownership of this socket, and is responsible
+     *                    for closing it when done.  The newly accepted file
+     *                    descriptor will have already been put into
+     *                    non-blocking mode.
+     * @param clientAddr  A reference to a SocketAddress struct containing the
+     *                    client's address.  This struct is only guaranteed to
+     *                    remain valid until connectionAccepted() returns.
+     */
+    virtual void connectionAccepted(
+        const core::Name &subscriber_name) noexcept = 0;
+
+    /**
+     * acceptError() is called if an error occurs while accepting.
+     *
+     * The AcceptCallback will remain installed even after an accept error,
+     * as the errors are typically somewhat transient, such as being out of
+     * file descriptors.  The server socket must be explicitly stopped if you
+     * wish to stop accepting after an error.
+     *
+     * @param ex  An exception representing the error.
+     */
+    virtual void acceptError(const std::exception &ex) noexcept = 0;
+
+    /**
+     * acceptStarted() will be called in the callback's EventBase thread
+     * after this callback has been added to the AsyncServerSocket.
+     *
+     * acceptStarted() will be called before any calls to connectionAccepted()
+     * or acceptError() are made on this callback.
+     *
+     * acceptStarted() makes it easier for callbacks to perform initialization
+     * inside the callback thread.  (The call to addAcceptCallback() must
+     * always be made from the AsyncServerSocket's primary EventBase thread.
+     * acceptStarted() provides a hook that will always be invoked in the
+     * callback's thread.)
+     *
+     * Note that the call to acceptStarted() is made once the callback is
+     * added, regardless of whether or not the AsyncServerSocket is actually
+     * accepting at the moment.  acceptStarted() will be called even if the
+     * AsyncServerSocket is paused when the callback is added (including if
+     * the initial call to startAccepting() on the AsyncServerSocket has not
+     * been made yet).
+     */
+    virtual void acceptStarted() noexcept {}
+
+    /**
+     * acceptStopped() will be called when this AcceptCallback is removed from
+     * the AsyncServerSocket, or when the AsyncServerSocket is destroyed,
+     * whichever occurs first.
+     *
+     * No more calls to connectionAccepted() or acceptError() will be made
+     * after acceptStopped() is invoked.
+     */
+    virtual void acceptStopped() noexcept {}
+  };
+
+  /**
+   * Wait for subscribers
+   *
+   */
+  virtual void waitForSubscribers(AcceptCallback *cb) = 0;
+};
+
+class AsyncReader {
+ public:
+  class ReadCallback {
+   public:
+    virtual ~ReadCallback() = default;
+
+    /**
+     * When data becomes available, getReadBuffer() will be invoked to get the
+     * buffer into which data should be read.
+     *
+     * This method allows the ReadCallback to delay buffer allocation until
+     * data becomes available.  This allows applications to manage large
+     * numbers of idle connections, without having to maintain a separate read
+     * buffer for each idle connection.
+     *
+     * It is possible that in some cases, getReadBuffer() may be called
+     * multiple times before readDataAvailable() is invoked.  In this case, the
+     * data will be written to the buffer returned from the most recent call to
+     * readDataAvailable().  If the previous calls to readDataAvailable()
+     * returned different buffers, the ReadCallback is responsible for ensuring
+     * that they are not leaked.
+     *
+     * If getReadBuffer() throws an exception, returns a nullptr buffer, or
+     * returns a 0 length, the ReadCallback will be uninstalled and its
+     * readError() method will be invoked.
+     *
+     * getReadBuffer() is not allowed to change the transport state before it
+     * returns.  (For example, it should never uninstall the read callback, or
+     * set a different read callback.)
+     *
+     * @param bufReturn getReadBuffer() should update *bufReturn to contain the
+     *                  address of the read buffer.  This parameter will never
+     *                  be nullptr.
+     * @param lenReturn getReadBuffer() should update *lenReturn to contain the
+     *                  maximum number of bytes that may be written to the read
+     *                  buffer.  This parameter will never be nullptr.
+     *
+     *
+     * XXX TODO this does not seems to be completely true Checlk i/.
+     */
+    virtual void getReadBuffer(void **bufReturn, size_t *lenReturn) = 0;
+
+    /**
+     * readDataAvailable() will be invoked when data has been successfully read
+     * into the buffer returned by the last call to getReadBuffer().
+     *
+     * The read callback remains installed after readDataAvailable() returns.
+     * It must be explicitly uninstalled to stop receiving read events.
+     * getReadBuffer() will be called at least once before each call to
+     * readDataAvailable().  getReadBuffer() will also be called before any
+     * call to readEOF().
+     *
+     * @param len       The number of bytes placed in the buffer.
+     */
+
+    virtual void readDataAvailable(size_t len) noexcept = 0;
+
+    /**
+     * When data becomes available, isBufferMovable() will be invoked to figure
+     * out which API will be used, readBufferAvailable() or
+     * readDataAvailable(). If isBufferMovable() returns true, that means
+     * ReadCallback supports the IOBuf ownership transfer and
+     * readBufferAvailable() will be used.  Otherwise, not.
+
+     * By default, isBufferMovable() always return false. If
+     * readBufferAvailable() is implemented and to be invoked, You should
+     * overwrite isBufferMovable() and return true in the inherited class.
+     *
+     * This method allows the AsyncSocket/AsyncSSLSocket do buffer allocation by
+     * itself until data becomes available.  Compared with the pre/post buffer
+     * allocation in getReadBuffer()/readDataAvailabe(), readBufferAvailable()
+     * has two advantages.  First, this can avoid memcpy. E.g., in
+     * AsyncSSLSocket, the decrypted data was copied from the openssl internal
+     * buffer to the readbuf buffer.  With the buffer ownership transfer, the
+     * internal buffer can be directly "moved" to ReadCallback. Second, the
+     * memory allocation can be more precise.  The reason is
+     * AsyncSocket/AsyncSSLSocket can allocate the memory of precise size
+     * because they have more context about the available data than
+     * ReadCallback.  Think about the getReadBuffer() pre-allocate 4072 bytes
+     * buffer, but the available data is always 16KB (max OpenSSL record size).
+     */
+
+    virtual bool isBufferMovable() noexcept { return false; }
+
+    /**
+     * Suggested buffer size, allocated for read operations,
+     * if callback is movable and supports folly::IOBuf
+     */
+
+    virtual size_t maxBufferSize() const {
+      return 64 * 1024;  // 64K
+    }
+
+    /**
+     * readBufferAvailable() will be invoked when data has been successfully
+     * read.
+     *
+     * Note that only either readBufferAvailable() or readDataAvailable() will
+     * be invoked according to the return value of isBufferMovable(). The timing
+     * and aftereffect of readBufferAvailable() are the same as
+     * readDataAvailable()
+     *
+     * @param readBuf The unique pointer of read buffer.
+     */
+
+    // virtual void readBufferAvailable(uint8_t** buffer, std::size_t
+    // *buf_length) noexcept {}
+
+    virtual void readBufferAvailable(
+        utils::SharableVector<uint8_t> &&buffer) noexcept {}
+
+    // virtual void readBufferAvailable(utils::SharableBuffer<uint8_t>&& buffer)
+    // noexcept {}
+
+    /**
+     * readEOF() will be invoked when the transport is closed.
+     *
+     * The read callback will be automatically uninstalled immediately before
+     * readEOF() is invoked.
+     */
+    virtual void readEOF() noexcept = 0;
+
+    /**
+     * readError() will be invoked if an error occurs reading from the
+     * transport.
+     *
+     * The read callback will be automatically uninstalled immediately before
+     * readError() is invoked.
+     *
+     * @param ex        An exception describing the error that occurred.
+     */
+    virtual void readErr(const std::error_code ec) noexcept = 0;
+  };
+
+  // Read methods that aren't part of AsyncTransport.
+  virtual void setReadCB(ReadCallback *callback) = 0;
+  virtual ReadCallback *getReadCallback() const = 0;
+
+ protected:
+  virtual ~AsyncReader() = default;
+};
+
+class AsyncWriter {
+ public:
+  class WriteCallback {
+   public:
+    virtual ~WriteCallback() = default;
+
+    /**
+     * writeSuccess() will be invoked when all of the data has been
+     * successfully written.
+     *
+     * Note that this mainly signals that the buffer containing the data to
+     * write is no longer needed and may be freed or re-used.  It does not
+     * guarantee that the data has been fully transmitted to the remote
+     * endpoint.  For example, on socket-based transports, writeSuccess() only
+     * indicates that the data has been given to the kernel for eventual
+     * transmission.
+     */
+    virtual void writeSuccess() noexcept = 0;
+
+    /**
+     * writeError() will be invoked if an error occurs writing the data.
+     *
+     * @param bytesWritten      The number of bytes that were successfull
+     * @param ex                An exception describing the error that occurred.
+     */
+    virtual void writeErr(size_t bytesWritten) noexcept = 0;
+  };
+
+  /**
+   * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+   * or writeErr() will be invoked when the write completes. If you supply
+   * the same WriteCallback object for multiple write() calls, it will be
+   * invoked exactly once per call. The only way to cancel outstanding
+   * write requests is to close the socket (e.g., with closeNow() or
+   * shutdownWriteNow()). When closing the socket this way, writeErr() will
+   * still be invoked once for each outstanding write operation.
+   */
+  virtual void write(WriteCallback *callback, const void *buf, size_t bytes,
+                     const PublicationOptions &options,
+                     WriteFlags flags = WriteFlags::NONE) = 0;
+
+  /**
+   * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+   * or writeErr() will be invoked when the write completes. If you supply
+   * the same WriteCallback object for multiple write() calls, it will be
+   * invoked exactly once per call. The only way to cancel outstanding
+   * write requests is to close the socket (e.g., with closeNow() or
+   * shutdownWriteNow()). When closing the socket this way, writeErr() will
+   * still be invoked once for each outstanding write operation.
+   */
+  virtual void write(WriteCallback *callback,
+                     utils::SharableVector<uint8_t> &&output_buffer,
+                     const PublicationOptions &options,
+                     WriteFlags flags = WriteFlags::NONE) = 0;
+
+  // /**
+  //  * If you supply a non-null WriteCallback, exactly one of writeSuccess()
+  //  * or writeErr() will be invoked when the write completes. If you supply
+  //  * the same WriteCallback object for multiple write() calls, it will be
+  //  * invoked exactly once per call. The only way to cancel outstanding
+  //  * write requests is to close the socket (e.g., with closeNow() or
+  //  * shutdownWriteNow()). When closing the socket this way, writeErr() will
+  //  * still be invoked once for each outstanding write operation.
+  //  */
+  // virtual void writeChain(
+  //     WriteCallback* callback,
+  //     std::unique_ptr<IOBuf>&& buf,
+  //     WriteFlags flags = WriteFlags::NONE) = 0;
+
+  virtual void setWriteCB(WriteCallback *callback) = 0;
+  virtual WriteCallback *getWriteCallback() const = 0;
+
+ protected:
+  virtual ~AsyncWriter() = default;
+};
+
+}  // namespace interface
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.cc
new file mode 100755 (executable)
index 0000000..7b63422
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/full_duplex_socket.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <memory>
+
+namespace transport {
+
+namespace interface {
+
+static const std::string producer_identity = "producer_socket";
+
+AsyncFullDuplexSocket::AsyncFullDuplexSocket(const Prefix &locator)
+    : AsyncFullDuplexSocket(locator, internal_io_service_) {}
+
+AsyncFullDuplexSocket::AsyncFullDuplexSocket(const Prefix &locator,
+                                             asio::io_service &io_service)
+    : locator_(locator),
+      incremental_suffix_(0),
+      io_service_(io_service),
+      work_(io_service),
+      producer_(std::make_unique<ProducerSocket>(io_service_)),
+      consumer_(std::make_unique<ConsumerSocket>(
+          TransportProtocolAlgorithms::RAAQM /* , io_service_ */)),
+      read_callback_(nullptr),
+      write_callback_(nullptr),
+      connect_callback_(nullptr),
+      accept_callback_(nullptr),
+      internal_connect_callback_(new OnConnectCallback(*this)),
+      internal_signal_callback_(new OnSignalCallback(*this)),
+      send_timeout_milliseconds_(~0),
+      counters_({0}),
+      receive_buffer_(std::make_shared<utils::SharableVector<uint8_t>>()) {
+  using namespace transport;
+  using namespace std::placeholders;
+  producer_->registerPrefix(locator);
+
+  producer_->setSocketOption(
+      ProducerCallbacksOptions::CACHE_MISS,
+      std::bind(&AsyncFullDuplexSocket::onControlInterest, this, _1, _2));
+
+  producer_->setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE,
+                             uint32_t{150000});
+
+  producer_->setSocketOption(
+      ProducerCallbacksOptions::CONTENT_PRODUCED,
+      std::bind(&AsyncFullDuplexSocket::onContentProduced, this, _1, _2, _3));
+
+  producer_->connect();
+
+  consumer_->setSocketOption(ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY,
+                             (ConsumerContentObjectVerificationCallback)[](
+                                 ConsumerSocket & s, const ContentObject &c)
+                                 ->bool { return true; });
+
+  consumer_->setSocketOption(
+      ConsumerCallbacksOptions::CONTENT_RETRIEVED,
+      std::bind(&AsyncFullDuplexSocket::onContentRetrieved, this, _1, _2, _3));
+
+  consumer_->setSocketOption(GeneralTransportOptions::MAX_INTEREST_RETX,
+                             uint32_t{4});
+
+  consumer_->connect();
+}
+
+void AsyncFullDuplexSocket::close() {
+  this->consumer_->stop();
+  this->producer_->stop();
+}
+
+void AsyncFullDuplexSocket::closeNow() { close(); }
+
+void AsyncFullDuplexSocket::shutdownWrite() { producer_->stop(); }
+
+void AsyncFullDuplexSocket::shutdownWriteNow() { shutdownWrite(); }
+
+bool AsyncFullDuplexSocket::good() const { return true; }
+
+bool AsyncFullDuplexSocket::readable() const {
+  // TODO return status of consumer socket
+  return true;
+}
+
+bool AsyncFullDuplexSocket::writable() const {
+  // TODO return status of producer socket
+  return true;
+}
+
+bool AsyncFullDuplexSocket::isPending() const {
+  // TODO save if there are production operation in the ops queue
+  // in producer socket
+  return true;
+}
+
+bool AsyncFullDuplexSocket::connected() const {
+  // No real connection here (ICN world). Return good
+  return good();
+}
+
+bool AsyncFullDuplexSocket::error() const { return !good(); }
+
+void AsyncFullDuplexSocket::setSendTimeout(uint32_t milliseconds) {
+  // TODO if production takes too much to complete
+  // let's abort the operation.
+
+  // Normally with hicn this should be done for content
+  // pull, not for production.
+
+  send_timeout_milliseconds_ = milliseconds;
+}
+
+uint32_t AsyncFullDuplexSocket::getSendTimeout() const {
+  return send_timeout_milliseconds_;
+}
+
+size_t AsyncFullDuplexSocket::getAppBytesWritten() const {
+  return counters_.app_bytes_written_;
+}
+
+size_t AsyncFullDuplexSocket::getRawBytesWritten() const { return 0; }
+
+size_t AsyncFullDuplexSocket::getAppBytesReceived() const {
+  return counters_.app_bytes_read_;
+}
+
+size_t AsyncFullDuplexSocket::getRawBytesReceived() const { return 0; }
+
+void AsyncFullDuplexSocket::connect(ConnectCallback *callback,
+                                    const core::Prefix &prefix) {
+  connect_callback_ = callback;
+
+  // Create an interest for a subscription
+  auto interest =
+      core::Interest::Ptr(new core::Interest(prefix.makeRandomName()));
+  auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+  _payload->append(sizeof(ActionMessage));
+  auto payload = _payload->writableData();
+  ActionMessage *subscription_message =
+      reinterpret_cast<ActionMessage *>(payload);
+  subscription_message->header.msg_type = MessageType::ACTION;
+  subscription_message->action = Action::SUBSCRIBE;
+  subscription_message->header.reserved[0] = 0;
+  subscription_message->header.reserved[1] = 0;
+
+  // Set the name the other part should use for notifying a content production
+  sync_notification_ = std::move(locator_.makeRandomName());
+  sync_notification_.copyToDestination(
+      reinterpret_cast<uint8_t *>(subscription_message->name));
+
+  TRANSPORT_LOGI(
+      "Trying to connect. Sending interest: %s, name for notifications: %s",
+      prefix.getName().toString().c_str(),
+      sync_notification_.toString().c_str());
+
+  interest->setLifetime(1000);
+  interest->appendPayload(std::move(_payload));
+  consumer_->asyncSendInterest(std::move(interest),
+                               internal_connect_callback_.get());
+}
+
+void AsyncFullDuplexSocket::write(WriteCallback *callback, const void *buf,
+                                  size_t bytes,
+                                  const PublicationOptions &options,
+                                  WriteFlags flags) {
+  using namespace transport;
+
+  // 1 asynchronously write the content. I assume here the
+  // buffer contains the whole application frame. FIXME: check
+  // if this is true and fix it accordingly
+  std::cout << "Size of the PAYLOAD: " << bytes << std::endl;
+
+  if (bytes > core::Packet::default_mtu - sizeof(PayloadMessage)) {
+    TRANSPORT_LOGI("Producing content with name %s",
+                   options.name.toString().c_str());
+    producer_->asyncProduce(options.name,
+                            reinterpret_cast<const uint8_t *>(buf), bytes);
+    signalProductionToSubscribers(options.name);
+  } else {
+    TRANSPORT_LOGI("Sending payload through interest");
+    piggybackPayloadToSubscribers(
+        options.name, reinterpret_cast<const uint8_t *>(buf), bytes);
+  }
+}
+
+void AsyncFullDuplexSocket::write(
+    WriteCallback *callback, utils::SharableVector<uint8_t> &&output_buffer,
+    const PublicationOptions &options, WriteFlags flags) {
+  using namespace transport;
+
+  // 1 asynchronously write the content. I assume here the
+  // buffer contains the whole application frame. FIXME: check
+  // if this is true and fix it accordingly
+  std::cout << "Size of the PAYLOAD: " << output_buffer.size() << std::endl;
+
+  if (output_buffer.size() >
+      core::Packet::default_mtu - sizeof(PayloadMessage)) {
+    TRANSPORT_LOGI("Producing content with name %s",
+                   options.name.toString().c_str());
+    producer_->asyncProduce(options.name, std::move(output_buffer));
+    signalProductionToSubscribers(options.name);
+  } else {
+    TRANSPORT_LOGI("Sending payload through interest");
+    piggybackPayloadToSubscribers(options.name, &output_buffer[0],
+                                  output_buffer.size());
+  }
+}
+
+void AsyncFullDuplexSocket::piggybackPayloadToSubscribers(
+    const core::Name &name, const uint8_t *buffer, std::size_t bytes) {
+  for (auto &sub : subscribers_) {
+    auto interest = core::Interest::Ptr(new core::Interest(name));
+    auto _payload = utils::MemBuf::create(bytes + sizeof(PayloadMessage));
+    _payload->append(bytes + sizeof(PayloadMessage));
+    auto payload = _payload->writableData();
+
+    PayloadMessage *interest_payload =
+        reinterpret_cast<PayloadMessage *>(payload);
+    interest_payload->header.msg_type = MessageType::PAYLOAD;
+    interest_payload->header.reserved[0] = 0;
+    interest_payload->header.reserved[1] = 0;
+    interest_payload->reserved[0] = 0;
+    std::memcpy(payload + sizeof(PayloadMessage), buffer, bytes);
+    interest->appendPayload(std::move(_payload));
+
+    // Set the timeout of 0.2 second
+    interest->setLifetime(1000);
+    interest->setName(sub);
+    interest->getWritableName().setSuffix(incremental_suffix_++);
+    // TRANSPORT_LOGI("Sending signalization to %s",
+    // interest->getName().toString().c_str());
+
+    consumer_->asyncSendInterest(std::move(interest),
+                                 internal_signal_callback_.get());
+  }
+}
+
+void AsyncFullDuplexSocket::signalProductionToSubscribers(
+    const core::Name &name) {
+  // Signal the other part we are producing a content
+  // Create an interest for a subscription
+
+  for (auto &sub : subscribers_) {
+    auto interest = core::Interest::Ptr(new core::Interest(name));
+    // Todo consider using preallocated pool of membufs
+    auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+    _payload->append(sizeof(ActionMessage));
+    auto payload = const_cast<uint8_t *>(interest->getPayload().data());
+
+    ActionMessage *produce_notification =
+        reinterpret_cast<ActionMessage *>(payload);
+    produce_notification->header.msg_type = MessageType::ACTION;
+    produce_notification->action = Action::SIGNAL_PRODUCTION;
+    produce_notification->header.reserved[0] = 0;
+    produce_notification->header.reserved[1] = 0;
+    name.copyToDestination(
+        reinterpret_cast<uint8_t *>(produce_notification->name));
+    interest->appendPayload(std::move(_payload));
+
+    // Set the timeout of 0.2 second
+    interest->setLifetime(1000);
+    interest->setName(sub);
+    interest->getWritableName().setSuffix(incremental_suffix_++);
+    // TRANSPORT_LOGI("Sending signalization to %s",
+    // interest->getName().toString().c_str());
+
+    consumer_->asyncSendInterest(std::move(interest),
+                                 internal_signal_callback_.get());
+  }
+}
+
+void AsyncFullDuplexSocket::waitForSubscribers(AcceptCallback *cb) {
+  accept_callback_ = cb;
+}
+
+std::shared_ptr<core::ContentObject>
+AsyncFullDuplexSocket::decodeSynchronizationMessage(
+    const core::Interest &interest) {
+  auto mesg = interest.getPayload();
+  const MessageHeader *header =
+      reinterpret_cast<const MessageHeader *>(mesg.data());
+
+  switch (header->msg_type) {
+    case MessageType::ACTION: {
+      // Check what is the action to perform
+      const ActionMessage *message =
+          reinterpret_cast<const ActionMessage *>(header);
+
+      if (message->action == Action::SUBSCRIBE) {
+        // Add consumer to list on consumers to be notified
+        auto ret =
+            subscribers_.emplace(AF_INET6, (const uint8_t *)message->name, 0);
+        TRANSPORT_LOGI("Added subscriber %s :)", ret.first->toString().c_str());
+        if (ret.second) {
+          accept_callback_->connectionAccepted(*ret.first);
+        }
+
+        TRANSPORT_LOGI("Connection success!");
+
+        sync_notification_ = std::move(locator_.makeRandomName());
+        return createSubscriptionResponse(sync_notification_);
+
+      } else if (message->action == Action::CANCEL_SUBSCRIPTION) {
+        // XXX Modify name!!! Each allocated name allocates a 128 bit array.
+        subscribers_.erase(
+            core::Name(AF_INET6, (const uint8_t *)message->name, 0));
+        return createAck();
+      } else if (message->action == Action::SIGNAL_PRODUCTION) {
+        // trigger a reverse pull for the name contained in the message
+        core::Name n(AF_INET6, (const uint8_t *)message->name, 0);
+        std::cout << "PROD NOTIFICATION: Content to retrieve: " << n
+                  << std::endl;
+        std::cout << "PROD NOTIFICATION: Interest name: " << interest.getName()
+                  << std::endl;  // << " compared to " << sync_notification_ <<
+                                 // std::endl;
+
+        if (sync_notification_.equals(interest.getName(), false)) {
+          std::cout << "Starting reverse pull for " << n << std::endl;
+          consumer_->asyncConsume(n, receive_buffer_);
+          return createAck();
+        }
+      } else {
+        TRANSPORT_LOGE("Received unknown message. Dropping it.");
+      }
+
+      break;
+    }
+    case MessageType::RESPONSE: {
+      throw errors::RuntimeException(
+          "The response should be a content object!!");
+    }
+    case MessageType::PAYLOAD: {
+      // The interest contains the payload directly.
+      // We saved one round trip :)
+
+      auto buffer = std::make_shared<utils::SharableVector<uint8_t>>();
+      const uint8_t *data = mesg.data() + sizeof(PayloadMessage);
+      buffer->assign(data, data + mesg.length() - sizeof(PayloadMessage));
+      read_callback_->readBufferAvailable(std::move(*buffer));
+      return createAck();
+    }
+    default: {
+      return std::shared_ptr<core::ContentObject>(nullptr);
+    }
+  }
+
+  return std::shared_ptr<core::ContentObject>(nullptr);
+}
+
+void AsyncFullDuplexSocket::onControlInterest(ProducerSocket &s,
+                                              const core::Interest &i) {
+  auto payload = i.getPayload();
+  if (payload.length()) {
+    // Try to decode payload and see if starting an async pull operation
+    auto response = decodeSynchronizationMessage(i);
+    if (response) {
+      response->setName(i.getName());
+      s.produce(*response);
+    }
+  }
+}
+
+void AsyncFullDuplexSocket::onContentProduced(ProducerSocket &producer,
+                                              const std::error_code &ec,
+                                              uint64_t bytes_written) {
+  if (write_callback_) {
+    if (!ec) {
+      write_callback_->writeSuccess();
+    } else {
+      write_callback_->writeErr(bytes_written);
+    }
+  }
+}
+
+void AsyncFullDuplexSocket::onContentRetrieved(ConsumerSocket &s,
+                                               std::size_t size,
+                                               const std::error_code &ec) {
+  // Sanity check
+  if (size != receive_buffer_->size()) {
+    TRANSPORT_LOGE(
+        "Received content size differs from size retrieved from the buffer.");
+    return;
+  }
+
+  TRANSPORT_LOGI("Received content with size %lu", size);
+  if (!ec) {
+    read_callback_->readBufferAvailable(std::move(*receive_buffer_));
+  } else {
+    TRANSPORT_LOGE("Error retrieving content.");
+  }
+  // consumer_->stop();
+}
+
+void AsyncFullDuplexSocket::OnConnectCallback::onContentObject(
+    core::Interest::Ptr &&, core::ContentObject::Ptr &&content_object) {
+  // The ack message should contain the name to be used for notifying
+  // the production of the content to the other part
+
+  if (content_object->getPayload().length() == 0) {
+    TRANSPORT_LOGW("Connection response message empty....");
+    return;
+  }
+
+  SubscriptionResponseMessage *response =
+      reinterpret_cast<SubscriptionResponseMessage *>(
+          content_object->getPayload().writableData());
+
+  if (response->response.header.msg_type == MessageType::RESPONSE) {
+    if (response->response.return_code == ReturnCode::OK) {
+      auto ret =
+          socket_.subscribers_.emplace(AF_INET6, (uint8_t *)response->name, 0);
+      TRANSPORT_LOGI("Successfully connected!!!! Subscriber added: %s",
+                     ret.first->toString().c_str());
+      socket_.connect_callback_->connectSuccess();
+    }
+  }
+}
+
+void AsyncFullDuplexSocket::OnSignalCallback::onContentObject(
+    core::Interest::Ptr &&, core::ContentObject::Ptr &&content_object) {
+  return;
+}
+
+void AsyncFullDuplexSocket::OnSignalCallback::onTimeout(
+    core::Interest::Ptr &&interest) {
+  TRANSPORT_LOGE("Retransmitting signalization interest to %s!!",
+                 interest->getName().toString().c_str());
+  socket_.consumer_->asyncSendInterest(std::move(interest),
+                                       socket_.internal_signal_callback_.get());
+}
+
+void AsyncFullDuplexSocket::OnConnectCallback::onTimeout(
+    core::Interest::Ptr &&interest) {
+  socket_.connect_callback_->connectErr(
+      std::make_error_code(std::errc::not_connected));
+}
+
+std::shared_ptr<core::ContentObject> AsyncFullDuplexSocket::createAck() {
+  // Send the response back
+  core::Name name("b001::abcd");
+  auto response = std::make_shared<core::ContentObject>(name);
+  auto _payload = utils::MemBuf::create(sizeof(ActionMessage));
+  _payload->append(sizeof(ResponseMessage));
+  auto payload = response->getPayload().data();
+  ResponseMessage *response_message = (ResponseMessage *)payload;
+  response_message->header.msg_type = MessageType::RESPONSE;
+  response_message->header.reserved[0] = 0;
+  response_message->header.reserved[1] = 0;
+  response_message->return_code = ReturnCode::OK;
+  response->appendPayload(std::move(_payload));
+  response->setLifetime(0);
+  return response;
+}
+
+std::shared_ptr<core::ContentObject>
+AsyncFullDuplexSocket::createSubscriptionResponse(const core::Name &name) {
+  // Send the response back
+  core::Name tmp_name("b001::abcd");
+  auto response = std::make_shared<core::ContentObject>(tmp_name);
+  auto _payload = utils::MemBuf::create(sizeof(SubscriptionResponseMessage));
+  _payload->append(sizeof(SubscriptionResponseMessage));
+  auto payload = _payload->data();
+  SubscriptionResponseMessage *response_message =
+      (SubscriptionResponseMessage *)payload;
+  response_message->response.header.msg_type = MessageType::RESPONSE;
+  response_message->response.header.reserved[0] = 0;
+  response_message->response.header.reserved[1] = 0;
+  response_message->response.return_code = ReturnCode::OK;
+  name.copyToDestination(reinterpret_cast<uint8_t *>(response_message->name));
+  response->appendPayload(std::move(_payload));
+  response->setLifetime(0);
+  return response;
+}
+
+}  // namespace interface
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h b/libtransport/src/hicn/transport/interfaces/full_duplex_socket.h
new file mode 100755 (executable)
index 0000000..f881bea
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * This class is created for sending/receiving data over an ICN network.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/prefix.h>
+#include <hicn/transport/interfaces/async_transport.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <unordered_set>
+#include <vector>
+
+namespace transport {
+
+namespace interface {
+
+enum class MessageType : uint8_t { ACTION, RESPONSE, PAYLOAD };
+
+enum class Action : uint8_t {
+  SUBSCRIBE,
+  CANCEL_SUBSCRIPTION,
+  SIGNAL_PRODUCTION,
+};
+
+enum class ReturnCode : uint8_t {
+  OK,
+  FAILED,
+};
+
+struct MessageHeader {
+  MessageType msg_type;
+  uint8_t reserved[2];
+};
+
+struct ActionMessage {
+  MessageHeader header;
+  Action action;
+  uint64_t name[2];
+};
+
+struct ResponseMessage {
+  MessageHeader header;
+  ReturnCode return_code;
+};
+
+struct SubscriptionResponseMessage {
+  ResponseMessage response;
+  uint64_t name[2];
+};
+
+struct PayloadMessage {
+  MessageHeader header;
+  uint8_t reserved[1];
+};
+
+// struct NotificationMessage {
+//   Action action;
+//   uint8_t reserved[3];
+//   uint64_t
+// }
+
+using core::Prefix;
+
+class AsyncFullDuplexSocket : public AsyncSocket,
+                              public AsyncReader,
+                              public AsyncWriter,
+                              public AsyncAcceptor {
+ private:
+  struct Counters {
+    uint64_t app_bytes_written_;
+    uint64_t app_bytes_read_;
+
+    TRANSPORT_ALWAYS_INLINE void updateBytesWritten(uint64_t bytes) {
+      app_bytes_written_ += bytes;
+    }
+
+    TRANSPORT_ALWAYS_INLINE void updateBytesRead(uint64_t bytes) {
+      app_bytes_read_ += bytes;
+    }
+  };
+
+ public:
+  using UniquePtr = std::unique_ptr<AsyncFullDuplexSocket>;
+  using SharedPtr = std::unique_ptr<AsyncFullDuplexSocket>;
+
+  AsyncFullDuplexSocket(const Prefix &locator, asio::io_service &io_service);
+  AsyncFullDuplexSocket(const core::Prefix &locator);
+
+  ~AsyncFullDuplexSocket() {
+    TRANSPORT_LOGI("Adios AsyncFullDuplexSocket!!!");
+  };
+
+  using ReadCallback = AsyncReader::ReadCallback;
+  using WriteCallback = AsyncWriter::WriteCallback;
+
+  TRANSPORT_ALWAYS_INLINE void setReadCB(ReadCallback *callback) override {
+    read_callback_ = callback;
+  }
+
+  TRANSPORT_ALWAYS_INLINE ReadCallback *getReadCallback() const override {
+    return read_callback_;
+  }
+
+  TRANSPORT_ALWAYS_INLINE void setWriteCB(WriteCallback *callback) override {
+    write_callback_ = callback;
+  }
+
+  TRANSPORT_ALWAYS_INLINE WriteCallback *getWriteCallback() const override {
+    return write_callback_;
+  }
+
+  TRANSPORT_ALWAYS_INLINE const core::Prefix &getLocator() { return locator_; }
+
+  void connect(ConnectCallback *callback, const core::Prefix &prefix) override;
+
+  void write(WriteCallback *callback, const void *buf, size_t bytes,
+             const PublicationOptions &options,
+             WriteFlags flags = WriteFlags::NONE) override;
+
+  virtual void write(WriteCallback *callback,
+                     utils::SharableVector<uint8_t> &&output_buffer,
+                     const PublicationOptions &options,
+                     WriteFlags flags = WriteFlags::NONE) override;
+
+  void waitForSubscribers(AcceptCallback *cb) override;
+
+  // void writev(
+  //     WriteCallback* callback,
+  //     const iovec* vec,
+  //     size_t count,
+  //     Name &&content_to_publish_name,
+  //     WriteFlags flags = WriteFlags::NONE) override;
+
+  void close() override;
+
+  void closeNow() override;
+
+  void shutdownWrite() override;
+
+  void shutdownWriteNow() override;
+
+  bool good() const override;
+
+  bool readable() const override;
+
+  bool writable() const override;
+
+  bool isPending() const override;
+
+  bool connected() const override;
+
+  bool error() const override;
+
+  void setSendTimeout(uint32_t milliseconds) override;
+
+  size_t getAppBytesWritten() const override;
+  size_t getRawBytesWritten() const override;
+  size_t getAppBytesReceived() const override;
+  size_t getRawBytesReceived() const override;
+
+  uint32_t getSendTimeout() const override;
+
+ private:
+  std::shared_ptr<core::ContentObject> decodeSynchronizationMessage(
+      const core::Interest &interest);
+
+  class OnConnectCallback : public BasePortal::ConsumerCallback {
+   public:
+    OnConnectCallback(AsyncFullDuplexSocket &socket) : socket_(socket){};
+    virtual ~OnConnectCallback() = default;
+    void onContentObject(core::Interest::Ptr &&,
+                         core::ContentObject::Ptr &&content_object) override;
+    void onTimeout(core::Interest::Ptr &&interest) override;
+
+   private:
+    AsyncFullDuplexSocket &socket_;
+  };
+
+  class OnSignalCallback : public BasePortal::ConsumerCallback {
+   public:
+    OnSignalCallback(AsyncFullDuplexSocket &socket) : socket_(socket){};
+    virtual ~OnSignalCallback() = default;
+    void onContentObject(core::Interest::Ptr &&,
+                         core::ContentObject::Ptr &&content_object);
+    void onTimeout(core::Interest::Ptr &&interest);
+
+   private:
+    AsyncFullDuplexSocket &socket_;
+  };
+
+  void onControlInterest(ProducerSocket &s, const core::Interest &i);
+  void onContentProduced(ProducerSocket &producer, const std::error_code &ec,
+                         uint64_t bytes_written);
+  void onContentRetrieved(ConsumerSocket &s, std::size_t size,
+                          const std::error_code &ec);
+
+  void signalProductionToSubscribers(const core::Name &name);
+  void piggybackPayloadToSubscribers(const core::Name &name,
+                                     const uint8_t *buffer, std::size_t bytes);
+
+  std::shared_ptr<core::ContentObject> createAck();
+  std::shared_ptr<core::ContentObject> createSubscriptionResponse(
+      const core::Name &name);
+
+  core::Prefix locator_;
+  uint32_t incremental_suffix_;
+  core::Name sync_notification_;
+  //  std::unique_ptr<BasePortal> portal_;
+  asio::io_service internal_io_service_;
+  asio::io_service &io_service_;
+  asio::io_service::work work_;
+
+  // These names represent the "locator" of a certain
+  // peer that subscribed to this.
+  std::unordered_set<core::Name> subscribers_;
+
+  // Useful for publishing / Retrieving data
+  std::unique_ptr<ProducerSocket> producer_;
+  std::unique_ptr<ConsumerSocket> consumer_;
+
+  ReadCallback *read_callback_;
+  WriteCallback *write_callback_;
+  ConnectCallback *connect_callback_;
+  AcceptCallback *accept_callback_;
+
+  std::unique_ptr<OnConnectCallback> internal_connect_callback_;
+  std::unique_ptr<OnSignalCallback> internal_signal_callback_;
+
+  uint32_t send_timeout_milliseconds_;
+  struct Counters counters_;
+  std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer_;
+};
+
+}  // namespace interface
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/publication_options.h b/libtransport/src/hicn/transport/interfaces/publication_options.h
new file mode 100755 (executable)
index 0000000..ae5366c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <sstream>
+#include <vector>
+
+namespace transport {
+
+namespace interface {
+
+class PublicationOptions {
+ public:
+  core::Name name;
+  uint32_t content_lifetime_milliseconds;
+  // TODO Signature
+};
+}  // namespace interface
+
+}  // namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.cc
new file mode 100755 (executable)
index 0000000..de3e844
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/rtc_socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+RTCConsumerSocket::RTCConsumerSocket(int protocol, asio::io_service &io_service)
+    : ConsumerSocket(protocol, io_service) {}
+
+RTCConsumerSocket::~RTCConsumerSocket() {}
+
+void RTCConsumerSocket::handleRTCPPacket(uint8_t *packet, size_t len) {
+  RTCTransportProtocol *transport = dynamic_cast<RTCTransportProtocol *>(
+      ConsumerSocket::transport_protocol_.get());
+  if (transport) transport->onRTCPPacket(packet, len);
+}
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_consumer.h
new file mode 100755 (executable)
index 0000000..86ccf6e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+class RTCConsumerSocket : public ConsumerSocket {
+ public:
+  explicit RTCConsumerSocket(int protocol, asio::io_service &io_service);
+
+  ~RTCConsumerSocket();
+
+  void handleRTCPPacket(uint8_t *packet, size_t len);
+};
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.cc
new file mode 100755 (executable)
index 0000000..d8a9d53
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2017-2019 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 <stdlib.h>
+#include <time.h>
+#include <hicn/transport/interfaces/rtc_socket_producer.h>
+
+#define NACK_HEADER_SIZE 8  // bytes
+#define TIMESTAMP_LEN 8     // bytes
+#define TCP_HEADER_SIZE 20
+#define IP6_HEADER_SIZE 40
+#define INIT_PACKET_PRODUCTION_RATE 100  // pps random value (almost 1Mbps)
+#define STATS_INTERVAL_DURATION 500      // ms
+#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8
+
+// NACK HEADER
+//   +-----------------------------------------+
+//   | 4 bytes: current segment in production  |
+//   +-----------------------------------------+
+//   | 4 bytes: production rate (bytes x sec)  |
+//   +-----------------------------------------+
+//   may require additional field (Rate for multiple qualities, ...)
+//
+
+namespace transport {
+
+namespace interface {
+
+RTCProducerSocket::RTCProducerSocket(asio::io_service &io_service)
+    : ProducerSocket(io_service),
+      currentSeg_(1),
+      nack_(std::make_shared<ContentObject>()),
+      producedBytes_(0),
+      producedPackets_(0),
+      bytesProductionRate_(0),
+      packetsProductionRate_(INIT_PACKET_PRODUCTION_RATE),
+      perSecondFactor_(1000 / STATS_INTERVAL_DURATION) {
+  nack_->appendPayload(utils::MemBuf::create(NACK_HEADER_SIZE));
+  lastStats_ = std::chrono::steady_clock::now();
+  srand(time(NULL));
+  prodLabel_ = ((rand() % 255) << 24UL);
+}
+
+RTCProducerSocket::~RTCProducerSocket() {}
+
+void RTCProducerSocket::registerName(Prefix &producer_namespace) {
+  ProducerSocket::registerPrefix(producer_namespace);
+
+  flowName_ = producer_namespace.getName();
+
+  if (flowName_.getType() == HNT_CONTIGUOUS_V4 ||
+      flowName_.getType() == HNT_IOV_V4) {
+    headerSize_ = sizeof(hicn_v6_hdr_t::ip);
+  } else if (flowName_.getType() == HNT_CONTIGUOUS_V6 ||
+             flowName_.getType() == HNT_IOV_V6) {
+    headerSize_ = sizeof(hicn_v4_hdr_t::ip);
+  } else {
+    throw errors::RuntimeException("Unknown name format.");
+  }
+
+  headerSize_ += TCP_HEADER_SIZE;
+}
+
+void RTCProducerSocket::updateStats(uint32_t packet_size) {
+  producedBytes_ += packet_size;
+  producedPackets_++;
+  std::chrono::steady_clock::duration duration =
+      std::chrono::steady_clock::now() - lastStats_;
+  if (std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() >=
+      STATS_INTERVAL_DURATION) {
+    lastStats_ = std::chrono::steady_clock::now();
+    bytesProductionRate_ = producedBytes_ * perSecondFactor_;
+    packetsProductionRate_ = producedPackets_ * perSecondFactor_;
+    producedBytes_ = 0;
+    producedPackets_ = 0;
+  }
+}
+
+void RTCProducerSocket::produce(const uint8_t *buf, size_t buffer_size) {
+  if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) {
+    return;
+  }
+
+  if (TRANSPORT_EXPECT_FALSE((buffer_size + headerSize_ + TIMESTAMP_LEN) >
+                             data_packet_size_)) {
+    return;
+  }
+
+  updateStats(buffer_size + headerSize_ + TIMESTAMP_LEN);
+
+  std::shared_ptr<ContentObject> content_object =
+      std::make_shared<ContentObject>(flowName_.setSuffix(currentSeg_));
+  auto payload = utils::MemBuf::copyBuffer(buf, buffer_size, TIMESTAMP_LEN);
+
+  // content_object->setLifetime(content_object_expiry_time_);
+  content_object->setLifetime(1000);  // XXX this should be set by the APP
+
+  uint64_t timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
+                           std::chrono::system_clock::now().time_since_epoch())
+                           .count();
+
+  payload->prepend(TIMESTAMP_LEN);
+  uint8_t *payloadPointer = payload->writableData();
+  *(uint64_t *)payloadPointer = timestamp;
+  content_object->appendPayload(std::move(payload));
+
+  content_object->setPathLabel(prodLabel_);
+  portal_->sendContentObject(*content_object);
+
+  currentSeg_++;
+}
+
+void RTCProducerSocket::onInterest(Interest::Ptr &&interest) {
+  uint32_t interestSeg = interest->getName().getSuffix();
+  uint32_t lifetime = interest->getLifetime();
+  uint32_t max_gap;
+
+  // XXX
+  // packetsProductionRate_ is modified by another thread in updateStats
+  // this should be safe since I just read here. but, you never know.
+  max_gap =
+      floor((double)((double)((double)lifetime *
+                              INTEREST_LIFETIME_REDUCTION_FACTOR / 1000.0) *
+                     (double)packetsProductionRate_));
+
+  if (interestSeg < currentSeg_ || interestSeg > (max_gap + currentSeg_)) {
+    sendNack(*interest);
+  }
+  // else drop packet
+}
+
+void RTCProducerSocket::sendNack(const Interest &interest) {
+  nack_->setName(interest.getName());
+  uint32_t *payload_ptr = (uint32_t *)nack_->getPayload().data();
+  *payload_ptr = currentSeg_;
+  *(++payload_ptr) = bytesProductionRate_;
+
+  nack_->setLifetime(0);
+  nack_->setPathLabel(prodLabel_);
+  portal_->sendContentObject(*nack_);
+}
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h b/libtransport/src/hicn/transport/interfaces/rtc_socket_producer.h
new file mode 100755 (executable)
index 0000000..1a42bdc
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/utils/content_store.h>
+
+#include <map>
+#include <mutex>
+
+namespace transport {
+
+namespace interface {
+
+class RTCProducerSocket : public ProducerSocket {
+ public:
+  RTCProducerSocket(asio::io_service &io_service);
+  ~RTCProducerSocket();
+
+  void registerName(Prefix &producer_namespace);
+
+  void produce(const uint8_t *buffer, size_t buffer_size);
+
+  void onInterest(Interest::Ptr &&interest) override;
+
+ private:
+  void sendNack(const Interest &interest);
+  void updateStats(uint32_t packet_size);
+
+  // std::map<uint32_t, uint64_t> pendingInterests_;
+  uint32_t currentSeg_;
+  uint32_t prodLabel_;
+  uint16_t headerSize_;
+  Name flowName_;
+  // bool produceInSynch_;
+  std::shared_ptr<ContentObject> nack_;
+  uint32_t producedBytes_;
+  uint32_t producedPackets_;
+  uint32_t bytesProductionRate_;
+  uint32_t packetsProductionRate_;
+  uint32_t perSecondFactor_;
+  std::chrono::steady_clock::time_point lastStats_;
+};
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket.h b/libtransport/src/hicn/transport/interfaces/socket.h
new file mode 100755 (executable)
index 0000000..2275781
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/facade.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/interfaces/socket_options_default_values.h>
+#include <hicn/transport/interfaces/socket_options_keys.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/identity.h>
+#include <hicn/transport/utils/verifier.h>
+
+#define SOCKET_OPTION_GET 0
+#define SOCKET_OPTION_NOT_GET 1
+#define SOCKET_OPTION_SET 2
+#define SOCKET_OPTION_NOT_SET 3
+#define SOCKET_OPTION_DEFAULT 12345
+
+#define VOID_HANDLER 0
+
+namespace transport {
+
+namespace protocol {
+class IcnObserver;
+}
+
+namespace interface {
+
+template <typename PortalType>
+class Socket;
+class ConsumerSocket;
+class ProducerSocket;
+
+// using Interest = core::Interest;
+// using ContentObject = core::ContentObject;
+// using Name = core::Name;
+// using HashAlgorithm = core::HashAlgorithm;
+// using CryptoSuite = utils::CryptoSuite;
+// using Identity = utils::Identity;
+// using Verifier = utils::Verifier;
+
+using HicnForwarderPortal = core::HicnForwarderPortal;
+
+#ifdef __linux__
+#ifndef __ANDROID__
+using RawSocketPortal = core::RawSocketPortal;
+#endif
+#endif
+
+#ifdef __vpp__
+using VPPForwarderPortal = core::VPPForwarderPortal;
+using BaseSocket = Socket<VPPForwarderPortal>;
+using BasePortal = VPPForwarderPortal;
+#else
+using BaseSocket = Socket<HicnForwarderPortal>;
+using BasePortal = HicnForwarderPortal;
+#endif
+
+using PayloadType = core::PayloadType;
+using Prefix = core::Prefix;
+using Array = utils::Array<uint8_t>;
+
+using ConsumerInterestCallback =
+    std::function<void(ConsumerSocket &, const core::Interest &)>;
+
+using ConsumerContentCallback =
+    std::function<void(ConsumerSocket &, std::size_t, const std::error_code &)>;
+
+using ConsumerTimerCallback =
+    std::function<void(ConsumerSocket &, std::size_t,
+                       std::chrono::milliseconds &, float, uint32_t, uint32_t)>;
+
+using ProducerContentCallback = std::function<void(
+    ProducerSocket &, const std::error_code &, uint64_t bytes_written)>;
+
+using ConsumerContentObjectCallback =
+    std::function<void(ConsumerSocket &, const core::ContentObject &)>;
+
+using ConsumerContentObjectVerificationCallback =
+    std::function<bool(ConsumerSocket &, const core::ContentObject &)>;
+
+using ConsumerManifestCallback =
+    std::function<void(ConsumerSocket &, const core::ContentObjectManifest &)>;
+
+using ProducerContentObjectCallback =
+    std::function<void(ProducerSocket &, core::ContentObject &)>;
+
+using ProducerInterestCallback =
+    std::function<void(ProducerSocket &, const core::Interest &)>;
+
+using ProducerInterestCallback =
+    std::function<void(ProducerSocket &, const core::Interest &)>;
+
+using namespace protocol;
+
+template <typename PortalType>
+class Socket {
+  static_assert(std::is_same<PortalType, HicnForwarderPortal>::value
+#ifdef __linux__
+#ifndef __ANDROID__
+                    || std::is_same<PortalType, RawSocketPortal>::value
+#ifdef __vpp__
+                    || std::is_same<PortalType, VPPForwarderPortal>::value
+#endif
+#endif
+                ,
+#else
+                ,
+
+#endif
+                "This class is not allowed as Portal");
+
+ public:
+  using Portal = PortalType;
+
+  virtual asio::io_service &getIoService() = 0;
+
+  virtual void connect() = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              uint32_t socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              double socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              bool socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              core::Name socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              std::list<Prefix> socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ProducerInterestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ProducerContentCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerInterestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerContentCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerManifestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              IcnObserver *socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              core::HashAlgorithm socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              utils::CryptoSuite socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              const utils::Identity &socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerTimerCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              const std::string &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              uint32_t &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              double &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              bool &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              core::Name &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::list<Prefix> &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ProducerInterestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ConsumerInterestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ConsumerContentCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ConsumerManifestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ProducerContentCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::shared_ptr<Portal> &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              IcnObserver **socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              core::HashAlgorithm &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              utils::CryptoSuite &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              utils::Identity &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::string &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ConsumerTimerCallback &socket_option_value) = 0;
+
+ protected:
+  virtual ~Socket(){};
+
+ protected:
+  std::string output_interface_;
+};
+
+}  // namespace interface
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.cc b/libtransport/src/hicn/transport/interfaces/socket_consumer.cc
new file mode 100755 (executable)
index 0000000..8109d0e
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_consumer.h>
+
+namespace transport {
+
+namespace interface {
+
+ConsumerSocket::ConsumerSocket(int protocol)
+    : ConsumerSocket(protocol, internal_io_service_) {}
+
+ConsumerSocket::ConsumerSocket(int protocol, asio::io_service &io_service)
+    : io_service_(io_service),
+      portal_(std::make_shared<Portal>(io_service_)),
+      async_downloader_(),
+      interest_lifetime_(default_values::interest_lifetime),
+      min_window_size_(default_values::min_window_size),
+      max_window_size_(default_values::max_window_size),
+      current_window_size_(-1),
+      max_retransmissions_(
+          default_values::transport_protocol_max_retransmissions),
+      /****** RAAQM Parameters ******/
+      minimum_drop_probability_(default_values::minimum_drop_probability),
+      sample_number_(default_values::sample_number),
+      gamma_(default_values::gamma_value),
+      beta_(default_values::beta_value),
+      drop_factor_(default_values::drop_factor),
+      /****** END RAAQM Parameters ******/
+      rate_estimation_alpha_(default_values::rate_alpha),
+      rate_estimation_observer_(nullptr),
+      rate_estimation_choice_(0),
+      is_async_(false),
+      verify_signature_(false),
+      content_buffer_(nullptr),
+      on_interest_output_(VOID_HANDLER),
+      on_interest_timeout_(VOID_HANDLER),
+      on_interest_satisfied_(VOID_HANDLER),
+      on_content_object_input_(VOID_HANDLER),
+      on_content_object_verification_(VOID_HANDLER),
+      on_content_object_(VOID_HANDLER),
+      on_manifest_(VOID_HANDLER),
+      on_payload_retrieved_(VOID_HANDLER),
+      virtual_download_(false),
+      rtt_stats_(false),
+      timer_(portal_->getIoService()),
+      timer_interval_milliseconds_(0) {
+  switch (protocol) {
+    case TransportProtocolAlgorithms::VEGAS:
+      transport_protocol_ = std::make_shared<VegasTransportProtocol>(this);
+      break;
+    case TransportProtocolAlgorithms::CBR:
+      transport_protocol_ = std::make_shared<CbrTransportProtocol>(this);
+      break;
+    case TransportProtocolAlgorithms::RTC:
+      transport_protocol_ = std::make_shared<RTCTransportProtocol>(this);
+      break;
+    case TransportProtocolAlgorithms::RAAQM:
+    default:
+      transport_protocol_ = std::make_shared<RaaqmTransportProtocol>(this);
+      break;
+  }
+}
+
+ConsumerSocket::~ConsumerSocket() {
+  stop();
+
+  async_downloader_.stop();
+
+  transport_protocol_.reset();
+  portal_.reset();
+}
+
+void ConsumerSocket::connect() { portal_->connect(); }
+
+int ConsumerSocket::consume(const Name &name,
+                            utils::SharableVector<uint8_t> &receive_buffer) {
+  if (transport_protocol_->isRunning()) {
+    return CONSUMER_BUSY;
+  }
+
+  content_buffer_ = receive_buffer.shared_from_this();
+
+  network_name_ = name;
+  network_name_.setSuffix(0);
+  is_async_ = false;
+
+  transport_protocol_->start(receive_buffer);
+
+  return CONSUMER_READY;
+}
+
+int ConsumerSocket::asyncConsume(
+    const Name &name,
+    std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer) {
+  // XXX Try to move the name here, instead of copying it!!
+  if (!async_downloader_.stopped()) {
+    async_downloader_.add([this, receive_buffer, name]() {
+      network_name_ = std::move(name);
+      network_name_.setSuffix(0);
+      is_async_ = true;
+      transport_protocol_->start(*receive_buffer);
+    });
+  }
+
+  return CONSUMER_READY;
+}
+
+void ConsumerSocket::asyncSendInterest(Interest::Ptr &&interest,
+                                       Portal::ConsumerCallback *callback) {
+  if (!async_downloader_.stopped()) {
+    // TODO Workaround, to be fixed!
+    auto i = interest.release();
+    async_downloader_.add([this, i, callback]() mutable {
+      Interest::Ptr _interest(i);
+      portal_->setConsumerCallback(callback);
+      portal_->sendInterest(std::move(_interest));
+      portal_->runEventsLoop();
+    });
+  }
+}
+
+void ConsumerSocket::stop() {
+  if (transport_protocol_->isRunning()) {
+    transport_protocol_->stop();
+  }
+
+  //is_running_ = false;
+}
+
+void ConsumerSocket::resume() {
+  if(!transport_protocol_->isRunning()){
+    transport_protocol_->resume();
+  }
+}
+
+asio::io_service &ConsumerSocket::getIoService() {
+  return portal_->getIoService();
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    double socket_option_value) {
+  switch (socket_option_key) {
+    case MIN_WINDOW_SIZE:
+      min_window_size_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case MAX_WINDOW_SIZE:
+      max_window_size_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case CURRENT_WINDOW_SIZE:
+      current_window_size_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GAMMA_VALUE:
+      gamma_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case BETA_VALUE:
+      beta_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case DROP_FACTOR:
+      drop_factor_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case MINIMUM_DROP_PROBABILITY:
+      minimum_drop_probability_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case RATE_ESTIMATION_ALPHA:
+      if (socket_option_value >= 0 && socket_option_value < 1) {
+        rate_estimation_alpha_ = socket_option_value;
+      } else {
+        rate_estimation_alpha_ = ALPHA;
+      }
+      return SOCKET_OPTION_SET;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    uint32_t socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+      input_buffer_size_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+      output_buffer_size_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::MAX_INTEREST_RETX:
+      max_retransmissions_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::INTEREST_LIFETIME:
+      interest_lifetime_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_retransmission_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_timeout_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_satisfied_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_output_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_content_object_input_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+      if (socket_option_value == VOID_HANDLER) {
+        on_content_object_verification_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+      if (socket_option_value == VOID_HANDLER) {
+        on_payload_retrieved_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+      if (socket_option_value > 0) {
+        rate_estimation_batching_parameter_ = socket_option_value;
+      } else {
+        rate_estimation_batching_parameter_ = BATCH;
+      }
+      return SOCKET_OPTION_SET;
+
+    case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+      if (socket_option_value > 0) {
+        rate_estimation_choice_ = socket_option_value;
+      } else {
+        rate_estimation_choice_ = RATE_CHOICE;
+      }
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::TIMER_INTERVAL:
+      timer_interval_milliseconds_ = socket_option_value;
+      TRANSPORT_LOGD("Ok set %d", timer_interval_milliseconds_);
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    bool socket_option_value) {
+  switch (socket_option_key) {
+    case OtherOptions::VIRTUAL_DOWNLOAD:
+      virtual_download_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case RaaqmTransportOptions::RTT_STATS:
+      rtt_stats_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::VERIFY_SIGNATURE:
+      verify_signature_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    Name socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::NETWORK_NAME:
+      network_name_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    std::list<Prefix> socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ConsumerContentObjectCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+      on_content_object_input_ = socket_option_value;
+      ;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ProducerContentObjectCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key,
+    ConsumerContentObjectVerificationCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+      on_content_object_verification_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ConsumerInterestCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+      on_interest_retransmission_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+      on_interest_output_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+      on_interest_timeout_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+      on_interest_satisfied_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ProducerInterestCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ConsumerContentCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+      on_payload_retrieved_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ConsumerManifestCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::MANIFEST_INPUT:
+      on_manifest_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, ProducerContentCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    IcnObserver *socket_option_value) {
+  if (socket_option_key == RateEstimationOptions::RATE_ESTIMATION_OBSERVER) {
+    rate_estimation_observer_ = socket_option_value;
+    return SOCKET_OPTION_SET;
+  }
+
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    HashAlgorithm socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    utils::CryptoSuite socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(
+    int socket_option_key, const utils::Identity &socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    const std::string &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::CERTIFICATE:
+      key_id_ = verifier_.addKeyFromCertificate(socket_option_value);
+
+      if (key_id_ != nullptr) {
+        return SOCKET_OPTION_SET;
+      }
+
+      break;
+
+    case DataLinkOptions::OUTPUT_INTERFACE:
+      output_interface_ = socket_option_value;
+      portal_->setOutputInterface(output_interface_);
+      return SOCKET_OPTION_SET;
+  }
+
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::setSocketOption(int socket_option_key,
+                                    ConsumerTimerCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::TIMER_EXPIRES:
+      on_timer_expires_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+  }
+
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    double &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::MIN_WINDOW_SIZE:
+      socket_option_value = min_window_size_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::MAX_WINDOW_SIZE:
+      socket_option_value = max_window_size_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::CURRENT_WINDOW_SIZE:
+      socket_option_value = current_window_size_;
+      return SOCKET_OPTION_GET;
+
+      // RAAQM parameters
+
+    case RaaqmTransportOptions::GAMMA_VALUE:
+      socket_option_value = gamma_;
+      return SOCKET_OPTION_GET;
+
+    case RaaqmTransportOptions::BETA_VALUE:
+      socket_option_value = beta_;
+      return SOCKET_OPTION_GET;
+
+    case RaaqmTransportOptions::DROP_FACTOR:
+      socket_option_value = drop_factor_;
+      return SOCKET_OPTION_GET;
+
+    case RaaqmTransportOptions::MINIMUM_DROP_PROBABILITY:
+      socket_option_value = minimum_drop_probability_;
+      return SOCKET_OPTION_GET;
+
+    case RateEstimationOptions::RATE_ESTIMATION_ALPHA:
+      socket_option_value = rate_estimation_alpha_;
+      return SOCKET_OPTION_GET;
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    uint32_t &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+      socket_option_value = input_buffer_size_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+      socket_option_value = output_buffer_size_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::MAX_INTEREST_RETX:
+      socket_option_value = max_retransmissions_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::INTEREST_LIFETIME:
+      socket_option_value = interest_lifetime_;
+      return SOCKET_OPTION_GET;
+
+    case RaaqmTransportOptions::SAMPLE_NUMBER:
+      socket_option_value = sample_number_;
+      return SOCKET_OPTION_GET;
+
+    case RateEstimationOptions::RATE_ESTIMATION_BATCH_PARAMETER:
+      socket_option_value = rate_estimation_batching_parameter_;
+      return SOCKET_OPTION_GET;
+
+    case RateEstimationOptions::RATE_ESTIMATION_CHOICE:
+      socket_option_value = rate_estimation_choice_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    bool &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::ASYNC_MODE:
+      socket_option_value = is_async_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::RUNNING:
+      socket_option_value = transport_protocol_->isRunning();
+       return SOCKET_OPTION_GET;
+
+    case OtherOptions::VIRTUAL_DOWNLOAD:
+      socket_option_value = virtual_download_;
+      return SOCKET_OPTION_GET;
+
+    case RaaqmTransportOptions::RTT_STATS:
+      socket_option_value = rtt_stats_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::VERIFY_SIGNATURE:
+      socket_option_value = verify_signature_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    Name &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::NETWORK_NAME:
+      socket_option_value = network_name_;
+      return SOCKET_OPTION_GET;
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    std::list<Prefix> &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ConsumerContentObjectCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_INPUT:
+      socket_option_value = on_content_object_input_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ProducerContentObjectCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key,
+    ConsumerContentObjectVerificationCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_OBJECT_TO_VERIFY:
+      socket_option_value = on_content_object_verification_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ConsumerInterestCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::INTEREST_RETRANSMISSION:
+      socket_option_value = on_interest_retransmission_;
+      return SOCKET_OPTION_GET;
+
+    case ConsumerCallbacksOptions::INTEREST_OUTPUT:
+      socket_option_value = on_interest_output_;
+      return SOCKET_OPTION_GET;
+
+    case ConsumerCallbacksOptions::INTEREST_EXPIRED:
+      socket_option_value = on_interest_timeout_;
+      return SOCKET_OPTION_GET;
+
+    case ConsumerCallbacksOptions::INTEREST_SATISFIED:
+      socket_option_value = on_interest_satisfied_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ProducerInterestCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ConsumerContentCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::CONTENT_RETRIEVED:
+      socket_option_value = on_payload_retrieved_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ConsumerManifestCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::MANIFEST_INPUT:
+      socket_option_value = on_manifest_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+  switch (socket_option_key) {
+    case PORTAL:
+      socket_option_value = portal_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    IcnObserver **socket_option_value) {
+  if (socket_option_key == RATE_ESTIMATION_OBSERVER) {
+    *socket_option_value = (rate_estimation_observer_);
+    return SOCKET_OPTION_GET;
+  }
+
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    HashAlgorithm &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    utils::CryptoSuite &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    utils::Identity &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ProducerContentCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(int socket_option_key,
+                                    std::string &socket_option_value) {
+  switch (socket_option_key) {
+    case DataLinkOptions::OUTPUT_INTERFACE:
+      socket_option_value = output_interface_;
+      return SOCKET_OPTION_GET;
+  }
+
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ConsumerSocket::getSocketOption(
+    int socket_option_key, ConsumerTimerCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ConsumerCallbacksOptions::TIMER_EXPIRES:
+      socket_option_value = on_timer_expires_;
+      return SOCKET_OPTION_GET;
+  }
+
+  return SOCKET_OPTION_NOT_GET;
+}
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_consumer.h b/libtransport/src/hicn/transport/interfaces/socket_consumer.h
new file mode 100755 (executable)
index 0000000..9e309aa
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket.h>
+
+#include <hicn/transport/protocols/cbr.h>
+#include <hicn/transport/protocols/protocol.h>
+#include <hicn/transport/protocols/raaqm.h>
+#include <hicn/transport/protocols/rtc.h>
+#include <hicn/transport/protocols/vegas.h>
+
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#define CONSUMER_READY 0
+#define CONSUMER_BUSY 1
+
+namespace transport {
+
+namespace interface {
+
+class ConsumerSocket : public BaseSocket {
+  friend class protocol::TransportProtocol;
+  friend class protocol::VegasTransportProtocol;
+  friend class protocol::RaaqmTransportProtocol;
+  friend class protocol::CbrTransportProtocol;
+
+ public:
+  explicit ConsumerSocket(int protocol);
+  explicit ConsumerSocket(int protocol, asio::io_service &io_service);
+
+  ~ConsumerSocket();
+
+  void connect() override;
+
+  int consume(const Name &name, utils::SharableVector<uint8_t> &receive_buffer);
+
+  int asyncConsume(
+      const Name &name,
+      std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer);
+
+  void asyncSendInterest(Interest::Ptr &&interest,
+                         Portal::ConsumerCallback *callback);
+
+  void stop();
+
+  void resume();
+
+  asio::io_service &getIoService() override;
+
+  int setSocketOption(int socket_option_key,
+                      uint32_t socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      double socket_option_value) override;
+
+  int setSocketOption(int socket_option_key, bool socket_option_value) override;
+
+  int setSocketOption(int socket_option_key, Name socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      std::list<Prefix> socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerInterestCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ProducerInterestCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerContentCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerManifestCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      IcnObserver *socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      HashAlgorithm socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      utils::CryptoSuite crypto_suite) override;
+
+  int setSocketOption(int socket_option_key,
+                      const utils::Identity &crypto_suite) override;
+
+  int setSocketOption(int socket_option_key,
+                      const std::string &socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerTimerCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ProducerContentCallback socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      uint32_t &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      double &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      bool &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      Name &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::list<Prefix> &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerInterestCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ProducerInterestCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerContentCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerManifestCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<Portal> &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      IcnObserver **socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      HashAlgorithm &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      utils::CryptoSuite &crypto_suite) override;
+
+  int getSocketOption(int socket_option_key,
+                      utils::Identity &crypto_suite) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::string &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerTimerCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ProducerContentCallback &socket_option_value) override;
+
+ protected:
+  std::shared_ptr<TransportProtocol> transport_protocol_;
+
+ private:
+  // context inner state variables
+  asio::io_service internal_io_service_;
+  asio::io_service &io_service_;
+
+  std::shared_ptr<Portal> portal_;
+
+  utils::EventThread async_downloader_;
+
+  Name network_name_;
+
+  int interest_lifetime_;
+
+  double min_window_size_;
+  double max_window_size_;
+  double current_window_size_;
+  uint32_t max_retransmissions_;
+  size_t output_buffer_size_;
+  size_t input_buffer_size_;
+
+  // RAAQM Parameters
+
+  double minimum_drop_probability_;
+  unsigned int sample_number_;
+  double gamma_;
+  double beta_;
+  double drop_factor_;
+
+  // Rate estimation parameters
+  double rate_estimation_alpha_;
+  IcnObserver *rate_estimation_observer_;
+  int rate_estimation_batching_parameter_;
+  int rate_estimation_choice_;
+
+  bool is_async_;
+
+  utils::Verifier verifier_;
+  PARCKeyId *key_id_;
+  bool verify_signature_;
+
+  std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+
+  ConsumerInterestCallback on_interest_retransmission_;
+  ConsumerInterestCallback on_interest_output_;
+  ConsumerInterestCallback on_interest_timeout_;
+  ConsumerInterestCallback on_interest_satisfied_;
+
+  ConsumerContentObjectCallback on_content_object_input_;
+  ConsumerContentObjectVerificationCallback on_content_object_verification_;
+
+  ConsumerContentObjectCallback on_content_object_;
+  ConsumerManifestCallback on_manifest_;
+
+  ConsumerContentCallback on_payload_retrieved_;
+
+  ConsumerTimerCallback on_timer_expires_;
+
+  // Virtual download for traffic generator
+
+  bool virtual_download_;
+  bool rtt_stats_;
+
+  Time t0_;
+  Time t1_;
+  asio::steady_timer timer_;
+  uint32_t timer_interval_milliseconds_;
+};
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h b/libtransport/src/hicn/transport/interfaces/socket_options_default_values.h
new file mode 100755 (executable)
index 0000000..5fae1c4
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+
+namespace transport {
+
+namespace interface {
+
+namespace default_values {
+
+const uint32_t interest_lifetime = 1001;  // milliseconds
+const uint32_t content_object_expiry_time =
+    0xffff;                                        // milliseconds -> 50 seconds
+const uint32_t content_object_packet_size = 1500;  // The ethernet MTU
+const uint32_t producer_socket_input_buffer_size = 150000;   // Interests
+const uint32_t producer_socket_output_buffer_size = 150000;  // Content Object
+const uint32_t log_2_default_buffer_size = 12;
+const uint32_t signature_size = 260;           // bytes
+const uint32_t key_locator_size = 60;          // bytes
+const uint32_t limit_guard = 80;               // bytes
+const uint32_t min_window_size = 1;            // Interests
+const uint32_t max_window_size = 128000;       // Interests
+const uint32_t digest_size = 34;               // bytes
+const uint32_t max_out_of_order_segments = 3;  // content object
+const uint32_t never_expire_time = 0x0000ffff << 0x0f;
+
+// RAAQM
+const int sample_number = 30;
+const double gamma_value = 1;
+const double beta_value = 0.8;
+const double drop_factor = 0.2;
+const double minimum_drop_probability = 0.00001;
+const int path_id = 0;
+const double rate_alpha = 0.8;
+
+// Vegas
+const double alpha = 1 / 8;
+const double beta = 1 / 4;
+const uint16_t k = 4;
+const std::chrono::milliseconds clock_granularity =
+    std::chrono::milliseconds(100);
+
+// maximum allowed values
+const uint32_t transport_protocol_min_retransmissions = 0;
+const uint32_t transport_protocol_max_retransmissions = 128;
+const uint32_t max_content_object_size = 8096;
+
+}  // namespace default_values
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_options_keys.h b/libtransport/src/hicn/transport/interfaces/socket_options_keys.h
new file mode 100755 (executable)
index 0000000..1afad2b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace interface {
+
+typedef enum {
+  RAAQM = 0,
+  VEGAS = 1,
+  CBR = 3,
+  RTC = 4,
+} TransportProtocolAlgorithms;
+
+typedef enum {
+  INPUT_BUFFER_SIZE = 101,
+  OUTPUT_BUFFER_SIZE = 102,
+  NETWORK_NAME = 103,
+  NAME_SUFFIX = 104,
+  MAX_INTEREST_RETX = 105,
+  DATA_PACKET_SIZE = 106,
+  INTEREST_LIFETIME = 107,
+  CONTENT_OBJECT_EXPIRY_TIME = 108,
+  KEY_LOCATOR = 110,
+  SIGNATURE_TYPE = 111,
+  MIN_WINDOW_SIZE = 112,
+  MAX_WINDOW_SIZE = 113,
+  CURRENT_WINDOW_SIZE = 114,
+  ASYNC_MODE = 115,
+  MAKE_MANIFEST = 116,
+  PORTAL = 117,
+  RUNNING = 118,
+  HASH_ALGORITHM = 119,
+  CRYPTO_SUITE = 120,
+  IDENTITY = 121,
+  CERTIFICATE = 122,
+  VERIFY_SIGNATURE = 123,
+  TIMER_INTERVAL = 124
+} GeneralTransportOptions;
+
+typedef enum {
+  SAMPLE_NUMBER = 201,
+  GAMMA_VALUE = 202,
+  BETA_VALUE = 203,
+  DROP_FACTOR = 204,
+  MINIMUM_DROP_PROBABILITY = 205,
+  PATH_ID = 206,
+  RTT_STATS = 207,
+} RaaqmTransportOptions;
+
+typedef enum {
+  RATE_ESTIMATION_ALPHA = 301,
+  RATE_ESTIMATION_OBSERVER = 302,
+  RATE_ESTIMATION_BATCH_PARAMETER = 303,
+  RATE_ESTIMATION_CHOICE = 304,
+} RateEstimationOptions;
+
+typedef enum {
+  INTEREST_OUTPUT = 401,
+  INTEREST_RETRANSMISSION = 402,
+  INTEREST_EXPIRED = 403,
+  INTEREST_SATISFIED = 404,
+  CONTENT_OBJECT_INPUT = 411,
+  MANIFEST_INPUT = 412,
+  CONTENT_OBJECT_TO_VERIFY = 413,
+  CONTENT_RETRIEVED = 414,
+  TIMER_EXPIRES = 415
+} ConsumerCallbacksOptions;
+
+typedef enum {
+  INTEREST_INPUT = 501,
+  INTEREST_DROP = 502,
+  INTEREST_PASS = 503,
+  CACHE_HIT = 506,
+  CACHE_MISS = 508,
+  NEW_CONTENT_OBJECT = 509,
+  CONTENT_OBJECT_SIGN = 513,
+  CONTENT_OBJECT_READY = 510,
+  CONTENT_OBJECT_OUTPUT = 511,
+  CONTENT_PRODUCED = 512
+} ProducerCallbacksOptions;
+
+typedef enum { OUTPUT_INTERFACE = 601 } DataLinkOptions;
+
+typedef enum { VIRTUAL_DOWNLOAD = 601, USE_CFG_FILE = 603 } OtherOptions;
+
+typedef enum {
+  SHA_256 = 701,
+  RSA_256 = 702,
+} SignatureType;
+
+}  // namespace interface
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.cc b/libtransport/src/hicn/transport/interfaces/socket_producer.cc
new file mode 100755 (executable)
index 0000000..69adc2b
--- /dev/null
@@ -0,0 +1,948 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_producer.h>
+
+namespace transport {
+
+namespace interface {
+
+typedef std::chrono::time_point<std::chrono::steady_clock> Time;
+typedef std::chrono::microseconds TimeDuration;
+
+ProducerSocket::ProducerSocket() : ProducerSocket(internal_io_service_) {}
+
+ProducerSocket::ProducerSocket(asio::io_service &io_service)
+    : io_service_(io_service),
+      portal_(std::make_shared<Portal>(io_service_)),
+      data_packet_size_(default_values::content_object_packet_size),
+      content_object_expiry_time_(default_values::content_object_expiry_time),
+      output_buffer_(default_values::producer_socket_output_buffer_size),
+      async_thread_(),
+      registration_status_(REGISTRATION_NOT_ATTEMPTED),
+      making_manifest_(false),
+      signature_type_(SHA_256),
+      hash_algorithm_(HashAlgorithm::SHA_256),
+      input_buffer_capacity_(default_values::producer_socket_input_buffer_size),
+      input_buffer_size_(0),
+      processing_thread_stop_(false),
+      listening_thread_stop_(false),
+      on_interest_input_(VOID_HANDLER),
+      on_interest_dropped_input_buffer_(VOID_HANDLER),
+      on_interest_inserted_input_buffer_(VOID_HANDLER),
+      on_interest_satisfied_output_buffer_(VOID_HANDLER),
+      on_interest_process_(VOID_HANDLER),
+      on_new_segment_(VOID_HANDLER),
+      on_content_object_to_sign_(VOID_HANDLER),
+      on_content_object_in_output_buffer_(VOID_HANDLER),
+      on_content_object_output_(VOID_HANDLER),
+      on_content_object_evicted_from_output_buffer_(VOID_HANDLER),
+      on_content_produced_(VOID_HANDLER) {
+  listening_thread_stop_ = false;
+}
+
+ProducerSocket::~ProducerSocket() {
+  TRANSPORT_LOGI("Destroying the ProducerSocket");
+  processing_thread_stop_ = true;
+  portal_->stopEventsLoop();
+
+  if (processing_thread_.joinable()) {
+    processing_thread_.join();
+  }
+
+  if (listening_thread_.joinable()) {
+    listening_thread_.join();
+  }
+}
+
+void ProducerSocket::connect() {
+  portal_->connect(false);
+  listening_thread_ = std::thread(std::bind(&ProducerSocket::listen, this));
+}
+
+void ProducerSocket::serveForever() {
+  if (listening_thread_.joinable()) {
+    listening_thread_.join();
+  }
+}
+
+void ProducerSocket::stop() {
+  TRANSPORT_LOGI("Calling stop for ProducerSocket");
+  portal_->killConnection();
+  portal_->stopEventsLoop();
+}
+
+void ProducerSocket::registerPrefix(const Prefix &producer_namespace) {
+  served_namespaces_.push_back(producer_namespace);
+}
+
+void ProducerSocket::listen() {
+  registration_status_ = REGISTRATION_IN_PROGRESS;
+  bool first = true;
+
+  for (core::Prefix &producer_namespace : served_namespaces_) {
+    if (first) {
+      core::BindConfig bind_config(producer_namespace, 1000);
+      portal_->bind(bind_config);
+      portal_->setProducerCallback(this);
+      first = !first;
+    } else {
+      portal_->registerRoute(producer_namespace);
+    }
+  }
+
+  portal_->runEventsLoop();
+}
+
+void ProducerSocket::passContentObjectToCallbacks(
+    const std::shared_ptr<ContentObject> &content_object) {
+  if (content_object) {
+    if (on_new_segment_ != VOID_HANDLER) {
+      on_new_segment_(*this, *content_object);
+    }
+
+    if (on_content_object_to_sign_ != VOID_HANDLER) {
+      on_content_object_to_sign_(*this, *content_object);
+    }
+
+    if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
+      on_content_object_in_output_buffer_(*this, *content_object);
+    }
+
+    output_buffer_.insert(content_object);
+
+    if (on_content_object_output_ != VOID_HANDLER) {
+      on_content_object_output_(*this, *content_object);
+    }
+
+#ifndef PUSH_API
+    std::unordered_map<Name, std::shared_ptr<const Interest>>::iterator it;
+
+    {
+      std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+      it = pending_interests_.find(content_object->getName());
+    }
+
+    if (it != pending_interests_.end()) {
+      content_object->setLocator(it->second->getLocator());
+      portal_->sendContentObject(*content_object);
+      std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+      pending_interests_.erase(it);
+    }
+#else
+    portal_->sendContentObject(*content_object);
+#endif
+  }
+}
+
+void ProducerSocket::produce(ContentObject &content_object) {
+  if (on_content_object_in_output_buffer_ != VOID_HANDLER) {
+    on_content_object_in_output_buffer_(*this, content_object);
+  }
+
+  output_buffer_.insert(std::static_pointer_cast<ContentObject>(
+      content_object.shared_from_this()));
+
+  if (on_content_object_output_ != VOID_HANDLER) {
+    on_content_object_output_(*this, content_object);
+  }
+
+#ifndef PUSH_API
+  std::unordered_map<Name, std::shared_ptr<const Interest>>::iterator it;
+
+  {
+    std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+    it = pending_interests_.find(content_object.getName());
+  }
+
+  if (it != pending_interests_.end()) {
+    content_object.setLocator(it->second->getLocator());
+    portal_->sendContentObject(content_object);
+    std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+    pending_interests_.erase(it);
+  }
+#else
+  portal_->sendContentObject(content_object);
+#endif
+}
+
+uint32_t ProducerSocket::produce(Name content_name, const uint8_t *buf,
+                                 size_t buffer_size, bool is_last,
+                                 uint32_t start_offset) {
+  if (TRANSPORT_EXPECT_FALSE(buffer_size == 0)) {
+    return 0;
+  }
+
+  const std::size_t hash_size = 32;
+
+  int bytes_segmented = 0;
+  std::size_t header_size;
+  std::size_t manifest_header_size = 0;
+  std::size_t signature_length = 0;
+  std::uint32_t final_block_number = 0;
+
+  uint64_t free_space_for_content = 0;
+
+  core::Packet::Format format;
+
+  uint32_t current_segment = start_offset;
+  std::shared_ptr<ContentObjectManifest> manifest;
+  bool is_last_manifest = false;
+  std::unique_ptr<utils::CryptoHash> zero_hash;
+
+  // TODO Manifest may still be used for indexing
+  if (making_manifest_ && !identity_) {
+    throw errors::RuntimeException(
+        "Making manifests without setting producer identity. Aborting.");
+  }
+
+  core::Packet::Format hf_format = core::Packet::Format::HF_UNSPEC;
+  core::Packet::Format hf_format_ah = core::Packet::Format::HF_UNSPEC;
+  if (content_name.getType() == HNT_CONTIGUOUS_V4 ||
+      content_name.getType() == HNT_IOV_V4) {
+    hf_format = core::Packet::Format::HF_INET_TCP;
+    hf_format_ah = core::Packet::Format::HF_INET_TCP_AH;
+  } else if (content_name.getType() == HNT_CONTIGUOUS_V6 ||
+             content_name.getType() == HNT_IOV_V6) {
+    hf_format = core::Packet::Format::HF_INET6_TCP;
+    hf_format_ah = core::Packet::Format::HF_INET6_TCP_AH;
+  } else {
+    throw errors::RuntimeException("Unknown name format.");
+  }
+
+  format = hf_format;
+  if (making_manifest_) {
+    format = hf_format;
+    manifest_header_size = core::Packet::getHeaderSizeFromFormat(
+        hf_format_ah, identity_->getSignatureLength());
+  } else if (identity_) {
+    format = hf_format_ah;
+    signature_length = identity_->getSignatureLength();
+  }
+
+  header_size = core::Packet::getHeaderSizeFromFormat(format, signature_length);
+
+  free_space_for_content = data_packet_size_ - header_size;
+
+  uint32_t number_of_segments =
+      uint32_t(std::ceil(double(buffer_size) / double(free_space_for_content)));
+
+  if (free_space_for_content * number_of_segments < buffer_size) {
+    number_of_segments++;
+  }
+
+  if (making_manifest_) {
+    auto segment_in_manifest = static_cast<float>(
+        std::floor(double(data_packet_size_ - manifest_header_size -
+                          ContentObjectManifest::getManifestHeaderSize()) /
+                   (4.0 + 32.0)) -
+        1.0);
+    auto number_of_manifests = static_cast<uint32_t>(
+        std::ceil(float(number_of_segments) / segment_in_manifest));
+    final_block_number = number_of_segments + number_of_manifests - 1;
+
+    manifest.reset(ContentObjectManifest::createManifest(
+        content_name.setSuffix(current_segment++),
+        core::ManifestVersion::VERSION_1, core::ManifestType::INLINE_MANIFEST,
+        hash_algorithm_, is_last_manifest, content_name,
+        core::NextSegmentCalculationStrategy::INCREMENTAL,
+        identity_->getSignatureLength()));
+    manifest->setLifetime(content_object_expiry_time_);
+
+    if (is_last) {
+      manifest->setFinalBlockNumber(final_block_number);
+    } else {
+      manifest->setFinalBlockNumber(std::numeric_limits<uint32_t>::max());
+    }
+
+    uint8_t hash[hash_size];
+    std::memset(hash, 0, hash_size);
+    zero_hash = std::make_unique<utils::CryptoHash>(
+        hash, hash_size, static_cast<utils::CryptoHashType>(hash_algorithm_));
+  }
+
+  for (unsigned int packaged_segments = 0;
+       packaged_segments < number_of_segments; packaged_segments++) {
+    if (making_manifest_) {
+      if (manifest->estimateManifestSize(2) >
+          data_packet_size_ - manifest_header_size) {
+        // Add next manifest
+        manifest->addSuffixHash(current_segment, *zero_hash);
+
+        // Send the current manifest
+        manifest->encode();
+
+        identity_->getSigner().sign(*manifest);
+
+        passContentObjectToCallbacks(manifest);
+
+        // Create new manifest. The reference to the last manifest has been
+        // acquired in the passContentObjectToCallbacks function, so we can
+        // safely release this reference
+        manifest.reset(ContentObjectManifest::createManifest(
+            content_name.setSuffix(current_segment),
+            core::ManifestVersion::VERSION_1,
+            core::ManifestType::INLINE_MANIFEST, hash_algorithm_,
+            is_last_manifest, content_name,
+            core::NextSegmentCalculationStrategy::INCREMENTAL,
+            identity_->getSignatureLength()));
+        manifest->setLifetime(content_object_expiry_time_);
+        if (is_last) {
+          manifest->setFinalBlockNumber(final_block_number);
+        } else {
+          manifest->setFinalBlockNumber(std::numeric_limits<uint32_t>::max());
+        }
+        current_segment++;
+      }
+    }
+
+    auto content_object = std::make_shared<ContentObject>(
+        content_name.setSuffix(current_segment), format);
+    content_object->setLifetime(content_object_expiry_time_);
+
+    if (!making_manifest_ && identity_) {
+      content_object->setSignatureSize(signature_length);
+    }
+
+    if (packaged_segments == number_of_segments - 1) {
+      content_object->appendPayload(&buf[bytes_segmented],
+                                    buffer_size - bytes_segmented);
+      bytes_segmented += buffer_size - bytes_segmented;
+
+      if (is_last && making_manifest_) {
+        is_last_manifest = true;
+      } else if (is_last) {
+        content_object->setRst();
+      }
+
+    } else {
+      content_object->appendPayload(&buf[bytes_segmented],
+                                    free_space_for_content);
+      bytes_segmented += free_space_for_content;
+    }
+
+    if (making_manifest_) {
+      using namespace std::chrono_literals;
+      utils::CryptoHash hash = content_object->computeDigest(hash_algorithm_);
+      manifest->addSuffixHash(current_segment, hash);
+    } else if (identity_) {
+      identity_->getSigner().sign(*content_object);
+    }
+
+    current_segment++;
+    passContentObjectToCallbacks(content_object);
+  }
+
+  if (making_manifest_) {
+    if (is_last_manifest) {
+      manifest->setFinalManifest(is_last_manifest);
+    }
+    manifest->encode();
+    //  Time t0 = std::chrono::steady_clock::now();
+    identity_->getSigner().sign(*manifest);
+    passContentObjectToCallbacks(manifest);
+  }
+
+  if (on_content_produced_ != VOID_HANDLER) {
+    on_content_produced_(*this, std::make_error_code(std::errc(0)),
+                         buffer_size);
+  }
+
+  return current_segment;
+}
+
+void ProducerSocket::asyncProduce(ContentObject &content_object) {
+  if (!async_thread_.stopped()) {
+    // async_thread_.add(std::bind(&ProducerSocket::produce, this,
+    // content_object));
+  }
+}
+
+// void ProducerSocket::asyncProduce(const Name &suffix,
+//                                   const uint8_t *buf,
+//                                   size_t buffer_size,
+//                                   AsyncProduceCallback && handler) {
+//   if (!async_thread_.stopped()) {
+//     async_thread_.add([this, buffer = buf, size = buffer_size, cb =
+//     std::move(handler)] () {
+//       uint64_t bytes_written = produce(suff, buffer, size, 0, false);
+//       auto ec = std::make_errc(0);
+//       cb(*this, ec, bytes_written);
+//     });
+//   }
+// }
+
+void ProducerSocket::asyncProduce(const Name &suffix, const uint8_t *buf,
+                                  size_t buffer_size) {
+  if (!async_thread_.stopped()) {
+    async_thread_.add(
+        [this, suff = suffix, buffer = buf, size = buffer_size]() {
+          produce(suff, buffer, size, true);
+        });
+  }
+}
+
+void ProducerSocket::asyncProduce(
+    const Name &suffix, utils::SharableVector<uint8_t> &&output_buffer) {
+  if (!async_thread_.stopped()) {
+    async_thread_.add(
+        [this, suff = suffix, buffer = std::move(output_buffer)]() {
+          TRANSPORT_LOGI("FOR REAL!!!!!! --> Producing content with name %s",
+                         suff.toString().c_str());
+          produce(suff, &buffer[0], buffer.size(), true);
+        });
+  }
+}
+
+void ProducerSocket::onInterest(const Interest &interest) {
+  if (on_interest_input_ != VOID_HANDLER) {
+    on_interest_input_(*this, interest);
+  }
+
+  const std::shared_ptr<ContentObject> content_object =
+      output_buffer_.find(interest);
+
+  if (content_object) {
+    if (on_interest_satisfied_output_buffer_ != VOID_HANDLER) {
+      on_interest_satisfied_output_buffer_(*this, interest);
+    }
+
+    if (on_content_object_output_ != VOID_HANDLER) {
+      on_content_object_output_(*this, *content_object);
+    }
+
+    portal_->sendContentObject(*content_object);
+  } else {
+#ifndef PUSH_API
+    {
+      std::lock_guard<std::mutex> lock(pending_interests_mtx_);
+      pending_interests_[interest.getName()] =
+          std::static_pointer_cast<const Interest>(interest.shared_from_this());
+    }
+#endif
+
+    if (on_interest_process_ != VOID_HANDLER) {
+      //  external_io_service_.post([this, &interest] () {
+      on_interest_process_(*this, interest);
+      //  });
+    }
+  }
+}
+
+asio::io_service &ProducerSocket::getIoService() { return io_service_; }
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    uint32_t socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::DATA_PACKET_SIZE:
+      if (socket_option_value < default_values::max_content_object_size &&
+          socket_option_value > 0) {
+        data_packet_size_ = socket_option_value;
+        return SOCKET_OPTION_SET;
+      } else {
+        return SOCKET_OPTION_NOT_SET;
+      }
+
+    case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+      if (socket_option_value >= 1) {
+        input_buffer_capacity_ = socket_option_value;
+        return SOCKET_OPTION_SET;
+      } else {
+        return SOCKET_OPTION_NOT_SET;
+      }
+
+    case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+      output_buffer_.setLimit(socket_option_value);
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+      content_object_expiry_time_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case GeneralTransportOptions::SIGNATURE_TYPE:
+      if (socket_option_value == SOCKET_OPTION_DEFAULT) {
+        signature_type_ = SHA_256;
+      } else {
+        signature_type_ = socket_option_value;
+      }
+
+      if (signature_type_ == SHA_256 || signature_type_ == RSA_256) {
+        signature_size_ = 32;
+      }
+
+    case ProducerCallbacksOptions::INTEREST_INPUT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_input_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::INTEREST_DROP:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_dropped_input_buffer_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::INTEREST_PASS:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_inserted_input_buffer_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::CACHE_HIT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_satisfied_output_buffer_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::CACHE_MISS:
+      if (socket_option_value == VOID_HANDLER) {
+        on_interest_process_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_new_segment_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+      if (socket_option_value == VOID_HANDLER) {
+        on_content_object_to_sign_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+      if (socket_option_value == VOID_HANDLER) {
+        on_content_object_in_output_buffer_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+      if (socket_option_value == VOID_HANDLER) {
+        on_content_object_output_ = VOID_HANDLER;
+        return SOCKET_OPTION_SET;
+      }
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    double socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    bool socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::MAKE_MANIFEST:
+      making_manifest_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    Name socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    std::list<Prefix> socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::NETWORK_NAME:
+      served_namespaces_ = socket_option_value;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+
+  return SOCKET_OPTION_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ProducerContentObjectCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+      on_new_segment_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+      on_content_object_to_sign_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+      on_content_object_in_output_buffer_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+      on_content_object_output_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ProducerInterestCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::INTEREST_INPUT:
+      on_interest_input_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::INTEREST_DROP:
+      on_interest_dropped_input_buffer_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::INTEREST_PASS:
+      on_interest_inserted_input_buffer_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::CACHE_HIT:
+      on_interest_satisfied_output_buffer_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    case ProducerCallbacksOptions::CACHE_MISS:
+      on_interest_process_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ProducerContentCallback socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::CONTENT_PRODUCED:
+      on_content_produced_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ConsumerContentObjectCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key,
+    ConsumerContentObjectVerificationCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ConsumerInterestCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ConsumerContentCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, ConsumerManifestCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    HashAlgorithm socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::HASH_ALGORITHM:
+      hash_algorithm_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    utils::CryptoSuite socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::CRYPTO_SUITE:
+      crypto_suite_ = socket_option_value;
+      return SOCKET_OPTION_SET;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key, const utils::Identity &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::IDENTITY:
+      identity_.reset();
+      identity_ = std::make_unique<utils::Identity>(socket_option_value);
+      return SOCKET_OPTION_SET;
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    const std::string &socket_option_value) {
+  switch (socket_option_key) {
+    case DataLinkOptions::OUTPUT_INTERFACE:
+      output_interface_ = socket_option_value;
+      portal_->setOutputInterface(output_interface_);
+      return SOCKET_OPTION_SET;
+  }
+
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::setSocketOption(
+    int socket_option_key,
+    interface::ConsumerTimerCallback socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    uint32_t &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::INPUT_BUFFER_SIZE:
+      socket_option_value = input_buffer_capacity_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::OUTPUT_BUFFER_SIZE:
+      socket_option_value = output_buffer_.getLimit();
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::DATA_PACKET_SIZE:
+      socket_option_value = data_packet_size_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME:
+      socket_option_value = content_object_expiry_time_;
+      return SOCKET_OPTION_GET;
+
+    case GeneralTransportOptions::SIGNATURE_TYPE:
+      socket_option_value = signature_type_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    double &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    bool &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::MAKE_MANIFEST:
+      socket_option_value = making_manifest_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    Name &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    std::list<Prefix> &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::NETWORK_NAME:
+
+      socket_option_value = served_namespaces_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ProducerContentObjectCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::NEW_CONTENT_OBJECT:
+      socket_option_value = on_new_segment_;
+      return SOCKET_OPTION_GET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_SIGN:
+      socket_option_value = on_content_object_to_sign_;
+      return SOCKET_OPTION_GET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_READY:
+      socket_option_value = on_content_object_in_output_buffer_;
+      return SOCKET_OPTION_GET;
+
+    case ProducerCallbacksOptions::CONTENT_OBJECT_OUTPUT:
+      socket_option_value = on_content_object_output_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ProducerContentCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::CONTENT_PRODUCED:
+      socket_option_value = on_content_produced_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ProducerInterestCallback &socket_option_value) {
+  switch (socket_option_key) {
+    case ProducerCallbacksOptions::INTEREST_INPUT:
+      socket_option_value = on_interest_input_;
+      return SOCKET_OPTION_GET;
+
+    case ProducerCallbacksOptions::INTEREST_DROP:
+      socket_option_value = on_interest_dropped_input_buffer_;
+      return SOCKET_OPTION_GET;
+
+    case ProducerCallbacksOptions::INTEREST_PASS:
+      socket_option_value = on_interest_inserted_input_buffer_;
+      return SOCKET_OPTION_GET;
+
+    case CACHE_HIT:
+      socket_option_value = on_interest_satisfied_output_buffer_;
+      return SOCKET_OPTION_GET;
+
+    case CACHE_MISS:
+      socket_option_value = on_interest_process_;
+      return SOCKET_OPTION_GET;
+
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ConsumerContentObjectCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key,
+    ConsumerContentObjectVerificationCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ConsumerInterestCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ConsumerContentCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, ConsumerManifestCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key, std::shared_ptr<Portal> &socket_option_value) {
+  switch (socket_option_key) {
+    case PORTAL:
+      socket_option_value = portal_;
+      return SOCKET_OPTION_GET;
+  }
+
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    IcnObserver **socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::setSocketOption(int socket_option_key,
+                                    IcnObserver *socket_option_value) {
+  return SOCKET_OPTION_NOT_SET;
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    HashAlgorithm &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::HASH_ALGORITHM:
+      socket_option_value = hash_algorithm_;
+      return SOCKET_OPTION_GET;
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    utils::CryptoSuite &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::HASH_ALGORITHM:
+      socket_option_value = crypto_suite_;
+      return SOCKET_OPTION_GET;
+    default:
+      return SOCKET_OPTION_NOT_GET;
+  }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    utils::Identity &socket_option_value) {
+  switch (socket_option_key) {
+    case GeneralTransportOptions::IDENTITY:
+      if (identity_) {
+        socket_option_value = *identity_;
+        return SOCKET_OPTION_SET;
+      }
+    default:
+      return SOCKET_OPTION_NOT_SET;
+  }
+}
+
+int ProducerSocket::getSocketOption(int socket_option_key,
+                                    std::string &socket_option_value) {
+  switch (socket_option_key) {
+    case DataLinkOptions::OUTPUT_INTERFACE:
+      socket_option_value = output_interface_;
+      return SOCKET_OPTION_GET;
+  }
+
+  return SOCKET_OPTION_NOT_GET;
+}
+
+int ProducerSocket::getSocketOption(
+    int socket_option_key,
+    interface::ConsumerTimerCallback &socket_option_value) {
+  return SOCKET_OPTION_NOT_GET;
+}
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/interfaces/socket_producer.h b/libtransport/src/hicn/transport/interfaces/socket_producer.h
new file mode 100755 (executable)
index 0000000..06c47d9
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket.h>
+#include <hicn/transport/utils/content_store.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <atomic>
+#include <cmath>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#define PUSH_API 1
+
+#define REGISTRATION_NOT_ATTEMPTED 0
+#define REGISTRATION_SUCCESS 1
+#define REGISTRATION_FAILURE 2
+#define REGISTRATION_IN_PROGRESS 3
+
+namespace transport {
+
+namespace interface {
+
+using namespace core;
+
+class ProducerSocket : public Socket<BasePortal>,
+                       public BasePortal::ProducerCallback {
+ public:
+  explicit ProducerSocket();
+  explicit ProducerSocket(asio::io_service &io_service);
+
+  ~ProducerSocket();
+
+  void connect() override;
+
+  uint32_t produce(Name content_name, const uint8_t *buffer, size_t buffer_size,
+                   bool is_last = true, uint32_t start_offset = 0);
+
+  void produce(ContentObject &content_object);
+
+  void asyncProduce(const Name &suffix, const uint8_t *buf, size_t buffer_size);
+
+  void asyncProduce(const Name &suffix,
+                    utils::SharableVector<uint8_t> &&output_buffer);
+
+  void asyncProduce(ContentObject &content_object);
+
+  void registerPrefix(const Prefix &producer_namespace);
+
+  void serveForever();
+
+  void stop();
+
+  asio::io_service &getIoService() override;
+
+  virtual void onInterest(const Interest &interest);
+
+  virtual void onInterest(Interest::Ptr &&interest) override {
+    onInterest(*interest);
+  };
+
+  int setSocketOption(int socket_option_key,
+                      uint32_t socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      double socket_option_value) override;
+
+  int setSocketOption(int socket_option_key, bool socket_option_value) override;
+
+  int setSocketOption(int socket_option_key, Name socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      std::list<Prefix> socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ProducerInterestCallback socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback socket_option_value) override;
+
+  int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerInterestCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerContentCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerManifestCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key, IcnObserver *obs) override;
+
+  int setSocketOption(int socket_option_key,
+                      HashAlgorithm socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      utils::CryptoSuite socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      const utils::Identity &socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      const std::string &socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ConsumerTimerCallback socket_option_value) override;
+
+  int setSocketOption(int socket_option_key,
+                      ProducerContentCallback socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      uint32_t &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      double &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      bool &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      Name &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::list<Prefix> &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ProducerInterestCallback &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback &socket_option_value) override;
+
+  int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerInterestCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerContentCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerManifestCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::shared_ptr<Portal> &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      IcnObserver **socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      HashAlgorithm &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      utils::CryptoSuite &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      utils::Identity &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      std::string &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ProducerContentCallback &socket_option_value) override;
+
+  int getSocketOption(int socket_option_key,
+                      ConsumerTimerCallback &socket_option_value) override;
+
+ protected:
+  asio::io_service internal_io_service_;
+  asio::io_service &io_service_;
+  std::shared_ptr<Portal> portal_;
+  std::size_t data_packet_size_;
+  std::list<Prefix> served_namespaces_;
+  uint32_t content_object_expiry_time_;
+
+  // buffers
+  utils::ContentStore output_buffer_;
+
+ private:
+  utils::EventThread async_thread_;
+
+  int registration_status_;
+
+  bool making_manifest_;
+
+  // map for storing sequence numbers for several calls of the publish function
+  std::unordered_map<Name, std::unordered_map<int, uint32_t>> seq_number_map_;
+
+  int signature_type_;
+  int signature_size_;
+
+  HashAlgorithm hash_algorithm_;
+  utils::CryptoSuite crypto_suite_;
+  std::unique_ptr<utils::Identity> identity_;
+  // utils::Signer& signer_;
+
+  // buffers
+
+  std::queue<std::shared_ptr<const Interest>> input_buffer_;
+  std::atomic_size_t input_buffer_capacity_;
+  std::atomic_size_t input_buffer_size_;
+
+#ifndef PUSH_API
+  std::mutex pending_interests_mtx_;
+  std::unordered_map<Name, std::shared_ptr<const Interest>> pending_interests_;
+#endif
+
+  // threads
+  std::thread listening_thread_;
+  std::thread processing_thread_;
+  volatile bool processing_thread_stop_;
+  volatile bool listening_thread_stop_;
+
+  // callbacks
+ protected:
+  ProducerInterestCallback on_interest_input_;
+  ProducerInterestCallback on_interest_dropped_input_buffer_;
+  ProducerInterestCallback on_interest_inserted_input_buffer_;
+  ProducerInterestCallback on_interest_satisfied_output_buffer_;
+  ProducerInterestCallback on_interest_process_;
+
+  ProducerContentObjectCallback on_new_segment_;
+  ProducerContentObjectCallback on_content_object_to_sign_;
+  ProducerContentObjectCallback on_content_object_in_output_buffer_;
+  ProducerContentObjectCallback on_content_object_output_;
+  ProducerContentObjectCallback on_content_object_evicted_from_output_buffer_;
+
+  ProducerContentCallback on_content_produced_;
+
+ private:
+  void listen();
+
+  void passContentObjectToCallbacks(
+      const std::shared_ptr<ContentObject> &content_object);
+};
+
+}  // namespace interface
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/portability/CMakeLists.txt b/libtransport/src/hicn/transport/portability/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..eee973c
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/c_portability.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/portability.h
+)
+
+list(APPEND SOURCE_FILES
+  ""
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/portability/c_portability.h b/libtransport/src/hicn/transport/portability/c_portability.h
new file mode 100755 (executable)
index 0000000..71e976a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, 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.
+ */
+
+#pragma once
+
+// noinline
+#ifdef _MSC_VER
+#define TRANSPORT_NOINLINE __declspec(noinline)
+#elif defined(__clang__) || defined(__GNUC__)
+#define TRANSPORT_NOINLINE __attribute__((__noinline__))
+#else
+#define TRANSPORT_NOINLINE
+#endif
+
+// always inline
+#ifdef _MSC_VER
+#define TRANSPORT_ALWAYS_INLINE __forceinline
+#elif defined(__clang__) || defined(__GNUC__)
+#define TRANSPORT_ALWAYS_INLINE inline __attribute__((__always_inline__))
+#else
+#define TRANSPORT_ALWAYS_INLINE inline
+#endif
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/portability/portability.h b/libtransport/src/hicn/transport/portability/portability.h
new file mode 100755 (executable)
index 0000000..7063e18
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/c_portability.h>
+
+#include <string.h>
+#include <cstddef>
+
+namespace portability {
+
+constexpr bool little_endian_arch = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;
+constexpr bool big_endian_arch = !little_endian_arch;
+
+#if defined(__GNUC__)
+#define _TRANSPORT_GNU_DISABLE_WARNING(warning) #warning
+#define TRANSPORT_GNU_DISABLE_WARNING(warning) \
+  _Pragma(_TRANSPORT_GNU_DISABLE_WARNING(GCC diagnostic ignored warning))
+
+#ifdef __clang__
+#define TRANSPORT_CLANG_DISABLE_WARNING(warning) \
+  TRANSPORT_GNU_DISABLE_WARNING(warning)
+#define TRANSPORT_GCC_DISABLE_WARNING(warning)
+#else
+#define TRANSPORT_CLANG_DISABLE_WARNING(warning)
+#define TRANSPORT_GCC_DISABLE_WARNING(warning) \
+  TRANSPORT_GNU_DISABLE_WARNING(warning)
+#endif
+#endif
+
+}  // namespace portability
diff --git a/libtransport/src/hicn/transport/protocols/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1c3b76c
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/download_observer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/vegas.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/vegas_rto_estimator.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/cbr.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.h
+)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/vegas.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/protocol.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/raaqm.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/vegas_rto_estimator.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/rate_estimation.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/raaqm_data_path.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/cbr.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/rtc_data_path.cc
+)
+
+set(TRANSPORT_CONFIG
+  ${CMAKE_CURRENT_SOURCE_DIR}/consumer.conf
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/cbr.cc b/libtransport/src/hicn/transport/protocols/cbr.cc
new file mode 100755 (executable)
index 0000000..3da4819
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/cbr.h>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+CbrTransportProtocol::CbrTransportProtocol(BaseSocket *icnet_socket)
+    : VegasTransportProtocol(icnet_socket) {}
+
+void CbrTransportProtocol::start(
+    utils::SharableVector<uint8_t> &receive_buffer) {
+  current_window_size_ = socket_->current_window_size_;
+  VegasTransportProtocol::start(receive_buffer);
+}
+
+void CbrTransportProtocol::changeInterestLifetime(uint64_t segment) { return; }
+
+void CbrTransportProtocol::increaseWindow() {}
+
+void CbrTransportProtocol::decreaseWindow() {}
+
+void CbrTransportProtocol::afterDataUnsatisfied(uint64_t segment) {}
+
+void CbrTransportProtocol::afterContentReception(
+    const Interest &interest, const ContentObject &content_object) {}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/cbr.h b/libtransport/src/hicn/transport/protocols/cbr.h
new file mode 100755 (executable)
index 0000000..0a57229
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/protocols/raaqm_data_path.h>
+#include <hicn/transport/protocols/rate_estimation.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+namespace transport {
+
+namespace protocol {
+
+class CbrTransportProtocol : public VegasTransportProtocol {
+ public:
+  CbrTransportProtocol(interface::BaseSocket *icnet_socket);
+
+  void start(utils::SharableVector<uint8_t> &receive_buffer) override;
+
+ private:
+  void afterContentReception(const Interest &interest,
+                             const ContentObject &content_object) override;
+
+  void afterDataUnsatisfied(uint64_t segment) override;
+
+  void increaseWindow() override;
+
+  void decreaseWindow() override;
+
+  void changeInterestLifetime(uint64_t segment) override;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/consumer.conf b/libtransport/src/hicn/transport/protocols/consumer.conf
new file mode 100755 (executable)
index 0000000..1a366f3
--- /dev/null
@@ -0,0 +1,21 @@
+; this file contais the parameters for RAAQM
+autotune = no
+lifetime = 500
+retransmissions = 128
+beta = 0.99
+drop = 0.003
+beta_wifi_ = 0.99
+drop_wifi_ = 0.6
+beta_lte_ = 0.99
+drop_lte_ = 0.003
+wifi_delay_ = 200
+lte_delay_ = 9000
+
+alpha = 0.95
+batching_parameter = 200
+
+;Choice of rate estimator:
+;0 --> an estimation each $(batching_parameter) packets
+;1 --> an estimation "a la TCP", estimation at the end of the download of the segment
+
+rate_estimator = 0
diff --git a/libtransport/src/hicn/transport/protocols/download_observer.h b/libtransport/src/hicn/transport/protocols/download_observer.h
new file mode 100755 (executable)
index 0000000..6d24fe6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+namespace transport {
+
+namespace protocol {
+
+class IcnObserver {
+ public:
+  virtual ~IcnObserver(){};
+
+  virtual void notifyStats(double throughput) = 0;
+  virtual void notifyDownloadTime(double downloadTime) = 0;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/protocol.cc b/libtransport/src/hicn/transport/protocols/protocol.cc
new file mode 100755 (executable)
index 0000000..ea4fd6d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/protocol.h>
+
+namespace transport {
+
+namespace protocol {
+
+TransportProtocol::TransportProtocol(interface::BaseSocket *icn_socket)
+    : socket_(dynamic_cast<interface::ConsumerSocket *>(icn_socket)),
+      is_running_(false),
+      interest_pool_() {
+  // Create pool of interests
+  increasePoolSize();
+}
+
+TransportProtocol::~TransportProtocol() {}
+
+void TransportProtocol::updatePortal() { portal_ = socket_->portal_; }
+
+bool TransportProtocol::isRunning() { return is_running_; }
+
+void TransportProtocol::increasePoolSize(std::size_t size) {
+  for (std::size_t i = 0; i < size; i++) {
+    interest_pool_.add(new Interest());
+  }
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/protocol.h b/libtransport/src/hicn/transport/protocols/protocol.h
new file mode 100755 (executable)
index 0000000..56c57e0
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket.h>
+#include <hicn/transport/utils/object_pool.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace core;
+
+class TransportProtocolCallback {
+  virtual void onContentObject(const core::Interest &interest,
+                               const core::ContentObject &content_object) = 0;
+  virtual void onTimeout(const core::Interest &interest) = 0;
+};
+
+class TransportProtocol : public interface::BasePortal::ConsumerCallback {
+  static constexpr std::size_t interest_pool_size = 4096;
+
+ public:
+  TransportProtocol(interface::BaseSocket *icn_socket);
+
+  virtual ~TransportProtocol();
+
+  void updatePortal();
+
+  bool isRunning();
+
+  virtual void start(utils::SharableVector<uint8_t> &content_buffer) = 0;
+
+  virtual void stop() = 0;
+
+  virtual void resume() = 0;
+
+ protected:
+  virtual void increasePoolSize(std::size_t size = interest_pool_size);
+
+  TRANSPORT_ALWAYS_INLINE Interest::Ptr getInterest() {
+    auto result = interest_pool_.get();
+
+    while (TRANSPORT_EXPECT_FALSE(!result.first)) {
+      // Add packets to the pool
+      increasePoolSize();
+      result = interest_pool_.get();
+    }
+
+    return std::move(result.second);
+  }
+  // Consumer Callback
+  virtual void onContentObject(Interest::Ptr &&i, ContentObject::Ptr &&c) = 0;
+  virtual void onTimeout(Interest::Ptr &&i) = 0;
+
+ protected:
+  interface::ConsumerSocket *socket_;
+  std::shared_ptr<interface::BasePortal> portal_;
+  volatile bool is_running_;
+  utils::ObjectPool<Interest> interest_pool_;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm.cc b/libtransport/src/hicn/transport/protocols/raaqm.cc
new file mode 100755 (executable)
index 0000000..cd22ecf
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/raaqm.h>
+
+#include <fstream>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RaaqmTransportProtocol::RaaqmTransportProtocol(BaseSocket *icnet_socket)
+    : VegasTransportProtocol(icnet_socket), rate_estimator_(NULL) {
+  init();
+}
+
+RaaqmTransportProtocol::~RaaqmTransportProtocol() {
+  if (this->rate_estimator_) {
+    delete this->rate_estimator_;
+  }
+}
+
+void RaaqmTransportProtocol::init() {
+  std::ifstream is(RAAQM_CONFIG_PATH);
+
+  std::string line;
+
+  socket_->beta_ = default_values::beta_value;
+  socket_->drop_factor_ = default_values::drop_factor;
+  socket_->interest_lifetime_ = default_values::interest_lifetime;
+  socket_->max_retransmissions_ =
+      default_values::transport_protocol_max_retransmissions;
+  raaqm_autotune_ = false;
+  default_beta_ = default_values::beta_value;
+  default_drop_ = default_values::drop_factor;
+  beta_wifi_ = default_values::beta_value;
+  drop_wifi_ = default_values::drop_factor;
+  beta_lte_ = default_values::beta_value;
+  drop_lte_ = default_values::drop_factor;
+  wifi_delay_ = 1000;
+  lte_delay_ = 15000;
+
+  if (!is) {
+    TRANSPORT_LOGW("WARNING: RAAQM parameters not found, set default values");
+    return;
+  }
+
+  while (getline(is, line)) {
+    std::string command;
+    std::istringstream line_s(line);
+
+    line_s >> command;
+
+    if (command == ";") {
+      continue;
+    }
+
+    if (command == "autotune") {
+      std::string tmp;
+      std::string val;
+      line_s >> tmp >> val;
+      if (val == "yes") {
+        raaqm_autotune_ = true;
+      } else {
+        raaqm_autotune_ = false;
+      }
+      continue;
+    }
+
+    if (command == "lifetime") {
+      std::string tmp;
+      uint32_t lifetime;
+      line_s >> tmp >> lifetime;
+      socket_->interest_lifetime_ = lifetime;
+      continue;
+    }
+
+    if (command == "retransmissions") {
+      std::string tmp;
+      uint32_t rtx;
+      line_s >> tmp >> rtx;
+      socket_->max_retransmissions_ = rtx;
+      continue;
+    }
+
+    if (command == "beta") {
+      std::string tmp;
+      line_s >> tmp >> default_beta_;
+      socket_->beta_ = default_beta_;
+      continue;
+    }
+
+    if (command == "drop") {
+      std::string tmp;
+      line_s >> tmp >> default_drop_;
+      socket_->drop_factor_ = default_drop_;
+      continue;
+    }
+
+    if (command == "beta_wifi_") {
+      std::string tmp;
+      line_s >> tmp >> beta_wifi_;
+      continue;
+    }
+
+    if (command == "drop_wifi_") {
+      std::string tmp;
+      line_s >> tmp >> drop_wifi_;
+      continue;
+    }
+
+    if (command == "beta_lte_") {
+      std::string tmp;
+      line_s >> tmp >> beta_lte_;
+      continue;
+    }
+
+    if (command == "drop_lte_") {
+      std::string tmp;
+      line_s >> tmp >> drop_lte_;
+      continue;
+    }
+
+    if (command == "wifi_delay_") {
+      std::string tmp;
+      line_s >> tmp >> wifi_delay_;
+      continue;
+    }
+
+    if (command == "lte_delay_") {
+      std::string tmp;
+      line_s >> tmp >> lte_delay_;
+      continue;
+    }
+    if (command == "alpha") {
+      std::string tmp;
+      double rate_alpha = 0.0;
+      line_s >> tmp >> rate_alpha;
+      socket_->rate_estimation_alpha_ = rate_alpha;
+      continue;
+    }
+
+    if (command == "batching_parameter") {
+      std::string tmp;
+      uint32_t batching_param = 0;
+      line_s >> tmp >> batching_param;
+      socket_->rate_estimation_batching_parameter_ = batching_param;
+      continue;
+    }
+
+    if (command == "rate_estimator") {
+      std::string tmp;
+      uint32_t choice_param = 0;
+      line_s >> tmp >> choice_param;
+      socket_->rate_estimation_choice_ = choice_param;
+      continue;
+    }
+  }
+  is.close();
+}
+
+void RaaqmTransportProtocol::start(
+    utils::SharableVector<uint8_t> &content_buffer) {
+  if (this->rate_estimator_) {
+    this->rate_estimator_->onStart();
+  }
+
+  if (!cur_path_) {
+    double drop_factor;
+    double minimum_drop_probability;
+    uint32_t sample_number;
+    uint32_t interest_lifetime;
+    // double beta;
+
+    drop_factor = socket_->drop_factor_;
+    minimum_drop_probability = socket_->minimum_drop_probability_;
+    sample_number = socket_->sample_number_;
+    interest_lifetime = socket_->interest_lifetime_;
+    // beta = socket_->beta_;
+
+    double alpha = 0.0;
+    uint32_t batching_param = 0;
+    uint32_t choice_param = 0;
+    alpha = socket_->rate_estimation_alpha_;
+    batching_param = socket_->rate_estimation_batching_parameter_;
+    choice_param = socket_->rate_estimation_choice_;
+
+    if (choice_param == 1) {
+      this->rate_estimator_ = new ALaTcpEstimator();
+    } else {
+      this->rate_estimator_ = new SimpleEstimator(alpha, batching_param);
+    }
+
+    this->rate_estimator_->observer_ = socket_->rate_estimation_observer_;
+
+    cur_path_ = std::make_shared<RaaqmDataPath>(
+        drop_factor, minimum_drop_probability, interest_lifetime * 1000,
+        sample_number);
+    path_table_[default_values::path_id] = cur_path_;
+  }
+
+  VegasTransportProtocol::start(content_buffer);
+}
+
+void RaaqmTransportProtocol::copyContent(const ContentObject &content_object) {
+  if (TRANSPORT_EXPECT_FALSE(
+          (content_object.getName().getSuffix() == final_block_number_) ||
+          !(is_running_))) {
+    this->rate_estimator_->onDownloadFinished();
+  }
+  VegasTransportProtocol::copyContent(content_object);
+}
+
+void RaaqmTransportProtocol::updatePathTable(
+    const ContentObject &content_object) {
+  uint32_t path_id = content_object.getPathLabel();
+
+  if (path_table_.find(path_id) == path_table_.end()) {
+    if (cur_path_) {
+      // Create a new path with some default param
+      if (path_table_.empty()) {
+        throw errors::RuntimeException(
+            "No path initialized for path table, error could be in default "
+            "path initialization.");
+      } else {
+        // Initiate the new path default param
+        std::shared_ptr<RaaqmDataPath> new_path =
+            std::make_shared<RaaqmDataPath>(
+                *(path_table_.at(default_values::path_id)));
+        // Insert the new path into hash table
+        path_table_[path_id] = new_path;
+      }
+    } else {
+      throw errors::RuntimeException(
+          "UNEXPECTED ERROR: when running,current path not found.");
+    }
+  }
+
+  cur_path_ = path_table_[path_id];
+
+  size_t header_size = content_object.headerSize();
+  size_t data_size = content_object.payloadSize();
+
+  // Update measurements for path
+  cur_path_->updateReceivedStats(header_size + data_size, data_size);
+}
+
+void RaaqmTransportProtocol::updateRtt(uint64_t segment) {
+  if (TRANSPORT_EXPECT_FALSE(!cur_path_)) {
+    throw std::runtime_error("ERROR: no current path found, exit");
+  } else {
+    std::chrono::microseconds rtt;
+
+    std::chrono::steady_clock::duration duration =
+        std::chrono::steady_clock::now() -
+        interest_timepoints_[segment & mask_];
+    rtt = std::chrono::duration_cast<std::chrono::microseconds>(duration);
+
+    if (this->rate_estimator_) {
+      this->rate_estimator_->onRttUpdate(rtt.count());
+    }
+    cur_path_->insertNewRtt(rtt.count());
+    cur_path_->smoothTimer();
+
+    if (cur_path_->newPropagationDelayAvailable()) {
+      check_drop_probability();
+    }
+  }
+}
+
+void RaaqmTransportProtocol::changeInterestLifetime(uint64_t segment) {
+  return;
+}
+
+void RaaqmTransportProtocol::check_drop_probability() {
+  if (!raaqm_autotune_) {
+    return;
+  }
+
+  unsigned int max_pd = 0;
+  std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>>::iterator it;
+  for (auto it = path_table_.begin(); it != path_table_.end(); ++it) {
+    if (it->second->getPropagationDelay() > max_pd &&
+        it->second->getPropagationDelay() != UINT_MAX &&
+        !it->second->isStale()) {
+      max_pd = it->second->getPropagationDelay();
+    }
+  }
+
+  double drop_prob = 0;
+  double beta = 0;
+  if (max_pd < wifi_delay_) {  // only ethernet paths
+    drop_prob = default_drop_;
+    beta = default_beta_;
+  } else if (max_pd < lte_delay_) {  // at least one wifi path
+    drop_prob = drop_wifi_;
+    beta = beta_wifi_;
+  } else {  // at least one lte path
+    drop_prob = drop_lte_;
+    beta = beta_lte_;
+  }
+
+  double old_drop_prob = 0;
+  double old_beta = 0;
+  old_beta = socket_->beta_;
+  old_drop_prob = socket_->drop_factor_;
+
+  if (drop_prob == old_drop_prob && beta == old_beta) {
+    return;
+  }
+
+  socket_->beta_ = beta;
+  socket_->drop_factor_ = drop_prob;
+
+  for (it = path_table_.begin(); it != path_table_.end(); it++) {
+    it->second->setDropProb(drop_prob);
+  }
+}
+
+void RaaqmTransportProtocol::check_for_stale_paths() {
+  if (!raaqm_autotune_) {
+    return;
+  }
+
+  bool stale = false;
+  std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>>::iterator it;
+  for (it = path_table_.begin(); it != path_table_.end(); ++it) {
+    if (it->second->isStale()) {
+      stale = true;
+      break;
+    }
+  }
+  if (stale) {
+    check_drop_probability();
+  }
+}
+
+void RaaqmTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+  check_for_stale_paths();
+  VegasTransportProtocol::onTimeout(std::move(interest));
+}
+
+void RaaqmTransportProtocol::increaseWindow() {
+  double max_window_size = socket_->max_window_size_;
+  if (current_window_size_ < max_window_size) {
+    double gamma = socket_->gamma_;
+
+    current_window_size_ += gamma / current_window_size_;
+    socket_->current_window_size_ = current_window_size_;
+  }
+  this->rate_estimator_->onWindowIncrease(current_window_size_);
+}
+
+void RaaqmTransportProtocol::decreaseWindow() {
+  double min_window_size = socket_->min_window_size_;
+  if (current_window_size_ > min_window_size) {
+    double beta = socket_->beta_;
+
+    current_window_size_ = current_window_size_ * beta;
+    if (current_window_size_ < min_window_size) {
+      current_window_size_ = min_window_size;
+    }
+
+    socket_->current_window_size_ = current_window_size_;
+  }
+  this->rate_estimator_->onWindowDecrease(current_window_size_);
+}
+
+void RaaqmTransportProtocol::RAAQM() {
+  if (!cur_path_) {
+    throw errors::RuntimeException("ERROR: no current path found, exit");
+    exit(EXIT_FAILURE);
+  } else {
+    // Change drop probability according to RTT statistics
+    cur_path_->updateDropProb();
+
+    if (rand() % 10000 <= cur_path_->getDropProb() * 10000) {
+      decreaseWindow();
+    }
+  }
+}
+
+void RaaqmTransportProtocol::afterDataUnsatisfied(uint64_t segment) {
+  // Decrease the window because the timeout happened
+  decreaseWindow();
+}
+
+void RaaqmTransportProtocol::afterContentReception(
+    const Interest &interest, const ContentObject &content_object) {
+  updatePathTable(content_object);
+  increaseWindow();
+  updateRtt(interest.getName().getSuffix());
+  this->rate_estimator_->onDataReceived((int)content_object.payloadSize() +
+                                        content_object.headerSize());
+  // Set drop probablility and window size accordingly
+  RAAQM();
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm.h b/libtransport/src/hicn/transport/protocols/raaqm.h
new file mode 100755 (executable)
index 0000000..6ca4102
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/protocols/raaqm_data_path.h>
+#include <hicn/transport/protocols/rate_estimation.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+namespace transport {
+
+namespace protocol {
+
+class RaaqmTransportProtocol : public VegasTransportProtocol {
+ public:
+  RaaqmTransportProtocol(interface::BaseSocket *icnet_socket);
+
+  ~RaaqmTransportProtocol();
+
+  void start(utils::SharableVector<uint8_t> &content_buffer) override;
+
+ protected:
+  void copyContent(const ContentObject &content_object) override;
+
+ private:
+  void init();
+
+  void afterContentReception(const Interest &interest,
+                             const ContentObject &content_object) override;
+
+  void afterDataUnsatisfied(uint64_t segment) override;
+
+  void increaseWindow() override;
+
+  void updateRtt(uint64_t segment);
+
+  void decreaseWindow() override;
+
+  void changeInterestLifetime(uint64_t segment) override;
+
+  void onTimeout(Interest::Ptr &&interest) override;
+
+  void RAAQM();
+
+  void updatePathTable(const ContentObject &content_object);
+
+  void check_drop_probability();
+
+  void check_for_stale_paths();
+
+  void printRtt();
+
+  /**
+   * Current download path
+   */
+  std::shared_ptr<RaaqmDataPath> cur_path_;
+
+  /**
+   * Hash table for path: each entry is a pair path ID(key) - path object
+   */
+  std::unordered_map<uint32_t, std::shared_ptr<RaaqmDataPath>> path_table_;
+
+  bool set_interest_filter_;
+  // for rate-estimation at packet level
+  IcnRateEstimator *rate_estimator_;
+
+  // params for autotuning
+  bool raaqm_autotune_;
+  double default_beta_;
+  double default_drop_;
+  double beta_wifi_;
+  double drop_wifi_;
+  double beta_lte_;
+  double drop_lte_;
+  unsigned int wifi_delay_;
+  unsigned int lte_delay_;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc b/libtransport/src/hicn/transport/protocols/raaqm_data_path.cc
new file mode 100755 (executable)
index 0000000..f876cf4
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/protocols/raaqm_data_path.h>
+
+namespace transport {
+
+namespace protocol {
+
+RaaqmDataPath::RaaqmDataPath(double drop_factor,
+                             double minimum_drop_probability,
+                             unsigned new_timer, unsigned int samples,
+                             uint64_t new_rtt, uint64_t new_rtt_min,
+                             uint64_t new_rtt_max, unsigned new_pd)
+
+    : drop_factor_(drop_factor),
+      minimum_drop_probability_(minimum_drop_probability),
+      timer_(new_timer),
+      samples_(samples),
+      rtt_(new_rtt),
+      rtt_min_(new_rtt_min),
+      rtt_max_(new_rtt_max),
+      prop_delay_(new_pd),
+      new_prop_delay_(false),
+      drop_prob_(0),
+      packets_received_(0),
+      last_packets_received_(0),
+      m_packets_bytes_received_(0),
+      last_packets_bytes_received_(0),
+      raw_data_bytes_received_(0),
+      last_raw_data_bytes_received_(0),
+      rtt_samples_(samples_),
+      average_rtt_(0),
+      alpha_(ALPHA) {
+  gettimeofday(&m_last_received_pkt_, 0);
+}
+
+RaaqmDataPath &RaaqmDataPath::insertNewRtt(uint64_t new_rtt) {
+  rtt_ = new_rtt;
+  rtt_samples_.pushBack(new_rtt);
+
+  rtt_max_ = rtt_samples_.rBegin();
+  rtt_min_ = rtt_samples_.begin();
+
+  if (rtt_min_ < prop_delay_) {
+    new_prop_delay_ = true;
+    prop_delay_ = rtt_min_;
+  }
+
+  gettimeofday(&m_last_received_pkt_, 0);
+
+  return *this;
+}
+
+RaaqmDataPath &RaaqmDataPath::updateReceivedStats(std::size_t packet_size,
+                                                  std::size_t data_size) {
+  packets_received_++;
+  m_packets_bytes_received_ += packet_size;
+  raw_data_bytes_received_ += data_size;
+
+  return *this;
+}
+
+double RaaqmDataPath::getDropFactor() { return drop_factor_; }
+
+double RaaqmDataPath::getDropProb() { return drop_prob_; }
+
+RaaqmDataPath &RaaqmDataPath::setDropProb(double dropProb) {
+  drop_prob_ = dropProb;
+
+  return *this;
+}
+
+double RaaqmDataPath::getMinimumDropProbability() {
+  return minimum_drop_probability_;
+}
+
+double RaaqmDataPath::getTimer() { return timer_; }
+
+RaaqmDataPath &RaaqmDataPath::smoothTimer() {
+  timer_ = (1 - TIMEOUT_SMOOTHER) * timer_ +
+           (TIMEOUT_SMOOTHER)*rtt_ * (TIMEOUT_RATIO);
+
+  return *this;
+}
+
+double RaaqmDataPath::getRtt() { return rtt_; }
+
+double RaaqmDataPath::getAverageRtt() { return average_rtt_; }
+
+double RaaqmDataPath::getRttMax() { return rtt_max_; }
+
+double RaaqmDataPath::getRttMin() { return rtt_min_; }
+
+unsigned RaaqmDataPath::getSampleValue() { return samples_; }
+
+unsigned RaaqmDataPath::getRttQueueSize() {
+  return static_cast<unsigned>(rtt_samples_.size());
+}
+
+RaaqmDataPath &RaaqmDataPath::updateDropProb() {
+  drop_prob_ = 0.0;
+
+  if (getSampleValue() == getRttQueueSize()) {
+    if (rtt_max_ == rtt_min_) {
+      drop_prob_ = minimum_drop_probability_;
+    } else {
+      drop_prob_ = minimum_drop_probability_ +
+                   drop_factor_ * (rtt_ - rtt_min_) / (rtt_max_ - rtt_min_);
+    }
+  }
+
+  return *this;
+}
+
+double RaaqmDataPath::getMicroSeconds(struct timeval &time) {
+  return (double)(time.tv_sec) * 1000000 + (double)(time.tv_usec);
+}
+
+void RaaqmDataPath::setAlpha(double alpha) {
+  if (alpha >= 0 && alpha <= 1) {
+    alpha_ = alpha;
+  }
+}
+
+bool RaaqmDataPath::newPropagationDelayAvailable() {
+  bool r = new_prop_delay_;
+  new_prop_delay_ = false;
+  return r;
+}
+
+unsigned int RaaqmDataPath::getPropagationDelay() { return prop_delay_; }
+
+bool RaaqmDataPath::isStale() {
+  struct timeval now;
+  gettimeofday(&now, 0);
+  double time = getMicroSeconds(now) - getMicroSeconds(m_last_received_pkt_);
+  if (time > 2000000) {
+    return true;
+  }
+  return false;
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/raaqm_data_path.h b/libtransport/src/hicn/transport/protocols/raaqm_data_path.h
new file mode 100755 (executable)
index 0000000..6f63940
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/utils/min_filter.h>
+
+#include <sys/time.h>
+#include <climits>
+#include <iostream>
+
+#define TIMEOUT_SMOOTHER 0.1
+#define TIMEOUT_RATIO 10
+#define ALPHA 0.8
+
+namespace transport {
+
+namespace protocol {
+
+class RaaqmDataPath {
+ public:
+  RaaqmDataPath(double drop_factor, double minimum_drop_probability,
+                unsigned new_timer, unsigned int samples,
+                uint64_t new_rtt = 1000, uint64_t new_rtt_min = 1000,
+                uint64_t new_rtt_max = 1000, unsigned new_pd = UINT_MAX);
+
+ public:
+  /*
+   * @brief Add a new RTT to the RTT queue of the path, check if RTT queue is
+   * full, and thus need overwrite. Also it maintains the validity of min and
+   * max of RTT.
+   * @param new_rtt is the value of the new RTT
+   */
+  RaaqmDataPath &insertNewRtt(uint64_t new_rtt);
+
+  /**
+   * @brief Update the path statistics
+   * @param packet_size the size of the packet received, including the ICN
+   * header
+   * @param data_size the size of the data received, without the ICN header
+   */
+  RaaqmDataPath &updateReceivedStats(std::size_t packet_size,
+                                     std::size_t data_size);
+
+  /**
+   * @brief Get the value of the drop factor parameter
+   */
+  double getDropFactor();
+
+  /**
+   * @brief Get the value of the drop probability
+   */
+  double getDropProb();
+
+  /**
+   * @brief Set the value pf the drop probability
+   * @param drop_prob is the value of the drop probability
+   */
+  RaaqmDataPath &setDropProb(double drop_prob);
+
+  /**
+   * @brief Get the minimum drop probability
+   */
+  double getMinimumDropProbability();
+
+  /**
+   * @brief Get last RTT
+   */
+  double getRtt();
+
+  /**
+   * @brief Get average RTT
+   */
+  double getAverageRtt();
+
+  /**
+   * @brief Get the current m_timer value
+   */
+  double getTimer();
+
+  /**
+   * @brief Smooth he value of the m_timer accordingly with the last RTT
+   * measured
+   */
+  RaaqmDataPath &smoothTimer();
+
+  /**
+   * @brief Get the maximum RTT among the last samples
+   */
+  double getRttMax();
+
+  /**
+   * @brief Get the minimum RTT among the last samples
+   */
+  double getRttMin();
+
+  /**
+   * @brief Get the number of saved samples
+   */
+  unsigned getSampleValue();
+
+  /**
+   * @brief Get the size og the RTT queue
+   */
+  unsigned getRttQueueSize();
+
+  /*
+   * @brief Change drop probability according to RTT statistics
+   *        Invoked in RAAQM(), before control window size update.
+   */
+  RaaqmDataPath &updateDropProb();
+
+  /**
+   * @brief This function convert the time from struct timeval to its value in
+   * microseconds
+   */
+  static double getMicroSeconds(struct timeval &time);
+
+  void setAlpha(double alpha);
+
+  /**
+   * @brief Returns the smallest RTT registered so far for this path
+   */
+
+  unsigned int getPropagationDelay();
+
+  bool newPropagationDelayAvailable();
+
+  bool isStale();
+
+ private:
+  /**
+   * The value of the drop factor
+   */
+  double drop_factor_;
+
+  /**
+   * The minumum drop probability
+   */
+  double minimum_drop_probability_;
+
+  /**
+   * The timer, expressed in milliseconds
+   */
+  double timer_;
+
+  /**
+   * The number of samples to store for computing the protocol measurements
+   */
+  const unsigned int samples_;
+
+  /**
+   * The last, the minimum and the maximum value of the RTT (among the last
+   * m_samples samples)
+   */
+  uint64_t rtt_, rtt_min_, rtt_max_, prop_delay_;
+
+  bool new_prop_delay_;
+
+  /**
+   * The current drop probability
+   */
+  double drop_prob_;
+
+  /**
+   * The number of packets received in this path
+   */
+  intmax_t packets_received_;
+
+  /**
+   * The first packet received after the statistics print
+   */
+  intmax_t last_packets_received_;
+
+  /**
+   * Total number of bytes received including the ICN header
+   */
+  intmax_t m_packets_bytes_received_;
+
+  /**
+   * The amount of packet bytes received at the last path summary computation
+   */
+  intmax_t last_packets_bytes_received_;
+
+  /**
+   * Total number of bytes received without including the ICN header
+   */
+  intmax_t raw_data_bytes_received_;
+
+  /**
+   * The amount of raw dat bytes received at the last path summary computation
+   */
+  intmax_t last_raw_data_bytes_received_;
+
+  class byArrival;
+
+  class byOrder;
+
+  /**
+   * Double ended queue for the RTTs
+   */
+
+  typedef utils::MinFilter<uint64_t> RTTQueue;
+
+  RTTQueue rtt_samples_;
+
+  /**
+   * Time of the last call to the path reporter method
+   */
+  struct timeval m_last_received_pkt_;
+
+  double average_rtt_;
+  double alpha_;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.cc b/libtransport/src/hicn/transport/protocols/rate_estimation.cc
new file mode 100755 (executable)
index 0000000..e313bf9
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/protocols/rate_estimation.h>
+#include <hicn/transport/utils/log.h>
+
+namespace transport {
+
+namespace protocol {
+
+void *Timer(void *data) {
+  InterRttEstimator *estimator = (InterRttEstimator *)data;
+
+  double dat_rtt, my_avg_win, my_avg_rtt;
+  int my_win_change, number_of_packets, max_packet_size;
+
+  pthread_mutex_lock(&(estimator->mutex_));
+  dat_rtt = estimator->rtt_;
+  pthread_mutex_unlock(&(estimator->mutex_));
+
+  while (estimator->is_running_) {
+    usleep(KV * dat_rtt);
+
+    pthread_mutex_lock(&(estimator->mutex_));
+
+    dat_rtt = estimator->rtt_;
+    my_avg_win = estimator->avg_win_;
+    my_avg_rtt = estimator->avg_rtt_;
+    my_win_change = estimator->win_change_;
+    number_of_packets = estimator->number_of_packets_;
+    max_packet_size = estimator->max_packet_size_;
+    estimator->avg_rtt_ = estimator->rtt_;
+    estimator->avg_win_ = 0;
+    estimator->win_change_ = 0;
+    estimator->number_of_packets_ = 1;
+
+    pthread_mutex_unlock(&(estimator->mutex_));
+
+    if (number_of_packets == 0 || my_win_change == 0) {
+      continue;
+    }
+    if (estimator->estimation_ == 0) {
+      estimator->estimation_ = (my_avg_win * 8.0 * max_packet_size * 1000000.0 /
+                                (1.0 * my_win_change)) /
+                               (my_avg_rtt / (1.0 * number_of_packets));
+    }
+
+    estimator->estimation_ =
+        estimator->alpha_ * estimator->estimation_ +
+        (1 - estimator->alpha_) * ((my_avg_win * 8.0 * max_packet_size *
+                                    1000000.0 / (1.0 * my_win_change)) /
+                                   (my_avg_rtt / (1.0 * number_of_packets)));
+
+    if (estimator->observer_) {
+      estimator->observer_->notifyStats(estimator->estimation_);
+    }
+  }
+
+  return nullptr;
+}
+
+InterRttEstimator::InterRttEstimator(double alpha_arg) {
+  this->estimated_ = false;
+  this->observer_ = NULL;
+  this->alpha_ = alpha_arg;
+  this->thread_is_running_ = false;
+  this->my_th_ = NULL;
+  this->is_running_ = true;
+  this->avg_rtt_ = 0.0;
+  this->estimation_ = 0.0;
+  this->avg_win_ = 0.0;
+  this->rtt_ = 0.0;
+  this->win_change_ = 0;
+  this->number_of_packets_ = 0;
+  this->max_packet_size_ = 0;
+  this->win_current_ = 1.0;
+
+  pthread_mutex_init(&(this->mutex_), NULL);
+  gettimeofday(&(this->start_time_), 0);
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+InterRttEstimator::~InterRttEstimator() {
+  this->is_running_ = false;
+  if (this->my_th_) {
+    pthread_join(*(this->my_th_), NULL);
+  }
+  this->my_th_ = NULL;
+  pthread_mutex_destroy(&(this->mutex_));
+}
+
+void InterRttEstimator::onRttUpdate(double rtt) {
+  pthread_mutex_lock(&(this->mutex_));
+  this->rtt_ = rtt;
+  this->number_of_packets_++;
+  this->avg_rtt_ += rtt;
+  pthread_mutex_unlock(&(this->mutex_));
+
+  if (!thread_is_running_) {
+    my_th_ = (pthread_t *)malloc(sizeof(pthread_t));
+    if (!my_th_) {
+      TRANSPORT_LOGE("Error allocating thread.");
+      my_th_ = NULL;
+    }
+    if (/*int err = */ pthread_create(my_th_, NULL, transport::protocol::Timer,
+                                      (void *)this)) {
+      TRANSPORT_LOGE("Error creating the thread");
+      my_th_ = NULL;
+    }
+    thread_is_running_ = true;
+  }
+}
+
+void InterRttEstimator::onWindowIncrease(double win_current) {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+
+  pthread_mutex_lock(&(this->mutex_));
+  this->avg_win_ += this->win_current_ * delay;
+  this->win_current_ = win_current;
+  this->win_change_ += delay;
+  pthread_mutex_unlock(&(this->mutex_));
+
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+void InterRttEstimator::onWindowDecrease(double win_current) {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+
+  pthread_mutex_lock(&(this->mutex_));
+  this->avg_win_ += this->win_current_ * delay;
+  this->win_current_ = win_current;
+  this->win_change_ += delay;
+  pthread_mutex_unlock(&(this->mutex_));
+
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+ALaTcpEstimator::ALaTcpEstimator() {
+  this->estimation_ = 0.0;
+  this->observer_ = NULL;
+  gettimeofday(&(this->start_time_), 0);
+  this->totalSize_ = 0.0;
+}
+
+void ALaTcpEstimator::onStart() {
+  this->totalSize_ = 0.0;
+  gettimeofday(&(this->start_time_), 0);
+}
+
+void ALaTcpEstimator::onDownloadFinished() {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->start_time_);
+  this->estimation_ = this->totalSize_ * 8 * 1000000 / delay;
+  if (observer_) {
+    observer_->notifyStats(this->estimation_);
+  }
+}
+
+void ALaTcpEstimator::onDataReceived(int packet_size) {
+  this->totalSize_ += packet_size;
+}
+
+SimpleEstimator::SimpleEstimator(double alphaArg, int batching_param) {
+  this->estimation_ = 0.0;
+  this->estimated_ = false;
+  this->observer_ = NULL;
+  this->batching_param_ = batching_param;
+  this->total_size_ = 0.0;
+  this->number_of_packets_ = 0;
+  this->base_alpha_ = alphaArg;
+  this->alpha_ = alphaArg;
+  gettimeofday(&(this->start_time_), 0);
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+void SimpleEstimator::onStart() {
+  this->estimated_ = false;
+  this->number_of_packets_ = 0;
+  this->total_size_ = 0.0;
+  gettimeofday(&(this->begin_batch_), 0);
+  gettimeofday(&(this->start_time_), 0);
+}
+
+void SimpleEstimator::onDownloadFinished() {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->start_time_);
+  if (observer_) {
+    observer_->notifyDownloadTime(delay);
+  }
+  if (!this->estimated_) {
+    // Assuming all packets carry max_packet_size_ bytes of data
+    // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+    if (this->estimation_) {
+      this->estimation_ =
+          alpha_ * this->estimation_ +
+          (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+    } else {
+      this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+    }
+    if (observer_) {
+      observer_->notifyStats(this->estimation_);
+    }
+    this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) /
+                                        ((double)this->batching_param_));
+  } else {
+    if (this->number_of_packets_ >=
+        (int)(75.0 * (double)this->batching_param_ / 100.0)) {
+      delay = RaaqmDataPath::getMicroSeconds(end) -
+              RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+      // Assuming all packets carry max_packet_size_ bytes of data
+      // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+      if (this->estimation_) {
+        this->estimation_ =
+            alpha_ * this->estimation_ +
+            (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+      } else {
+        this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+      }
+      if (observer_) {
+        observer_->notifyStats(this->estimation_);
+      }
+      this->alpha_ = this->base_alpha_ * (((double)this->number_of_packets_) /
+                                          ((double)this->batching_param_));
+    }
+  }
+  this->number_of_packets_ = 0;
+  this->total_size_ = 0.0;
+  gettimeofday(&(this->begin_batch_), 0);
+  gettimeofday(&(this->start_time_), 0);
+}
+
+void SimpleEstimator::onDataReceived(int packet_size) {
+  this->total_size_ += packet_size;
+}
+
+void SimpleEstimator::onRttUpdate(double rtt) {
+  this->number_of_packets_++;
+
+  if (number_of_packets_ == this->batching_param_) {
+    timeval end;
+    gettimeofday(&end, 0);
+    double delay = RaaqmDataPath::getMicroSeconds(end) -
+                   RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+    // Assuming all packets carry max_packet_size_ bytes of data
+    // (8*max_packet_size_ bits); 1000000 factor to convert us to seconds
+    if (this->estimation_) {
+      this->estimation_ =
+          alpha_ * this->estimation_ +
+          (1 - alpha_) * (total_size_ * 8 * 1000000.0 / (delay));
+    } else {
+      this->estimation_ = total_size_ * 8 * 1000000.0 / (delay);
+    }
+    if (observer_) {
+      observer_->notifyStats(this->estimation_);
+    }
+    this->alpha_ = this->base_alpha_;
+    this->number_of_packets_ = 0;
+    this->total_size_ = 0.0;
+    gettimeofday(&(this->begin_batch_), 0);
+  }
+}
+
+BatchingPacketsEstimator::BatchingPacketsEstimator(double alpha_arg,
+                                                   int param) {
+  this->estimated_ = false;
+  this->observer_ = NULL;
+  this->alpha_ = alpha_arg;
+  this->batching_param_ = param;
+  this->number_of_packets_ = 0;
+  this->avg_win_ = 0.0;
+  this->avg_rtt_ = 0.0;
+  this->win_change_ = 0.0;
+  this->max_packet_size_ = 0;
+  this->estimation_ = 0.0;
+  this->win_current_ = 1.0;
+  gettimeofday(&(this->begin_batch_), 0);
+  gettimeofday(&(this->start_time_), 0);
+}
+
+void BatchingPacketsEstimator::onRttUpdate(double rtt) {
+  this->number_of_packets_++;
+  this->avg_rtt_ += rtt;
+
+  if (number_of_packets_ == this->batching_param_) {
+    if (estimation_ == 0) {
+      estimation_ = (avg_win_ * 8.0 * max_packet_size_ * 1000000.0 /
+                     (1.0 * win_change_)) /
+                    (avg_rtt_ / (1.0 * number_of_packets_));
+    } else {
+      estimation_ = alpha_ * estimation_ +
+                    (1 - alpha_) * ((avg_win_ * 8.0 * max_packet_size_ *
+                                     1000000.0 / (1.0 * win_change_)) /
+                                    (avg_rtt_ / (1.0 * number_of_packets_)));
+    }
+
+    if (observer_) {
+      observer_->notifyStats(estimation_);
+    }
+
+    this->number_of_packets_ = 0;
+    this->avg_win_ = 0.0;
+    this->avg_rtt_ = 0.0;
+    this->win_change_ = 0.0;
+  }
+}
+
+void BatchingPacketsEstimator::onWindowIncrease(double win_current) {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+  this->avg_win_ += this->win_current_ * delay;
+  this->win_current_ = win_current;
+  this->win_change_ += delay;
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+void BatchingPacketsEstimator::onWindowDecrease(double win_current) {
+  timeval end;
+  gettimeofday(&end, 0);
+  double delay = RaaqmDataPath::getMicroSeconds(end) -
+                 RaaqmDataPath::getMicroSeconds(this->begin_batch_);
+  this->avg_win_ += this->win_current_ * delay;
+  this->win_current_ = win_current;
+  this->win_change_ += delay;
+  gettimeofday(&(this->begin_batch_), 0);
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rate_estimation.h b/libtransport/src/hicn/transport/protocols/rate_estimation.h
new file mode 100755 (executable)
index 0000000..b889efe
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+
+#include <hicn/transport/protocols/download_observer.h>
+#include <hicn/transport/protocols/raaqm_data_path.h>
+
+#define BATCH 50
+#define KV 20
+#define ALPHA 0.8
+#define RATE_CHOICE 0
+
+namespace transport {
+
+namespace protocol {
+
+class IcnRateEstimator {
+ public:
+  IcnRateEstimator(){};
+
+  virtual ~IcnRateEstimator(){};
+
+  virtual void onRttUpdate(double rtt){};
+
+  virtual void onDataReceived(int packetSize){};
+
+  virtual void onWindowIncrease(double winCurrent){};
+
+  virtual void onWindowDecrease(double winCurrent){};
+
+  virtual void onStart(){};
+
+  virtual void onDownloadFinished(){};
+
+  virtual void setObserver(IcnObserver *observer) {
+    this->observer_ = observer;
+  };
+  IcnObserver *observer_;
+  struct timeval start_time_;
+  struct timeval begin_batch_;
+  double base_alpha_;
+  double alpha_;
+  double estimation_;
+  int number_of_packets_;
+  // this boolean is to make sure at least one estimation of the BW is done
+  bool estimated_;
+};
+
+// A rate estimator RTT-based. Computes EWMA(WinSize)/EWMA(RTT)
+
+class InterRttEstimator : public IcnRateEstimator {
+ public:
+  InterRttEstimator(double alpha_arg);
+
+  ~InterRttEstimator();
+
+  void onRttUpdate(double rtt);
+
+  void onDataReceived(int packet_size) {
+    if (packet_size > this->max_packet_size_) {
+      this->max_packet_size_ = packet_size;
+    }
+  };
+
+  void onWindowIncrease(double win_current);
+
+  void onWindowDecrease(double win_current);
+
+  void onStart(){};
+
+  void onDownloadFinished(){};
+
+  // private: should be done by using getters
+  pthread_t *my_th_;
+  bool thread_is_running_;
+  double rtt_;
+  bool is_running_;
+  pthread_mutex_t mutex_;
+  double avg_rtt_;
+  double avg_win_;
+  int max_packet_size_;
+  double win_change_;
+  double win_current_;
+};
+
+// A rate estimator, Batching Packets based. Computes EWMA(WinSize)/EWMA(RTT)
+
+class BatchingPacketsEstimator : public IcnRateEstimator {
+ public:
+  BatchingPacketsEstimator(double alpha_arg, int batchingParam);
+
+  void onRttUpdate(double rtt);
+
+  void onDataReceived(int packet_size) {
+    if (packet_size > this->max_packet_size_) {
+      this->max_packet_size_ = packet_size;
+    }
+  };
+
+  void onWindowIncrease(double win_current);
+
+  void onWindowDecrease(double win_current);
+
+  void onStart(){};
+
+  void onDownloadFinished(){};
+
+ private:
+  int batching_param_;
+  double avg_rtt_;
+  double avg_win_;
+  double win_change_;
+  int max_packet_size_;
+  double win_current_;
+};
+
+// Segment Estimator
+
+class ALaTcpEstimator : public IcnRateEstimator {
+ public:
+  ALaTcpEstimator();
+
+  void onDataReceived(int packet_size);
+  void onStart();
+  void onDownloadFinished();
+
+ private:
+  double totalSize_;
+};
+
+// A Rate estimator, this one is the simplest: counting batching_param_ packets
+// and then divide the sum of the size of these packets by the time taken to DL
+// them. Should be the one used
+
+class SimpleEstimator : public IcnRateEstimator {
+ public:
+  SimpleEstimator(double alpha, int batching_param);
+
+  void onRttUpdate(double rtt);
+
+  void onDataReceived(int packet_size);
+
+  void onWindowIncrease(double win_current){};
+
+  void onWindowDecrease(double win_current){};
+
+  void onStart();
+
+  void onDownloadFinished();
+
+ private:
+  int batching_param_;
+  double total_size_;
+};
+
+void *Timer(void *data);
+
+}  // namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc.cc b/libtransport/src/hicn/transport/protocols/rtc.cc
new file mode 100755 (executable)
index 0000000..1f42cf2
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2017-2019 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 <math.h>
+
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/rtc.h>
+
+/*
+ * TODO
+ * 2) start/constructor/rest variable implementation
+ * 3) interest retransmission: now I always recover, we should recover only if
+ * we have enough time 4) returnContentToUser: rememeber to remove the first
+ * 32bits from the payload
+ */
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RTCTransportProtocol::RTCTransportProtocol(BaseSocket *icnet_socket)
+    : TransportProtocol(icnet_socket),
+      inflightInterests_(1 << default_values::log_2_default_buffer_size),
+      modMask_((1 << default_values::log_2_default_buffer_size) - 1) {
+  icnet_socket->getSocketOption(PORTAL, portal_);
+  reset();
+}
+
+RTCTransportProtocol::~RTCTransportProtocol() {
+  if (is_running_) {
+    stop();
+  }
+}
+
+void RTCTransportProtocol::start(
+    utils::SharableVector<uint8_t> &content_buffer) {
+
+  if(is_running_)
+    return;
+
+  is_running_ = true;
+  content_buffer_ = content_buffer.shared_from_this();
+
+  reset();
+  scheduleNextInterest();
+
+  portal_->runEventsLoop();
+  is_running_ = false;
+}
+
+void RTCTransportProtocol::stop() {
+  if(!is_running_)
+    return;
+
+  is_running_ = false;
+  portal_->stopEventsLoop();
+}
+
+void RTCTransportProtocol::resume(){
+    if(is_running_)
+        return;
+    
+    is_running_ = true;
+    
+    lastRoundBegin_ = std::chrono::steady_clock::now();
+    inflightInterestsCount_ = 0;
+    if(content_buffer_)
+        content_buffer_->clear();
+
+    scheduleNextInterest();
+    
+    portal_->runEventsLoop();
+
+    is_running_ = false;
+}
+
+void RTCTransportProtocol::onRTCPPacket(uint8_t *packet, size_t len) {
+  //#define MASK_RTCP_VERSION 192
+  //#define MASK_TYPE_CODE 31
+  size_t read = 0;
+  uint8_t *offset = packet;
+  while (read < len) {
+    if ((((*offset) & MASK_RTCP_VERSION) >> 6) != RTCP_VERSION) {
+      TRANSPORT_LOGE("error while parsing RTCP packet, version unkwown");
+      return;
+    }
+    processRtcpHeader(offset);
+    uint16_t RTCPlen = (ntohs(*(((uint16_t *)offset) + 1)) + 1) * 4;
+    offset += RTCPlen;
+    read += RTCPlen;
+  }
+}
+
+// private
+void RTCTransportProtocol::reset() {
+  // controller var
+  lastRoundBegin_ = std::chrono::steady_clock::now();
+  currentState_ = RTC_SYNC_STATE;
+
+  // cwin var
+  currentCWin_ = INITIAL_CWIN;
+  maxCWin_ = INITIAL_CWIN_MAX;
+
+  // names/packets var
+  actualSegment_ = 0;
+  inflightInterestsCount_ = 0;
+  while (interestRetransmissions_.size() != 0) interestRetransmissions_.pop();
+  nackedByProducer_.clear();
+  nackedByProducerMaxSize_ = 512;
+  if (content_buffer_) content_buffer_->clear();
+
+  holes_.clear();
+  lastReceived_ = 0;
+
+  // stats
+  receivedBytes_ = 0;
+  sentInterest_ = 0;
+  receivedData_ = 0;
+  packetLost_ = 0;
+  avgPacketSize_ = INIT_PACKET_SIZE;
+  gotNack_ = false;
+  gotFutureNack_ = 0;
+  roundsWithoutNacks_ = 0;
+  pathTable_.clear();
+  // roundCounter_ = 0;
+  // minRTTwin_.clear();
+  // for (int i = 0; i < MIN_RTT_WIN; i++)
+  //    minRTTwin_.push_back(UINT_MAX);
+  minRtt_ = UINT_MAX;
+
+  // CC var
+  estimatedBw_ = 0.0;
+  lossRate_ = 0.0;
+  queuingDelay_ = 0.0;
+  protocolState_ = RTC_NORMAL_STATE;
+
+  producerPathLabel_ = 0;
+  socket_->setSocketOption(
+      GeneralTransportOptions::INTEREST_LIFETIME,
+      (uint32_t)
+          RTC_INTEREST_LIFETIME);  // XXX this should bedone by the application
+}
+
+uint32_t max(uint32_t a, uint32_t b) {
+  if (a > b)
+    return a;
+  else
+    return b;
+}
+
+uint32_t min(uint32_t a, uint32_t b) {
+  if (a < b)
+    return a;
+  else
+    return b;
+}
+
+void RTCTransportProtocol::checkRound() {
+  uint32_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+                          std::chrono::steady_clock::now() - lastRoundBegin_)
+                          .count();
+  if (duration >= ROUND_LEN) {
+    lastRoundBegin_ = std::chrono::steady_clock::now();
+    updateStats(duration);  // update stats and window
+  }
+}
+
+void RTCTransportProtocol::updateDelayStats(
+    const ContentObject &content_object) {
+  uint32_t segmentNumber = content_object.getName().getSuffix();
+  uint32_t pkt = segmentNumber & modMask_;
+
+  if (inflightInterests_[pkt].transmissionTime ==
+      0)  // this is always the case if we have a retransmitted packet (timeout
+          // or RTCP)
+    return;
+
+  uint32_t pathLabel = content_object.getPathLabel();
+
+  if (pathTable_.find(pathLabel) == pathTable_.end()) {
+    // found a new path
+    std::shared_ptr<RTCDataPath> newPath = std::make_shared<RTCDataPath>();
+    pathTable_[pathLabel] = newPath;
+  }
+
+  // RTT measurements are useful both from NACKs and data packets
+  uint64_t RTT = std::chrono::duration_cast<std::chrono::milliseconds>(
+                     std::chrono::steady_clock::now().time_since_epoch())
+                     .count() -
+                 inflightInterests_[pkt].transmissionTime;
+
+  pathTable_[pathLabel]->insertRttSample(RTT);
+
+  // we collect OWD only for datapackets
+  if (content_object.getPayload().length() != NACK_HEADER_SIZE) {
+    uint64_t *senderTimeStamp = (uint64_t *)content_object.getPayload().data();
+
+    int64_t OWD = std::chrono::duration_cast<std::chrono::milliseconds>(
+                      std::chrono::system_clock::now().time_since_epoch())
+                      .count() -
+                  *senderTimeStamp;
+
+    pathTable_[pathLabel]->insertOwdSample(OWD);
+  }
+}
+
+void RTCTransportProtocol::updateStats(uint32_t round_duration) {
+  if (receivedBytes_ != 0) {
+    double bytesPerSec = (double)(receivedBytes_ * ((double)MILLI_IN_A_SEC /
+                                                    (double)round_duration));
+    estimatedBw_ = (estimatedBw_ * ESTIMATED_BW_ALPHA) +
+                   ((1 - ESTIMATED_BW_ALPHA) * bytesPerSec);
+  }
+
+  auto it = pathTable_.find(producerPathLabel_);
+  if (it == pathTable_.end()) return;
+
+  // double maxAvgRTT = it->second->getAverageRtt();
+  // double minRTT = it->second->getMinRtt();
+  minRtt_ = it->second->getMinRtt();
+  queuingDelay_ = it->second->getQueuingDealy();
+
+  if (minRtt_ == 0) minRtt_ = 1;
+
+  for (auto it = pathTable_.begin(); it != pathTable_.end(); it++) {
+    it->second->roundEnd();
+  }
+
+  // this is inefficient but the window is supposed to be small, so it
+  // probably makes sense to leave it like this
+  // if(minRTT == 0)
+  //    minRTT = 1;
+
+  // minRTTwin_[roundCounter_ % MIN_RTT_WIN] = minRTT;
+  // minRtt_ = minRTT;
+  // for (int i = 0; i < MIN_RTT_WIN; i++)
+  //    if(minRtt_ > minRTTwin_[i])
+  //        minRtt_ = minRTTwin_[i];
+
+  // roundCounter_++;
+
+  // std::cout << "min RTT " << minRtt_ << " queuing " << queuingDelay_ <<
+  // std::endl;
+
+  if (sentInterest_ != 0 && currentState_ == RTC_NORMAL_STATE) {
+    double lossRate = (double)((double)packetLost_ / (double)sentInterest_);
+    lossRate_ = lossRate_ * ESTIMATED_LOSSES_ALPHA +
+                (lossRate * (1 - ESTIMATED_LOSSES_ALPHA));
+  }
+
+  if (avgPacketSize_ == 0) avgPacketSize_ = INIT_PACKET_SIZE;
+
+  uint32_t BDP =
+      ceil((estimatedBw_ * (double)((double)minRtt_ / (double)MILLI_IN_A_SEC) *
+            BANDWIDTH_SLACK_FACTOR) /
+           avgPacketSize_);
+  uint32_t BW = ceil(estimatedBw_);
+  computeMaxWindow(BW, BDP);
+
+  // bound also by interest lifitime* production rate
+  if (!gotNack_) {
+    roundsWithoutNacks_++;
+    if (currentState_ == RTC_SYNC_STATE &&
+        roundsWithoutNacks_ >= ROUNDS_IN_SYNC_BEFORE_SWITCH) {
+      currentState_ = RTC_NORMAL_STATE;
+    }
+  } else {
+    roundsWithoutNacks_ = 0;
+  }
+
+  updateCCState();
+  updateWindow();
+
+  // in any case we reset all the counters
+
+  gotNack_ = false;
+  gotFutureNack_ = 0;
+  receivedBytes_ = 0;
+  sentInterest_ = 0;
+  receivedData_ = 0;
+  packetLost_ = 0;
+}
+
+void RTCTransportProtocol::updateCCState() {
+  // TODO
+}
+
+void RTCTransportProtocol::computeMaxWindow(uint32_t productionRate,
+                                            uint32_t BDPWin) {
+  if (productionRate ==
+      0)  // we have no info about the producer, keep the previous maxCWin
+    return;
+
+  uint32_t interestLifetime = default_values::interest_lifetime;
+  socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+                           interestLifetime);
+  uint32_t maxWaintingInterest = ceil(
+      (productionRate / avgPacketSize_) *
+      (double)((double)(interestLifetime * INTEREST_LIFETIME_REDUCTION_FACTOR) /
+               (double)MILLI_IN_A_SEC));
+
+  if (currentState_ == RTC_SYNC_STATE) {
+    // in this case we do not limit the window with the BDP, beacuse most likly
+    // it is wrong
+    maxCWin_ = maxWaintingInterest;
+    return;
+  }
+
+  // currentState = RTC_NORMAL_STATE
+  if (BDPWin != 0) {
+    maxCWin_ = ceil((double)BDPWin + ((double)BDPWin / 10.0));  // BDP + 10%
+  } else {
+    maxCWin_ = min(maxWaintingInterest, maxCWin_);
+  }
+}
+
+void RTCTransportProtocol::updateWindow() {
+  if (currentState_ == RTC_SYNC_STATE) return;
+
+  if (currentCWin_ < maxCWin_ * 0.7) {
+    currentCWin_ = min(maxCWin_, currentCWin_ * WIN_INCREASE_FACTOR);
+  } else if (currentCWin_ > maxCWin_) {
+    currentCWin_ = max(currentCWin_ * WIN_DECREASE_FACTOR, MIN_CWIN);
+  }
+}
+
+void RTCTransportProtocol::decreaseWindow() {
+  // this is used only in SYNC mode
+  if (currentState_ == RTC_NORMAL_STATE) return;
+
+  if (gotFutureNack_ == 1)
+    currentCWin_ =
+        min((currentCWin_ - 1), ceil((double)maxCWin_ * 0.66));  // 2/3
+  else
+    currentCWin_--;
+
+  currentCWin_ = max(currentCWin_, MIN_CWIN);
+}
+
+void RTCTransportProtocol::increaseWindow() {
+  // this is used only in SYNC mode
+  if (currentState_ == RTC_NORMAL_STATE) return;
+
+  // we need to be carefull to do not increase the window to much
+  if (currentCWin_ < ((double)maxCWin_ * 0.5)) {
+    currentCWin_ = currentCWin_ + 1;  // exponential
+  } else {
+    currentCWin_ = min(
+        maxCWin_, ceil(currentCWin_ + (1.0 / (double)currentCWin_)));  // linear
+  }
+}
+
+void RTCTransportProtocol::sendInterest() {
+  Name interest_name;
+  socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
+                           interest_name);
+  bool isRTX = false;
+  // uint32_t sentInt = 0;
+
+  if (interestRetransmissions_.size() > 0) {
+    // handle retransmission
+    // here we have two possibile retransmissions: retransmissions due to
+    // timeouts and retransmissions due to RTCP NACKs. we will send the interest
+    // anyway, even if it is pending (this is possible only in the second case)
+    uint32_t rtxSeg = interestRetransmissions_.front();
+    interestRetransmissions_.pop();
+
+    std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+        holes_.find(rtxSeg);
+    if (res != holes_.end()) {
+      // this packet is already managed by as an hole
+      // we don't need to send it again
+      return;
+    }
+
+    // a packet recovery means that there was a loss
+    packetLost_++;
+
+    uint32_t pkt = rtxSeg & modMask_;
+    interest_name.setSuffix(rtxSeg);
+
+    // if the interest is not pending anymore we encrease the retrasnmission
+    // counter in order to avoid to handle a recovered packt as a normal one
+    if (!portal_->interestIsPending(interest_name)) {
+      inflightInterests_[pkt].retransmissions++;
+    }
+
+    inflightInterests_[pkt].transmissionTime = 0;
+    isRTX = true;
+  } else {
+    // in this case we send the packet only if it is not pending yet
+    interest_name.setSuffix(actualSegment_);
+    if (portal_->interestIsPending(interest_name)) {
+      actualSegment_++;
+      return;
+    }
+
+    // sentInt = actualSegment_;
+    uint32_t pkt = actualSegment_ & modMask_;
+    inflightInterests_[pkt].transmissionTime =
+        std::chrono::duration_cast<std::chrono::milliseconds>(
+            std::chrono::steady_clock::now().time_since_epoch())
+            .count();
+    inflightInterests_[pkt].retransmissions = 0;
+    actualSegment_++;
+  }
+
+  auto interest = getInterest();
+  interest->setName(interest_name);
+
+  uint32_t interestLifetime = default_values::interest_lifetime;
+  socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+                           interestLifetime);
+  interest->setLifetime(uint32_t(interestLifetime));
+
+  ConsumerInterestCallback on_interest_output = VOID_HANDLER;
+
+  socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
+                           on_interest_output);
+
+  if (on_interest_output != VOID_HANDLER) {
+    on_interest_output(*dynamic_cast<ConsumerSocket *>(socket_), *interest);
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+    return;
+  }
+
+  using namespace std::placeholders;
+  portal_->sendInterest(std::move(interest));
+
+  sentInterest_++;
+
+  if (!isRTX) {
+    inflightInterestsCount_++;
+  }
+}
+
+void RTCTransportProtocol::scheduleNextInterest() {
+  checkRound();
+  if(!is_running_)
+    return;
+
+  uint32_t MAX_RECOVER =
+      40;  // if the packet is more than MAX_RECOVER seq in the past we drop it
+  uint64_t TIME_BEFORE_RECOVERY = 10;  // this should be proporsional to the RTT
+
+  // holes are important only in NORMAL state
+  if (currentState_ == RTC_NORMAL_STATE) {
+    for (std::unordered_map<uint32_t, uint64_t>::iterator it = holes_.begin();
+         it != holes_.end();) {
+      if (it->first < lastReceived_ - MAX_RECOVER) {
+        // the packet is to hold, remove it
+        it = holes_.erase(it);
+      } else {
+        uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
+                           std::chrono::steady_clock::now().time_since_epoch())
+                           .count();
+        uint64_t sinceLastTry = now - it->second;
+
+        if (sinceLastTry > TIME_BEFORE_RECOVERY || it->second == 0) {
+          // a recovery means a packet lost
+          packetLost_++;
+          // update last sent time
+          it->second = now;
+
+          Name interest_name;
+          socket_->getSocketOption(GeneralTransportOptions::NETWORK_NAME,
+                                   interest_name);
+
+          uint32_t pkt = it->first & modMask_;
+          interest_name.setSuffix(it->first);
+
+          if (!portal_->interestIsPending(interest_name)) {
+            inflightInterests_[pkt].retransmissions++;
+          }
+
+          inflightInterests_[pkt].transmissionTime = 0;
+          // XXX
+          // code refactoring:
+          // from here on this is a copy and paste of the code inside
+          // sendInterest this should go inside an other method
+          auto interest = getInterest();
+          uint32_t interestLifetime = default_values::interest_lifetime;
+          socket_->getSocketOption(GeneralTransportOptions::INTEREST_LIFETIME,
+                                   interestLifetime);
+          interest->setLifetime(uint32_t(interestLifetime));
+
+          ConsumerInterestCallback on_interest_output = VOID_HANDLER;
+
+          socket_->getSocketOption(ConsumerCallbacksOptions::INTEREST_OUTPUT,
+                                   on_interest_output);
+          if (on_interest_output != VOID_HANDLER)
+            on_interest_output(*dynamic_cast<ConsumerSocket *>(socket_),
+                               *interest);
+
+          if (TRANSPORT_EXPECT_FALSE(!is_running_)) return;
+
+          using namespace std::placeholders;
+          portal_->sendInterest(std::move(interest));
+
+          sentInterest_++;
+        }
+        ++it;
+      }
+      // as usual check the round at each packet
+      checkRound();
+    }
+  }
+
+  while (interestRetransmissions_.size() > 0) {
+    sendInterest();
+    checkRound();
+  }
+
+  while (inflightInterestsCount_ < currentCWin_) {
+    sendInterest();
+    checkRound();
+  }
+}
+
+void RTCTransportProtocol::scheduleAppNackRtx(std::vector<uint32_t> &nacks) {
+  for (uint32_t i = 0; i < nacks.size(); i++) {
+    if (nackedByProducer_.find(nacks[i]) != nackedByProducer_.end()) {
+      continue;
+    }
+    // packetLost_++;
+    // XXX here I need to avoid the retrasmission for packet that were nacked by
+    // the network
+    interestRetransmissions_.push(nacks[i]);
+  }
+
+  scheduleNextInterest();
+}
+void RTCTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+  // packetLost_++;
+
+  uint32_t segmentNumber = interest->getName().getSuffix();
+  uint32_t pkt = segmentNumber & modMask_;
+
+  if (inflightInterests_[pkt].retransmissions == 0) {
+    inflightInterestsCount_--;
+  }
+
+  if (inflightInterests_[pkt].retransmissions < MAX_RTX) {
+    interestRetransmissions_.push(segmentNumber);
+  }
+
+  scheduleNextInterest();
+}
+
+void RTCTransportProtocol::onNack(const ContentObject &content_object) {
+  uint32_t *payload = (uint32_t *)content_object.getPayload().data();
+  uint32_t productionSeg = *payload;
+  uint32_t productionRate = *(++payload);
+  uint32_t nackSegment = content_object.getName().getSuffix();
+
+  // we synch the estimated production rate with the actual one
+  estimatedBw_ = (double)productionRate;
+
+  // if(inflightInterests_[segmentNumber %
+  // default_values::default_buffer_size].retransmissions != 0){ ignore nacks for
+  // retransmissions
+  //    return;
+  //}
+
+  gotNack_ = true;
+
+  if (productionSeg > nackSegment) {
+    // we are asking for stuff produced in the past
+    actualSegment_ = max(productionSeg + 1, actualSegment_);
+    if (currentState_ == RTC_NORMAL_STATE) {
+      currentState_ = RTC_SYNC_STATE;
+      // if we switch in SYNC mode we do not care about holes
+      // se we reset the data structure. going back to NORMAL
+      // mode will anable again the holes_ check.
+      holes_.clear();
+      lastReceived_ = 0;
+    }
+
+    computeMaxWindow(productionRate, 0);
+    increaseWindow();
+
+    if (nackedByProducer_.size() >= nackedByProducerMaxSize_)
+      nackedByProducer_.erase(nackedByProducer_.begin());
+    nackedByProducer_.insert(nackSegment);
+
+  } else if (productionSeg < nackSegment) {
+    gotFutureNack_++;
+    // we are asking stuff in the future
+    // example
+    // 10    12    13    14    15    16    17
+    //       ^                  ^           ^
+    //       in prod            nack        actual
+    // in this example we sent up to segment 17 and we get a nack for segment 15
+    // this means that we will get nack also for 16 17
+    // and valid data for 13 14
+    // so the next segment to ask is 15, because 13 and 14 will can back anyway
+    // we go back only in the case that the actual segment is really bigger than
+    // nack segment, other we do nothing
+
+    actualSegment_ = min(actualSegment_, nackSegment);
+
+    computeMaxWindow(productionRate, 0);
+    decreaseWindow();
+
+    if (currentState_ == RTC_SYNC_STATE) {
+      currentState_ = RTC_NORMAL_STATE;
+    }
+  }  // equal should not happen
+}
+
+void RTCTransportProtocol::onContentObject(
+    Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+  uint32_t payload_size = content_object->getPayload().length();
+  uint32_t segmentNumber = content_object->getName().getSuffix();
+  uint32_t pkt = segmentNumber & modMask_;
+
+  // try to recover holes
+  // we can recover haoles with valid data, nacks or retransmitted packets
+  bool recoveredHole = false;
+  std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+      holes_.find(segmentNumber);
+  if (res != holes_.end()) {
+    holes_.erase(res);
+    recoveredHole = true;
+  }
+
+  if (payload_size == NACK_HEADER_SIZE) {
+    // Nacks always come form the producer, so we set the producerePathLabel_;
+    producerPathLabel_ = content_object->getPathLabel();
+    if (inflightInterests_[pkt].retransmissions == 0) {
+      inflightInterestsCount_--;
+      onNack(*content_object);
+      updateDelayStats(*content_object);
+    }
+
+  } else {
+    receivedData_++;
+
+    avgPacketSize_ =
+        (ESTIMATED_PACKET_SIZE * avgPacketSize_) +
+        ((1 - ESTIMATED_PACKET_SIZE) * content_object->getPayload().length());
+
+    if (inflightInterests_[pkt].retransmissions == 0) {
+      inflightInterestsCount_--;
+      // we count only non retransmitted data in order to take into accunt only
+      // the transmition rate of the producer
+      receivedBytes_ +=
+          content_object->headerSize() + content_object->payloadSize();
+      updateDelayStats(*content_object);
+
+      // handle holes
+      // the packet sequence make sense only in case of valid data (no nacks, no
+      // rtx) in RTC_NORMAL_STATE we should get all the packets in order, so if
+      // segmentNumber != lastReceived + 1 something happened
+      // if recoveredHole == true this is a packet recovered so we should do
+      // nothing
+      if (currentState_ == RTC_NORMAL_STATE && recoveredHole == false) {
+        if ((segmentNumber != lastReceived_ + 1) &&
+            segmentNumber > lastReceived_) {
+          // we have holes in the sequence
+          for (uint32_t seq = lastReceived_ + 1; seq < segmentNumber; seq++) {
+            // the hole exists we do not insert it again
+            std::unordered_map<uint32_t, uint64_t>::const_iterator res =
+                holes_.find(seq);
+            if (res == holes_.end())
+              holes_.insert(std::make_pair(seq, 0));  // 0 means never sent
+          }
+        }
+      }
+
+      // this if should be always true
+      if (segmentNumber > lastReceived_) {
+        lastReceived_ = segmentNumber;
+      }
+    }
+
+    returnContentToUser(*content_object);
+    increaseWindow();
+  }
+
+  scheduleNextInterest();
+}
+
+void RTCTransportProtocol::returnContentToUser(
+    const ContentObject &content_object) {
+  // return content to the user
+  Array a = content_object.getPayload();
+
+  uint8_t *start = ((uint8_t *)a.data()) + TIMESTAMP_SIZE;
+  unsigned size = a.length() - TIMESTAMP_SIZE;
+
+  // set offset between hICN and RTP packets
+  uint16_t rtp_seq = ntohs(*(((uint16_t *)start) + 1));
+  RTPhICN_offset_ = content_object.getName().getSuffix() - rtp_seq;
+
+  content_buffer_->insert(content_buffer_->end(), start, start + size);
+
+  ConsumerContentCallback on_payload = VOID_HANDLER;
+  socket_->getSocketOption(CONTENT_RETRIEVED, on_payload);
+  if (on_payload != VOID_HANDLER) {
+    on_payload(*dynamic_cast<ConsumerSocket *>(socket_), size,
+               std::make_error_code(std::errc(0)));
+  }
+}
+
+uint32_t RTCTransportProtocol::hICN2RTP(uint32_t hicn_seq) {
+  return RTPhICN_offset_ - hicn_seq;
+}
+
+uint32_t RTCTransportProtocol::RTP2hICN(uint32_t rtp_seq) {
+  return RTPhICN_offset_ + rtp_seq;
+}
+
+void RTCTransportProtocol::processRtcpHeader(uint8_t *offset) {
+  uint8_t pkt_type = (*(offset + 1));
+  switch (pkt_type) {
+    case RTCP_RR:  // Receiver report
+      TRANSPORT_LOGI("got RR packet\n");
+      break;
+    case RTCP_SR:  // Sender report
+      TRANSPORT_LOGI("got SR packet\n");
+      break;
+    case RTCP_SDES:  // Description
+      processSDES(offset);
+      break;
+    case RTCP_RTPFB:  // Transport layer FB message
+      processGenericNack(offset);
+      break;
+    case RTCP_PSFB:
+      processPli(offset);
+      break;
+    default:
+      errorParsingRtcpHeader(offset);
+  }
+}
+
+void RTCTransportProtocol::errorParsingRtcpHeader(uint8_t *offset) {
+  uint8_t pt = (*(offset + 1));
+  uint8_t code = ((*offset) & MASK_TYPE_CODE);
+  TRANSPORT_LOGE("Received unknwnon RTCP packet. Payload type = %u, code = %u",
+                 pt, code);
+}
+
+void RTCTransportProtocol::processSDES(uint8_t *offset) {
+  uint8_t code = ((*offset) & MASK_TYPE_CODE);
+  switch (code) {
+    case RTCP_SDES_CNAME:
+      TRANSPORT_LOGI("got SDES packet: CNAME\n");
+      break;
+    default:
+      errorParsingRtcpHeader(offset);
+  }
+}
+
+void RTCTransportProtocol::processPli(uint8_t *offset) {
+  if (((*offset) & MASK_TYPE_CODE) != RTCP_PSFB_PLI) {
+    errorParsingRtcpHeader(offset);
+    return;
+  }
+
+  TRANSPORT_LOGI("got PLI packet\n");
+}
+
+void RTCTransportProtocol::processGenericNack(uint8_t *offset) {
+  if (((*offset) & MASK_TYPE_CODE) != RTCP_RTPFB_GENERIC_NACK) {
+    errorParsingRtcpHeader(offset);
+    return;
+  }
+
+  std::vector<uint32_t> nacks;
+
+  uint16_t header_lines =
+      ntohs(*(((uint16_t *)offset) + 1)) -
+      2;  // 2 is the number of header 32-bits words - 1 (RFC 4885)
+  uint8_t *payload = offset + RTPC_NACK_HEADER;  // 12 bytes
+  for (uint16_t l = header_lines; l > 0; l--) {
+    nacks.push_back(RTP2hICN(ntohs(*((uint16_t *)payload))));
+
+    uint16_t BLP = ntohs(*(((uint16_t *)payload) + 1));
+
+    for (int bit = 0; bit < 15; bit++) {  // 16 bits word to scan
+      if ((BLP >> bit) & 1) {
+        nacks.push_back(RTP2hICN((ntohs(*((uint16_t *)payload)) + bit + 1) %
+                                 MAX_RTCP_SEQ_NUMBER));
+      }
+    }
+
+    payload += 4;  // go to the next line
+  }
+
+  portal_->getIoService().post(std::bind(
+      &RTCTransportProtocol::scheduleAppNackRtx, this, std::move(nacks)));
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc.h b/libtransport/src/hicn/transport/protocols/rtc.h
new file mode 100755 (executable)
index 0000000..249af6b
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiTC_SYNC_STATE
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <queue>
+#include <set>
+#include <unordered_map>
+
+#include <hicn/transport/protocols/protocol.h>
+#include <hicn/transport/protocols/rtc_data_path.h>
+
+// algorithm state
+#define RTC_SYNC_STATE 0
+#define RTC_NORMAL_STATE 1
+#define ROUNDS_IN_SYNC_BEFORE_SWITCH 3
+
+// packet constants
+#define INIT_PACKET_SIZE 1300       // bytes
+#define HICN_PACKET_HEADER_SIZE 60  // bytes ipv6+tcp
+#define NACK_HEADER_SIZE 8          // bytes
+#define TIMESTAMP_SIZE 8            // bytes
+#define RTC_INTEREST_LIFETIME 1000  // ms
+
+// controller constant
+#define ROUND_LEN \
+  200  // ms interval of time on which we take decisions / measurements
+#define MAX_RTX 128
+#define MIN_RTT_WIN 30  // rounds
+
+// cwin
+#define INITIAL_CWIN 1           // packets
+#define INITIAL_CWIN_MAX 100000  // packets
+#define MIN_CWIN 5               // packets
+
+// statistics constants
+#define BANDWIDTH_SLACK_FACTOR 1.5
+#define ESTIMATED_BW_ALPHA 0.7
+#define ESTIMATED_PACKET_SIZE 0.7
+#define ESTIMATED_LOSSES_ALPHA 0.8
+#define INTEREST_LIFETIME_REDUCTION_FACTOR 0.8
+
+//#define MAX_LOSS_RATE 0.05
+//#define MAX_QUEUING_DELAY 200       //ms
+
+// cwin
+#define INITIAL_CWIN 1
+#define MIN_CWIN 5
+#define WIN_DECREASE_FACTOR 0.8
+#define WIN_INCREASE_FACTOR 1.1
+
+// protocol state
+//#define RTC_CONGESTED_STATE 10
+//#define RTC_LOSSY_STATE 20
+//#define RTC_DELAY_STATE 30
+//#define RTC_NORMAL_STATE 40
+
+// other constants
+#define NANO_IN_A_SEC 1000000000
+#define MICRO_IN_A_SEC 1000000
+#define MILLI_IN_A_SEC 1000
+
+// RTCP
+#define MASK_RTCP_VERSION 192
+#define MASK_TYPE_CODE \
+  31  // this is RC in the RR/SR packet or FMT int the early feedback packets
+#define RTPC_NACK_HEADER 12  // bytes
+#define MAX_RTCP_SEQ_NUMBER 0xffff
+#define RTCP_VERSION 2
+// RTCP TYPES
+#define RTCP_SR 200
+#define RTCP_RR 201
+#define RTCP_SDES 202
+#define RTCP_RTPFB 205
+#define RTCP_PSFB 206
+// RTCP RC/FMT
+#define RTCP_SDES_CNAME 1
+#define RTCP_RTPFB_GENERIC_NACK 1
+#define RTCP_PSFB_PLI 1
+
+namespace transport {
+
+namespace protocol {
+
+struct sentInterest {
+  uint64_t transmissionTime;
+  uint8_t retransmissions;
+};
+
+class RTCTransportProtocol : public TransportProtocol {
+ public:
+  RTCTransportProtocol(interface::BaseSocket *icnet_socket);
+
+  ~RTCTransportProtocol();
+
+  void start(utils::SharableVector<uint8_t> &content_buffer);
+
+  void stop();
+
+  void resume();
+
+  void onRTCPPacket(uint8_t *packet, size_t len);
+
+ private:
+  // algo functions
+  void reset();
+  void checkRound();
+
+  // CC functions
+  void updateDelayStats(const ContentObject &content_object);
+  void updateStats(uint32_t round_duration);
+  void updateCCState();
+  void computeMaxWindow(uint32_t productionRate, uint32_t BDPWin);
+  void updateWindow();
+  void decreaseWindow();
+  void increaseWindow();
+  void resetPreviousWindow();
+
+  // packet functions
+  void sendInterest();
+  void scheduleNextInterest();
+  void scheduleAppNackRtx(std::vector<uint32_t> &nacks);
+  void onTimeout(Interest::Ptr &&interest);
+  void onNack(const ContentObject &content_object);
+  void onContentObject(Interest::Ptr &&interest,
+                       ContentObject::Ptr &&content_object);
+  void returnContentToUser(const ContentObject &content_object);
+
+  // RTCP functions
+  uint32_t hICN2RTP(uint32_t hicn_seq);
+  uint32_t RTP2hICN(uint32_t rtp_seq);
+  void processRtcpHeader(uint8_t *offset);
+  void errorParsingRtcpHeader(uint8_t *offset);
+  void processSDES(uint8_t *offset);
+  void processGenericNack(uint8_t *offset);
+  void processPli(uint8_t *offset);
+
+  // controller var
+  std::chrono::steady_clock::time_point lastRoundBegin_;
+  // bool allPacketsInSync_;
+  // unsigned numberOfRoundsInSync_;
+  // unsigned numberOfCatchUpRounds_;
+  // bool catchUpPhase_;
+  unsigned currentState_;
+
+  // uint32_t inProduction_;
+
+  // cwin var
+  uint32_t currentCWin_;
+  uint32_t maxCWin_;
+  // uint32_t previousCWin_;
+
+  // names/packets var
+  uint32_t actualSegment_;
+  int32_t RTPhICN_offset_;
+  uint32_t inflightInterestsCount_;
+  std::queue<uint32_t> interestRetransmissions_;
+  std::vector<sentInterest> inflightInterests_;
+  uint32_t nackedByProducerMaxSize_;
+  std::set<uint32_t>
+      nackedByProducer_;  // this is used to avoid retransmissions from the
+                          // application for pakets for which we already got a
+                          // past NACK by the producer these packet are too old,
+                          // they will never be retrived
+  std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+  uint32_t modMask_;
+
+  // stats
+  uint32_t receivedBytes_;
+  uint32_t sentInterest_;
+  uint32_t receivedData_;
+  uint32_t packetLost_;
+  double avgPacketSize_;
+  bool gotNack_;
+  uint32_t gotFutureNack_;
+  uint32_t roundsWithoutNacks_;
+  uint32_t producerPathLabel_;  // XXX we pick only one path lable for the
+                                // producer for now, assuming the usage of a
+                                // single path this should be extended to a
+                                // vector
+  std::unordered_map<uint32_t, std::shared_ptr<RTCDataPath>> pathTable_;
+  uint32_t roundCounter_;
+  // std::vector<uint64_t> minRTTwin_;
+  uint64_t minRtt_;
+
+  std::unordered_map<uint32_t, uint64_t> holes_;
+  uint32_t lastReceived_;
+
+  // CC var
+  double estimatedBw_;
+  double lossRate_;
+  double queuingDelay_;
+  unsigned protocolState_;
+};
+
+}  // namespace protocol
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.cc b/libtransport/src/hicn/transport/protocols/rtc_data_path.cc
new file mode 100755 (executable)
index 0000000..6c9605f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/protocols/rtc_data_path.h>
+
+namespace transport {
+
+namespace protocol {
+
+RTCDataPath::RTCDataPath()
+    : min_rtt(UINT_MAX),
+      prev_min_rtt(UINT_MAX),
+      min_owd(INT_MAX),  // this is computed like in LEDBAT, so it is not the
+                         // real OWD, but the measured one, that depends on the
+                         // clock of sender and receiver. the only meaningful
+                         // value is is the queueing delay. for this reason we
+                         // keep both RTT (for the windowd calculation) and OWD
+                         // (for congestion/quality control)
+      prev_min_owd(INT_MAX),
+      avg_owd(0.0),
+      queuing_delay(0.0),
+      RTThistory_(HISTORY_LEN),
+      OWDhistory_(HISTORY_LEN){};
+
+void RTCDataPath::insertRttSample(uint64_t rtt) {
+  // for the rtt we only keep track of the min one
+  if (rtt < min_rtt) min_rtt = rtt;
+}
+
+void RTCDataPath::insertOwdSample(int64_t owd) {
+  // for owd we use both min and avg
+  if (owd < min_owd) min_owd = owd;
+
+  avg_owd = (avg_owd * (1 - ALPHA_RTC)) + (owd * ALPHA_RTC);
+}
+
+void RTCDataPath::roundEnd() {
+  // compute queuing delay
+  queuing_delay = avg_owd - getMinOwd();
+
+  // reset min_rtt and add it to the history
+  if (min_rtt != UINT_MAX) {
+    prev_min_rtt = min_rtt;
+  } else {
+    // this may happen if we do not receive any packet
+    // from this path in the last round. in this case
+    // we use the measure from the previuos round
+    min_rtt = prev_min_rtt;
+  }
+
+  RTThistory_.pushBack(min_rtt);
+  min_rtt = UINT_MAX;
+
+  // do the same for min owd
+  if (min_owd != INT_MAX) {
+    prev_min_owd = min_owd;
+  } else {
+    min_owd = prev_min_owd;
+  }
+
+  OWDhistory_.pushBack(min_owd);
+  min_owd = INT_MAX;
+}
+
+double RTCDataPath::getQueuingDealy() { return queuing_delay; }
+
+uint64_t RTCDataPath::getMinRtt() { return RTThistory_.begin(); }
+
+int64_t RTCDataPath::getMinOwd() { return OWDhistory_.begin(); }
+
+}  // end namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/rtc_data_path.h b/libtransport/src/hicn/transport/protocols/rtc_data_path.h
new file mode 100755 (executable)
index 0000000..ace16ff
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <hicn/transport/utils/min_filter.h>
+#include <climits>
+
+#define ALPHA_RTC 0.125
+#define HISTORY_LEN 30
+
+namespace transport {
+
+namespace protocol {
+
+class RTCDataPath {
+ public:
+  RTCDataPath();
+
+ public:
+  void insertRttSample(uint64_t rtt);
+  void insertOwdSample(int64_t owd);
+
+  uint64_t getMinRtt();
+
+  double getQueuingDealy();
+
+  void roundEnd();
+
+ private:
+  int64_t getMinOwd();
+
+  uint64_t min_rtt;
+  uint64_t prev_min_rtt;
+
+  int64_t min_owd;
+  int64_t prev_min_owd;
+
+  double avg_owd;
+
+  double queuing_delay;
+
+  utils::MinFilter<uint64_t> RTThistory_;
+  utils::MinFilter<int64_t> OWDhistory_;
+};
+
+}  // namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt b/libtransport/src/hicn/transport/protocols/test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..6f9fdb9
--- /dev/null
@@ -0,0 +1,10 @@
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+set(TestsExpectedToPass
+    test_transport_producer)
+
+foreach(test ${TestsExpectedToPass})
+  AddTest(${test})
+endforeach()
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc b/libtransport/src/hicn/transport/protocols/test/test_transport_producer.cc
new file mode 100755 (executable)
index 0000000..204f2cb
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2019 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 <gtest/gtest.h>
+
+#include "../socket_producer.h"
+#include "literals.h"
+
+#include <test.h>
+#include <random>
+
+namespace transport {
+
+namespace protocol {
+
+namespace {
+// The fixture for testing class Foo.
+class ProducerTest : public ::testing::Test {
+ protected:
+  ProducerTest() : name_("b001::123|321"), producer_(io_service_) {
+    // You can do set-up work for each test here.
+  }
+
+  virtual ~ProducerTest() {
+    // You can do clean-up work that doesn't throw exceptions here.
+  }
+
+  // If the constructor and destructor are not enough for setting up
+  // and cleaning up each test, you can define the following methods:
+
+  virtual void SetUp() {
+    // Code here will be called immediately after the constructor (right
+    // before each test).
+  }
+
+  virtual void TearDown() {
+    // Code here will be called immediately after each test (right
+    // before the destructor).
+  }
+
+  Name name_;
+  asio::io_service io_service_;
+  ProducerSocket producer_;
+};
+
+}  // namespace
+
+// Tests that the Foo::Bar() method does Abc.
+TEST_F(ProducerTest, ProduceContent) {
+  std::string content(250000, '?');
+
+  producer_.registerPrefix(Prefix("b001::/64"));
+  producer_.produce(name_, reinterpret_cast<const uint8_t *>(content.data()),
+                    content.size(), true);
+  producer_.setSocketOption(GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+                            500000000_U32);
+  producer_.attach();
+  producer_.serveForever();
+}
+
+}  // namespace protocol
+
+}  // namespace transport
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/vegas.cc b/libtransport/src/hicn/transport/protocols/vegas.cc
new file mode 100755 (executable)
index 0000000..b6d79bf
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/errors/not_implemented_exception.h>
+#include <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/protocols/vegas.h>
+#include <hicn/transport/utils/literals.h>
+
+#include <cmath>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+VegasTransportProtocol::VegasTransportProtocol(BaseSocket *icnet_socket)
+    : TransportProtocol(icnet_socket),
+      is_final_block_number_discovered_(false),
+      final_block_number_(std::numeric_limits<uint32_t>::max()),
+      last_reassembled_segment_(0),
+      content_buffer_size_(0),
+      current_window_size_(default_values::min_window_size),
+      interests_in_flight_(0),
+      next_suffix_(0),
+      interest_retransmissions_(1 << default_values::log_2_default_buffer_size),
+      interest_timepoints_(1 << default_values::log_2_default_buffer_size),
+      retx_count_(0),
+      receive_buffer_(1 << default_values::log_2_default_buffer_size),
+      unverified_segments_(1 << default_values::log_2_default_buffer_size),
+      verified_manifests_(1 << default_values::log_2_default_buffer_size),
+      mask_((1 << default_values::log_2_default_buffer_size) - 1),
+      incremental_suffix_index_(0),
+      suffix_queue_completed_(false),
+      download_with_manifest_(false),
+      next_manifest_interval_(0_U16),
+      interest_tx_(0),
+      interest_count_(0),
+      byte_count_(0),
+      average_rtt_(0.0) {
+  portal_ = socket_->portal_;
+  incremental_suffix_index_++;
+}
+
+VegasTransportProtocol::~VegasTransportProtocol() { stop(); }
+
+void VegasTransportProtocol::reset() {
+  portal_->setConsumerCallback(this);
+
+  is_final_block_number_discovered_ = false;
+  interest_pool_index_ = 0;
+  final_block_number_ = std::numeric_limits<uint32_t>::max();
+  next_suffix_ = 0;
+  interests_in_flight_ = 0;
+  last_reassembled_segment_ = 0;
+  content_buffer_size_ = 0;
+  content_buffer_->clear();
+  interest_retransmissions_.clear();
+  interest_retransmissions_.resize(
+      1 << default_values::log_2_default_buffer_size, 0);
+  interest_timepoints_.clear();
+  interest_timepoints_.resize(1 << default_values::log_2_default_buffer_size,
+                              std::chrono::steady_clock::time_point());
+  receive_buffer_.clear();
+  unverified_segments_.clear();
+  verified_manifests_.clear();
+  next_manifest_interval_ = 0;
+  next_manifest_ = 0;
+  download_with_manifest_ = false;
+  incremental_suffix_index_ = 0;
+
+  interest_tx_ = 0;
+  interest_count_ = 0;
+  byte_count_ = 0;
+  average_rtt_ = 0;
+
+  // asio::io_service &io_service = portal_->getIoService();
+
+  // if (io_service.stopped()) {
+  //   io_service.reset();
+  // }
+}
+
+void VegasTransportProtocol::start(
+    utils::SharableVector<uint8_t> &content_buffer) {
+
+  if(is_running_)
+    return;
+
+  socket_->t0_ = std::chrono::steady_clock::now();
+
+  is_running_ = true;
+  content_buffer_ = content_buffer.shared_from_this();
+
+  reset();
+
+  sendInterest(next_suffix_++);
+  portal_->runEventsLoop();
+  removeAllPendingInterests();
+  is_running_ = false;
+
+}
+
+void VegasTransportProtocol::resume(){
+  if(is_running_)
+    return;
+
+  is_running_ = true;
+  sendInterest(next_suffix_++); 
+  portal_->runEventsLoop();
+  removeAllPendingInterests();
+  is_running_ = false;
+}
+
+void VegasTransportProtocol::sendInterest(std::uint64_t next_suffix) {
+  auto interest = getInterest();
+  socket_->network_name_.setSuffix(next_suffix);
+  interest->setName(socket_->network_name_);
+
+  interest->setLifetime(uint32_t(socket_->interest_lifetime_));
+
+  if (socket_->on_interest_output_ != VOID_HANDLER) {
+    socket_->on_interest_output_(*socket_, *interest);
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+    return;
+  }
+
+  interests_in_flight_++;
+  interest_retransmissions_[next_suffix & mask_] = 0;
+  interest_timepoints_[next_suffix & mask_] = std::chrono::steady_clock::now();
+
+  using namespace std::placeholders;
+  portal_->sendInterest(std::move(interest));
+}
+
+void VegasTransportProtocol::stop() {
+  is_running_ = false;
+  portal_->stopEventsLoop();
+}
+
+void VegasTransportProtocol::onContentSegment(
+    Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+  uint32_t incremental_suffix = content_object->getName().getSuffix();
+  bool virtual_download = socket_->virtual_download_;
+
+  if (verifyContentObject(*content_object)) {
+    byte_count_ += content_object->getPayload().length();
+
+    if (TRANSPORT_EXPECT_FALSE(content_object->testRst())) {
+      is_final_block_number_discovered_ = true;
+      final_block_number_ = incremental_suffix;
+    }
+
+    if (!virtual_download) {
+      receive_buffer_.emplace(
+          std::make_pair(incremental_suffix, std::move(content_object)));
+      reassemble();
+    } else if (TRANSPORT_EXPECT_FALSE(is_final_block_number_discovered_ &&
+                                      incremental_suffix ==
+                                          final_block_number_)) {
+      returnContentToUser();
+    }
+  } else {
+    unverified_segments_.emplace(
+        std::make_pair(incremental_suffix, std::move(content_object)));
+  }
+}
+
+void VegasTransportProtocol::afterContentReception(
+    const Interest &interest, const ContentObject &content_object) {
+  increaseWindow();
+}
+
+void VegasTransportProtocol::afterDataUnsatisfied(uint64_t segment) {
+  decreaseWindow();
+}
+
+void VegasTransportProtocol::scheduleNextInterests() {
+  if (is_running_) {
+    uint32_t next_suffix;
+    while (interests_in_flight_ < current_window_size_) {
+      if (download_with_manifest_) {
+        if (suffix_queue_.size() * 2 < current_window_size_ &&
+            next_manifest_ < final_block_number_ && next_manifest_interval_) {
+          next_manifest_ += next_manifest_interval_;
+          sendInterest(next_manifest_);
+          continue;
+        }
+
+        if (suffix_queue_.pop(next_suffix)) {
+          //          next_suffix = suffix_queue_.front();
+          sendInterest(next_suffix);
+          //          suffix_queue_.pop_front();
+        } else {
+          if (!suffix_queue_completed_) {
+            TRANSPORT_LOGE("Empty queue!!!!!!");
+          }
+          break;
+        }
+      } else {
+        if (is_final_block_number_discovered_) {
+          if (next_suffix_ > final_block_number_) {
+            return;
+          }
+        }
+
+        sendInterest(next_suffix_++);
+      }
+    }
+  }
+}
+
+void VegasTransportProtocol::decreaseWindow() {
+  if (current_window_size_ > socket_->min_window_size_) {
+    current_window_size_ = std::ceil(current_window_size_ / 2);
+    socket_->current_window_size_ = current_window_size_;
+  }
+}
+
+void VegasTransportProtocol::increaseWindow() {
+  if (current_window_size_ < socket_->max_window_size_) {
+    current_window_size_++;
+    socket_->max_window_size_ = current_window_size_;
+  }
+};
+
+void VegasTransportProtocol::changeInterestLifetime(uint64_t segment) {
+  std::chrono::steady_clock::duration duration =
+      std::chrono::steady_clock::now() - interest_timepoints_[segment];
+  rtt_estimator_.addMeasurement(
+      std::chrono::duration_cast<std::chrono::microseconds>(duration));
+
+  RtoEstimator::Duration rto = rtt_estimator_.computeRto();
+  std::chrono::milliseconds lifetime =
+      std::chrono::duration_cast<std::chrono::milliseconds>(rto);
+
+  socket_->interest_lifetime_ = lifetime.count();
+}
+
+void VegasTransportProtocol::returnContentToUser() {
+  if (socket_->on_payload_retrieved_ != VOID_HANDLER) {
+    socket_->on_payload_retrieved_(*socket_, byte_count_,
+                                   std::make_error_code(std::errc(0)));
+  }
+
+  stop();
+}
+
+void VegasTransportProtocol::onManifest(
+    std::unique_ptr<ContentObjectManifest> &&manifest) {
+  if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+    return;
+  }
+
+  download_with_manifest_ = true;
+
+  uint32_t segment = manifest->getName().getSuffix();
+
+  if (verifyManifest(*manifest)) {
+    manifest->decode();
+
+    if (TRANSPORT_EXPECT_TRUE(manifest->getVersion() ==
+                              core::ManifestVersion::VERSION_1)) {
+      switch (manifest->getManifestType()) {
+        case core::ManifestType::INLINE_MANIFEST: {
+          auto _it = manifest->getSuffixList().begin();
+          auto _end = --manifest->getSuffixList().end();
+
+          if (TRANSPORT_EXPECT_FALSE(manifest->isFinalManifest())) {
+            _end++;
+          }
+
+          // Get final block number
+          is_final_block_number_discovered_ = true;
+          final_block_number_ = manifest->getFinalBlockNumber();
+
+          for (; _it != _end; _it++) {
+            suffix_hash_map_[_it->first] = std::make_pair(
+                std::vector<uint8_t>(_it->second, _it->second + 32),
+                manifest->getHashAlgorithm());
+            suffix_queue_.push(_it->first);
+          }
+
+          next_manifest_interval_ = manifest->getSuffixList().size();
+
+          if (manifest->isFinalManifest()) {
+            suffix_queue_completed_ = true;
+            // Give it a try
+            if (verifier_thread_) {
+              asio::io_service &io_service = portal_->getIoService();
+              io_service.post([this]() { scheduleNextInterests(); });
+            }
+          }
+
+          break;
+        }
+        case core::ManifestType::FLIC_MANIFEST: {
+          throw errors::NotImplementedException();
+        }
+        case core::ManifestType::FINAL_CHUNK_NUMBER: {
+          throw errors::NotImplementedException();
+        }
+      }
+    }
+
+    if (!socket_->virtual_download_) {
+      receive_buffer_.emplace(
+          std::make_pair(segment, std::move(manifest->getPacket())));
+      reassemble();
+    } else {
+      if (segment >= final_block_number_) {
+        stop();
+      }
+    }
+  }
+}
+
+bool VegasTransportProtocol::verifyManifest(
+    const ContentObjectManifest &manifest) {
+  if (!socket_->verify_signature_) {
+    return true;
+  }
+
+  bool is_data_secure = false;
+
+  if (socket_->on_content_object_verification_ == VOID_HANDLER) {
+    is_data_secure = static_cast<bool>(socket_->verifier_.verify(manifest));
+  } else if (socket_->on_content_object_verification_(*socket_, manifest)) {
+    is_data_secure = true;
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(!is_data_secure)) {
+    TRANSPORT_LOGE("Verification failed for %s\n",
+                   manifest.getName().toString().c_str());
+  }
+
+  return is_data_secure;
+}
+
+// TODO Add the name in the digest computation!
+void VegasTransportProtocol::onContentObject(
+    Interest::Ptr &&interest, ContentObject::Ptr &&content_object) {
+  uint32_t incremental_suffix = content_object->getName().getSuffix();
+
+  std::chrono::microseconds rtt;
+  Time now = std::chrono::steady_clock::now();
+  std::chrono::steady_clock::duration duration =
+      now - interest_timepoints_[incremental_suffix & mask_];
+  rtt = std::chrono::duration_cast<std::chrono::microseconds>(duration);
+
+  average_rtt_ = (0.7 * average_rtt_) + (0.3 * (double)rtt.count());
+
+  if (socket_->on_timer_expires_ != VOID_HANDLER) {
+    auto dt = std::chrono::duration_cast<TimeDuration>(now - socket_->t0_);
+    if (dt.count() > socket_->timer_interval_milliseconds_) {
+      socket_->on_timer_expires_(*socket_, byte_count_, dt,
+                                 current_window_size_, retx_count_,
+                                 std::round(average_rtt_));
+      socket_->t0_ = std::chrono::steady_clock::now();
+    }
+  }
+
+  interests_in_flight_--;
+
+  if (TRANSPORT_EXPECT_FALSE(!is_running_ || incremental_suffix == ~0_U64 ||
+                             receive_buffer_.find(incremental_suffix) !=
+                                 receive_buffer_.end())) {
+    return;
+  }
+
+  changeInterestLifetime(incremental_suffix);
+
+  if (socket_->on_content_object_input_ != VOID_HANDLER) {
+    socket_->on_content_object_input_(*socket_, *content_object);
+  }
+
+  if (socket_->on_interest_satisfied_ != VOID_HANDLER) {
+    socket_->on_interest_satisfied_(*socket_, *interest);
+  }
+
+  if (!interest_retransmissions_[incremental_suffix & mask_]) {
+    afterContentReception(*interest, *content_object);
+  }
+
+  if (TRANSPORT_EXPECT_FALSE(content_object->getPayloadType() ==
+                             PayloadType::MANIFEST)) {
+    // TODO Fix manifest!!
+    auto manifest =
+        std::make_unique<ContentObjectManifest>(std::move(content_object));
+
+    if (verifier_thread_ && incremental_suffix != 0) {
+      // verifier_thread_->add(std::bind(&VegasTransportProtocol::onManifest,
+      // this, std::move(manifest)));
+    } else {
+      onManifest(std::move(manifest));
+    }
+  } else if (content_object->getPayloadType() == PayloadType::CONTENT_OBJECT) {
+    if (verifier_thread_) {
+      // verifier_thread_->add(std::bind(&VegasTransportProtocol::onContentSegment,
+      // this, std::move(content_object)));
+    } else {
+      onContentSegment(std::move(interest), std::move(content_object));
+    }
+  }
+
+  scheduleNextInterests();
+}
+
+bool VegasTransportProtocol::verifyContentObject(
+    const ContentObject &content_object) {
+  if (!dynamic_cast<ConsumerSocket *>(socket_)->verify_signature_) {
+    return true;
+  }
+
+  uint64_t segment = content_object.getName().getSuffix();
+
+  bool ret = false;
+
+  if (download_with_manifest_) {
+    auto it = suffix_hash_map_.find(segment);
+    if (it != suffix_hash_map_.end()) {
+      auto hash_type = static_cast<utils::CryptoHashType>(it->second.second);
+      auto data_packet_digest = content_object.computeDigest(it->second.second);
+      auto data_packet_digest_bytes =
+          data_packet_digest.getDigest<uint8_t>().data();
+      std::vector<uint8_t> &manifest_digest_bytes = it->second.first;
+
+      if (utils::CryptoHash::compareBinaryDigest(data_packet_digest_bytes,
+                                                 manifest_digest_bytes.data(),
+                                                 hash_type)) {
+        suffix_hash_map_.erase(it);
+        ret = true;
+      } else {
+        throw errors::RuntimeException(
+            "Verification failure policy has to be implemented.");
+      }
+    }
+  } else {
+    ret = static_cast<bool>(
+        dynamic_cast<ConsumerSocket *>(socket_)->verifier_.verify(
+            content_object));
+
+    if (!ret) {
+      throw errors::RuntimeException(
+          "Verification failure policy has to be implemented.");
+    }
+  }
+
+  return ret;
+  ;
+}
+
+void VegasTransportProtocol::onTimeout(Interest::Ptr &&interest) {
+  TRANSPORT_LOGW("Timeout on %s", interest->getName().toString().c_str());
+
+  if (TRANSPORT_EXPECT_FALSE(!is_running_)) {
+    return;
+  }
+
+  interests_in_flight_--;
+
+  uint64_t segment = interest->getName().getSuffix();
+
+  // Do not retransmit interests asking contents that do not exist.
+  if (is_final_block_number_discovered_) {
+    if (segment > final_block_number_) {
+      return;
+    }
+  }
+
+  if (socket_->on_interest_timeout_ != VOID_HANDLER) {
+    socket_->on_interest_timeout_(*socket_, *interest);
+  }
+
+  afterDataUnsatisfied(segment);
+
+  if (TRANSPORT_EXPECT_TRUE(interest_retransmissions_[segment & mask_] <
+                            socket_->max_retransmissions_)) {
+    retx_count_++;
+
+    if (socket_->on_interest_retransmission_ != VOID_HANDLER) {
+      socket_->on_interest_retransmission_(*socket_, *interest);
+    }
+
+    if (socket_->on_interest_output_ != VOID_HANDLER) {
+      socket_->on_interest_output_(*socket_, *interest);
+    }
+
+    if (!is_running_) {
+      return;
+    }
+
+    // retransmit
+    interests_in_flight_++;
+    interest_retransmissions_[segment & mask_]++;
+
+    using namespace std::placeholders;
+    portal_->sendInterest(std::move(interest));
+  } else {
+    TRANSPORT_LOGE("Stop: reached max retx limit.");
+    partialDownload();
+    stop();
+  }
+}
+
+void VegasTransportProtocol::copyContent(const ContentObject &content_object) {
+  Array a = content_object.getPayload();
+
+  content_buffer_->insert(content_buffer_->end(), (uint8_t *)a.data(),
+                          (uint8_t *)a.data() + a.length());
+
+  bool download_completed =
+      is_final_block_number_discovered_ &&
+      content_object.getName().getSuffix() == final_block_number_;
+
+  if (TRANSPORT_EXPECT_FALSE(download_completed || !is_running_)) {
+    // asio::io_service& io_service = portal_->getIoService();
+    // io_service.post([this] () {
+    returnContentToUser();
+    // });
+  }
+}
+
+void VegasTransportProtocol::reassemble() {
+  uint64_t index = last_reassembled_segment_;
+  auto it = receive_buffer_.find(index);
+
+  do {
+    if (it->second->getPayloadType() == PayloadType::CONTENT_OBJECT) {
+      copyContent(*it->second);
+      receive_buffer_.erase(it);
+    }
+
+    index = ++last_reassembled_segment_;
+    it = receive_buffer_.find(index);
+  } while (it != receive_buffer_.end());
+}
+
+void VegasTransportProtocol::partialDownload() {
+  if (!socket_->virtual_download_) {
+    reassemble();
+  }
+
+  if (socket_->on_payload_retrieved_ != VOID_HANDLER) {
+    socket_->on_payload_retrieved_(
+        *socket_, byte_count_,
+        std::make_error_code(std::errc(std::errc::io_error)));
+  }
+}
+
+// TODO Check vegas protocol
+// void VegasTransportProtocol::checkForFastRetransmission(const Interest
+// &interest) {
+//   uint64_t segNumber = interest.getName().getSuffix();
+//   received_segments_[segNumber] = true;
+//   fast_retransmitted_segments.erase(segNumber);
+
+//   uint64_t possibly_lost_segment = 0;
+//   uint64_t highest_received_segment = received_segments_.rbegin()->first;
+
+//   for (uint64_t i = 0; i <= highest_received_segment; i++) {
+//     if (received_segments_.find(i) == received_segments_.end()) {
+//       if (fast_retransmitted_segments.find(i) ==
+//       fast_retransmitted_segments.end()) {
+//         possibly_lost_segment = i;
+//         uint8_t out_of_order_segments = 0;
+//         for (uint64_t j = i; j <= highest_received_segment; j++) {
+//           if (received_segments_.find(j) != received_segments_.end()) {
+//             out_of_order_segments++;
+//             if (out_of_order_segments >=
+//             default_values::max_out_of_order_segments) {
+//               fast_retransmitted_segments[possibly_lost_segment] = true;
+//               fastRetransmit(interest, possibly_lost_segment);
+//             }
+//           }
+//         }
+//       }
+//     }
+//   }
+// }
+
+// void VegasTransportProtocol::fastRetransmit(const Interest &interest,
+// uint32_t chunk_number) {
+//   if (interest_retransmissions_[chunk_number & mask_] <
+//       socket_->max_retransmissions_) {
+//     Name name = interest.getName();
+//     name.setSuffix(chunk_number);
+
+//     std::shared_ptr<Interest> retx_interest =
+//     std::make_shared<Interest>(name);
+
+//     if (socket_->on_interest_retransmission_ != VOID_HANDLER) {
+//       socket_->on_interest_retransmission_(*socket_, *retx_interest);
+//     }
+
+//     if (socket_->on_interest_output_ != VOID_HANDLER) {
+//       socket_->on_interest_output_(*socket_, *retx_interest);
+//     }
+
+//     if (!is_running_) {
+//       return;
+//     }
+
+//     interests_in_flight_++;
+//     interest_retransmissions_[chunk_number & mask_]++;
+
+//     using namespace std::placeholders;
+//     portal_->sendInterest(std::move(retx_interest));
+//   }
+// }
+
+void VegasTransportProtocol::removeAllPendingInterests() { portal_->clear(); }
+
+}  // end namespace protocol
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/vegas.h b/libtransport/src/hicn/transport/protocols/vegas.h
new file mode 100755 (executable)
index 0000000..7791ffc
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/protocols/protocol.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+#include <hicn/transport/utils/event_thread.h>
+#include <hicn/transport/utils/ring_buffer.h>
+#include <hicn/transport/utils/sharable_vector.h>
+
+#include <map>
+
+namespace transport {
+
+namespace protocol {
+
+typedef utils::CircularFifo<uint32_t, 1024 * 128> SuffixQueue;
+typedef std::chrono::time_point<std::chrono::steady_clock> Time;
+typedef std::chrono::milliseconds TimeDuration;
+
+class VegasTransportProtocol : public TransportProtocol {
+ public:
+  VegasTransportProtocol(interface::BaseSocket *icnet_socket);
+
+  virtual ~VegasTransportProtocol();
+
+  virtual void start(utils::SharableVector<uint8_t> &content_buffer) override;
+
+  void stop() override;
+
+  void resume() override;
+
+ protected:
+  void reset();
+
+  void sendInterest(std::uint64_t next_suffix);
+
+  void onContentSegment(Interest::Ptr &&interest,
+                        ContentObject::Ptr &&content_object);
+
+  bool verifyContentObject(const ContentObject &content_object);
+
+  bool verifyManifest(const interface::ContentObjectManifest &manifest);
+
+  virtual void onTimeout(Interest::Ptr &&interest) override;
+
+  void onManifest(std::unique_ptr<interface::ContentObjectManifest> &&manifest);
+
+  void onContentObject(Interest::Ptr &&interest,
+                       ContentObject::Ptr &&content_object) override;
+
+  virtual void changeInterestLifetime(uint64_t segment);
+
+  void scheduleNextInterests();
+
+  virtual void decreaseWindow();
+
+  virtual void increaseWindow();
+
+  virtual void afterContentReception(const Interest &interest,
+                                     const ContentObject &content_object);
+
+  virtual void afterDataUnsatisfied(uint64_t segment);
+
+  void reassemble();
+
+  void returnContentToUser();
+
+  void partialDownload();
+
+  virtual void copyContent(const ContentObject &content_object);
+
+  // virtual void checkForFastRetransmission(const Interest &interest);
+
+  // void fastRetransmit(const Interest &interest, uint32_t chunk_number);
+
+  void removeAllPendingInterests();
+
+ protected:
+  void handleTimeout(const std::error_code &ec);
+
+  // reassembly variables
+  volatile bool is_final_block_number_discovered_;
+  std::atomic<uint64_t> final_block_number_;
+  uint64_t last_reassembled_segment_;
+  std::shared_ptr<utils::SharableVector<uint8_t>> content_buffer_;
+  size_t content_buffer_size_;
+
+  // transmission variablesis_final_block_number_discovered_
+  double current_window_size_;
+  double pending_window_size_;
+  uint64_t interests_in_flight_;
+  uint64_t next_suffix_;
+  std::vector<std::uint32_t> interest_retransmissions_;
+  std::vector<std::chrono::steady_clock::time_point> interest_timepoints_;
+  RtoEstimator rtt_estimator_;
+
+  uint32_t retx_count_;
+
+  // buffers
+  std::unordered_map<std::uint32_t, ContentObject::Ptr>
+      receive_buffer_;  // verified segments by segment number
+  std::unordered_map<std::uint32_t, ContentObject::Ptr>
+      unverified_segments_;  // used with embedded manifests
+  std::unordered_map<std::uint32_t, ContentObject::Ptr>
+      verified_manifests_;  // by segment number
+
+  std::uint16_t interest_pool_index_;
+  std::uint16_t mask_;
+
+  // suffix randomization: since the suffixes in the manifests could not be in a
+  // sequential order, we need to map those suffixes into an ordered sequence.
+  std::unordered_map<std::uint64_t, std::uint64_t>
+      incremental_suffix_to_real_suffix_map_;
+  std::unordered_map<std::uint64_t, std::uint64_t>
+      real_suffix_to_incremental_suffix_map_;
+  std::uint32_t incremental_suffix_index_;
+
+  // verification
+  std::unordered_map<uint32_t, std::pair<std::vector<uint8_t>, HashAlgorithm>>
+      suffix_hash_map_;
+
+  // Fast Retransmission
+  std::map<uint64_t, bool> received_segments_;
+  std::unordered_map<uint64_t, bool> fast_retransmitted_segments;
+
+  // Suffix queue
+  volatile bool suffix_queue_completed_;
+  SuffixQueue suffix_queue_;
+
+  volatile bool download_with_manifest_;
+  uint32_t next_manifest_;
+  std::atomic<uint16_t> next_manifest_interval_;
+
+  std::unique_ptr<utils::EventThread> verifier_thread_;
+
+  uint32_t interest_tx_;
+  uint32_t interest_count_;
+
+  uint64_t byte_count_;
+  double average_rtt_;
+
+  std::unordered_map<uint32_t, uint64_t> sign_time_;
+};
+
+}  // namespace protocol
+
+}  // end namespace transport
diff --git a/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.cc
new file mode 100755 (executable)
index 0000000..f5f797b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_options_default_values.h>
+#include <hicn/transport/protocols/vegas_rto_estimator.h>
+
+#include <algorithm>
+#include <cmath>
+
+namespace transport {
+
+namespace protocol {
+
+using namespace interface;
+
+RtoEstimator::RtoEstimator(Duration min_rto)
+    : smoothed_rtt_(RtoEstimator::getInitialRtt().count()),
+      rtt_variation_(0),
+      first_measurement_(true),
+      last_rto_(min_rto.count()) {}
+
+void RtoEstimator::addMeasurement(Duration rtt) {
+  double duration = static_cast<double>(rtt.count());
+  if (first_measurement_) {
+    smoothed_rtt_ = duration;
+    rtt_variation_ = duration / 2;
+    first_measurement_ = false;
+  } else {
+    rtt_variation_ = (1 - default_values::beta) * rtt_variation_ +
+                     default_values::beta * std::abs(smoothed_rtt_ - duration);
+    smoothed_rtt_ = (1 - default_values::alpha) * smoothed_rtt_ +
+                    default_values::alpha * duration;
+  }
+}
+
+RtoEstimator::Duration RtoEstimator::computeRto() const {
+  double rto = smoothed_rtt_ +
+               std::max(double(default_values::clock_granularity.count()),
+                        default_values::k* rtt_variation_);
+  return Duration(static_cast<Duration::rep>(rto));
+}
+
+}  // end namespace protocol
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.h b/libtransport/src/hicn/transport/protocols/vegas_rto_estimator.h
new file mode 100755 (executable)
index 0000000..e84afc4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+
+// Implementation inspired from RFC6298
+// (https://tools.ietf.org/search/rfc6298#ref-JK88)
+
+namespace transport {
+
+namespace protocol {
+
+class RtoEstimator {
+ public:
+  typedef std::chrono::microseconds Duration;
+
+  static Duration getInitialRtt() { return std::chrono::seconds(1); }
+
+  RtoEstimator(Duration min_rto = std::chrono::seconds(1));
+
+  void addMeasurement(Duration measure);
+
+  Duration computeRto() const;
+
+ private:
+  double smoothed_rtt_;
+  double rtt_variation_;
+  bool first_measurement_;
+  double last_rto_;
+};
+
+}  // end namespace protocol
+
+}  // end namespace transport
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/CMakeLists.txt b/libtransport/src/hicn/transport/utils/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..088fb58
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+
+list(APPEND SOURCE_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/uri.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/signer.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/verifier.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/identity.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/log.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/membuf.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/content_store.cc
+)
+
+
+list(APPEND HEADER_FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/array.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/hash.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/uri.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/daemonizator.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/sharable_vector.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/branch_prediction.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/deadline_timer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/ring_buffer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/event_reactor.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/min_filter.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/stream_buffer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/endianess.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/literals.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/signer.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/verifier.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hasher.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/crypto_suite.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/crypto_hash_type.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/identity.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/conversions.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/linux.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/log.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/event_thread.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/object_pool.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/membuf.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/spinlock.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/content_store.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/key_id.h
+)
+
+if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+  list(APPEND HEADER_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/fd_deadline_timer.h
+  )
+
+  list(APPEND SOURCE_FILES
+    ${CMAKE_CURRENT_SOURCE_DIR}/epoll_event_reactor.cc
+  )
+endif()
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
diff --git a/libtransport/src/hicn/transport/utils/array.h b/libtransport/src/hicn/transport/utils/array.h
new file mode 100755 (executable)
index 0000000..a3a66e4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+
+#include <cstddef>
+
+namespace utils {
+
+template <typename T>
+class Array {
+ public:
+  explicit Array(const T *array, size_t size) : array_(array), size_(size) {
+    this->array_ = array;
+    this->size_ = size;
+  }
+
+  Array() : array_(nullptr), size_(0) {
+    this->array_ = nullptr;
+    this->size_ = 0;
+  }
+
+  TRANSPORT_ALWAYS_INLINE const T *data() const { return array_; }
+
+  TRANSPORT_ALWAYS_INLINE T *writableData() const {
+    return const_cast<T *>(array_);
+  }
+
+  TRANSPORT_ALWAYS_INLINE std::size_t length() const { return size_; }
+
+  TRANSPORT_ALWAYS_INLINE Array &setData(const T *data) {
+    array_ = data;
+    return *this;
+  }
+
+  TRANSPORT_ALWAYS_INLINE Array &setSize(std::size_t size) {
+    size_ = size;
+    return *this;
+  }
+
+  TRANSPORT_ALWAYS_INLINE bool empty() { return !size_; }
+
+ private:
+  const T *array_;
+  std::size_t size_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/branch_prediction.h b/libtransport/src/hicn/transport/utils/branch_prediction.h
new file mode 100755 (executable)
index 0000000..b12282f
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#undef TRANSPORT_EXPECT_TRUE
+#undef TRANSPORT_EXPECT_FALSE
+
+#define TRANSPORT_EXPECT_TRUE(x) __builtin_expect((x), 1)
+#define TRANSPORT_EXPECT_FALSE(x) __builtin_expect((x), 0)
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/content_store.cc b/libtransport/src/hicn/transport/utils/content_store.cc
new file mode 100755 (executable)
index 0000000..4c7637d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/utils/content_store.h>
+
+namespace utils {
+
+ContentStore::ContentStore(std::size_t max_packets)
+    : max_content_store_size_(max_packets) {}
+
+ContentStore::~ContentStore() {}
+
+void ContentStore::insert(
+    const std::shared_ptr<ContentObject> &content_object) {
+  if (max_content_store_size_ == 0) {
+    return;
+  }
+
+  std::unique_lock<std::mutex> lock(cs_mutex_);
+
+  if (TRANSPORT_EXPECT_FALSE(content_store_hash_table_.size() !=
+                             lru_list_.size())) {
+    TRANSPORT_LOGW("Inconsistent size!!!!");
+    TRANSPORT_LOGW("Hash Table: %zu |||| FIFO List: %zu",
+                   content_store_hash_table_.size(), lru_list_.size());
+  }
+
+  // Check if the content can be cached
+  if (content_object->getLifetime() > 0) {
+    if (content_store_hash_table_.size() >= max_content_store_size_) {
+      content_store_hash_table_.erase(lru_list_.back());
+      lru_list_.pop_back();
+    }
+
+    // Insert new item
+
+    auto it = content_store_hash_table_.find(content_object->getName());
+    if (it != content_store_hash_table_.end()) {
+      lru_list_.erase(it->second.second);
+      content_store_hash_table_.erase(content_object->getName());
+    }
+
+    lru_list_.push_front(std::cref(content_object->getName()));
+    auto pos = lru_list_.begin();
+    content_store_hash_table_[content_object->getName()] = ContentStoreEntry(
+        ObjectTimeEntry(content_object, std::chrono::steady_clock::now()), pos);
+  }
+}
+
+const std::shared_ptr<ContentObject> &ContentStore::find(
+    const Interest &interest) {
+  std::unique_lock<std::mutex> lock(cs_mutex_);
+  auto it = content_store_hash_table_.find(interest.getName());
+  if (it != content_store_hash_table_.end()) {
+    // if (std::chrono::duration_cast<std::chrono::milliseconds>(
+    //     std::chrono::steady_clock::now() - it->second.first.second).count()
+    //     < it->second.first.first->getLifetime() ||
+    //     it->second.first.first->getLifetime() ==
+    //     default_values::never_expire_time) {
+    return it->second.first.first;
+    // }
+  }
+
+  return empty_reference_;
+}
+
+void ContentStore::erase(const Name &exact_name) {
+  std::unique_lock<std::mutex> lock(cs_mutex_);
+  auto it = content_store_hash_table_.find(exact_name);
+  lru_list_.erase(it->second.second);
+  content_store_hash_table_.erase(exact_name);
+}
+
+void ContentStore::setLimit(size_t max_packets) {
+  max_content_store_size_ = max_packets;
+}
+
+std::size_t ContentStore::getLimit() const { return max_content_store_size_; }
+
+std::size_t ContentStore::size() const {
+  return content_store_hash_table_.size();
+}
+
+void ContentStore::printContent() {
+  for (auto &item : content_store_hash_table_) {
+    if (item.second.first.first->getPayloadType() ==
+        transport::core::PayloadType::MANIFEST) {
+      TRANSPORT_LOGI("Manifest: %s\n",
+                     item.second.first.first->getName().toString().c_str());
+    }
+  }
+}
+
+}  // end namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/content_store.h b/libtransport/src/hicn/transport/utils/content_store.h
new file mode 100755 (executable)
index 0000000..ab4963f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/interfaces/socket.h>
+
+#include <mutex>
+
+namespace transport {
+
+namespace core {
+class Name;
+class ContentObject;
+class Interest;
+}  // namespace core
+
+}  // namespace transport
+
+namespace utils {
+
+using Name = transport::core::Name;
+using ContentObject = transport::core::ContentObject;
+using Interest = transport::core::Interest;
+
+typedef std::pair<std::shared_ptr<ContentObject>,
+                  std::chrono::steady_clock::time_point>
+    ObjectTimeEntry;
+typedef std::pair<ObjectTimeEntry,
+                  std::list<std::reference_wrapper<const Name>>::iterator>
+    ContentStoreEntry;
+typedef std::list<std::reference_wrapper<const Name>> LRUList;
+typedef std::unordered_map<Name, ContentStoreEntry> ContentStoreHashTable;
+
+class ContentStore {
+ public:
+  explicit ContentStore(std::size_t max_packets = 65536);
+
+  ~ContentStore();
+
+  void insert(const std::shared_ptr<ContentObject> &content_object);
+
+  const std::shared_ptr<ContentObject> &find(const Interest &interest);
+
+  void erase(const Name &exact_name);
+
+  void setLimit(size_t max_packets);
+
+  size_t getLimit() const;
+
+  size_t size() const;
+
+  void printContent();
+
+ private:
+  ContentStoreHashTable content_store_hash_table_;
+  LRUList lru_list_;
+  std::shared_ptr<ContentObject> empty_reference_;
+  std::size_t max_content_store_size_;
+  std::mutex cs_mutex_;
+};
+
+}  // end namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/conversions.h b/libtransport/src/hicn/transport/utils/conversions.h
new file mode 100755 (executable)
index 0000000..24b5292
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+
+#include <stdio.h>
+#include <cstdint>
+#include <string>
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int convertStringToMacAddress(
+    const std::string& mac_address, uint8_t* mac_byte_array) {
+  const char* mac = mac_address.c_str();
+
+  sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac_byte_array[0],
+         &mac_byte_array[1], &mac_byte_array[2], &mac_byte_array[3],
+         &mac_byte_array[4], &mac_byte_array[5]);
+
+  return 0;
+}
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hash.h b/libtransport/src/hicn/transport/utils/crypto_hash.h
new file mode 100755 (executable)
index 0000000..0c15c8b
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/array.h>
+#include <hicn/transport/utils/crypto_hash_type.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHash.h>
+};
+
+#include <cstring>
+#include <unordered_map>
+
+namespace utils {
+
+class CryptoHasher;
+
+struct EnumClassHash {
+  template <typename T>
+  std::size_t operator()(T t) const {
+    return static_cast<std::size_t>(t);
+  }
+};
+
+static std::unordered_map<CryptoHashType, std::size_t, EnumClassHash>
+    hash_size_map = {{CryptoHashType::SHA_256, 32},
+                     {CryptoHashType::CRC32C, 4},
+                     {CryptoHashType::SHA_512, 64}};
+
+class Signer;
+class Verifier;
+
+class CryptoHash {
+  friend class CryptoHasher;
+  friend class Signer;
+  friend class Verifier;
+
+ public:
+  CryptoHash() : hash_(nullptr) {}
+
+  CryptoHash(const CryptoHash& other) {
+    if (other.hash_) {
+      hash_ = parcCryptoHash_Acquire(other.hash_);
+    }
+  }
+
+  CryptoHash(CryptoHash&& other) {
+    if (other.hash_) {
+      hash_ = parcCryptoHash_Acquire(other.hash_);
+    }
+  }
+
+  template <typename T>
+  CryptoHash(const T* buffer, std::size_t length, CryptoHashType hash_type) {
+    hash_ = parcCryptoHash_CreateFromArray(
+        static_cast<PARCCryptoHashType>(hash_type), buffer, length);
+  }
+
+  ~CryptoHash() {
+    if (hash_) {
+      parcCryptoHash_Release(&hash_);
+    }
+  }
+
+  CryptoHash& operator=(const CryptoHash& other) {
+    if (other.hash_) {
+      hash_ = parcCryptoHash_Acquire(other.hash_);
+    }
+
+    return *this;
+  }
+
+  template <typename T>
+  utils::Array<T> getDigest() const {
+    return utils::Array<T>(
+        static_cast<T*>(parcBuffer_Overlay(parcCryptoHash_GetDigest(hash_), 0)),
+        parcBuffer_Remaining(parcCryptoHash_GetDigest(hash_)));
+  }
+
+  CryptoHashType getType() {
+    return static_cast<CryptoHashType>(parcCryptoHash_GetDigestType(hash_));
+  }
+
+  template <typename T>
+  static bool compareBinaryDigest(const T* digest1, const T* digest2,
+                                  CryptoHashType hash_type) {
+    if (hash_size_map.find(hash_type) == hash_size_map.end()) {
+      return false;
+    }
+
+    return !static_cast<bool>(
+        std::memcmp(digest1, digest2, hash_size_map[hash_type]));
+  }
+
+ private:
+  PARCCryptoHash* hash_;
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hash_type.h b/libtransport/src/hicn/transport/utils/crypto_hash_type.h
new file mode 100755 (executable)
index 0000000..b7597e2
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+extern "C" {
+#include <parc/security/parc_CryptoHashType.h>
+};
+
+namespace utils {
+
+enum class CryptoHashType : uint8_t {
+  SHA_256 = PARCCryptoHashType_SHA256,
+  SHA_512 = PARCCryptoHashType_SHA512,
+  CRC32C = PARCCryptoHashType_CRC32C,
+  NULL_HASH = PARCCryptoHashType_NULL
+};
+
+}
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_hasher.h b/libtransport/src/hicn/transport/utils/crypto_hasher.h
new file mode 100755 (executable)
index 0000000..c34a26f
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/utils/crypto_hash.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHasher.h>
+};
+
+namespace utils {
+
+class CryptoHasher {
+ public:
+  CryptoHasher(CryptoHashType hash_type)
+      : hasher_(parcCryptoHasher_Create(
+            static_cast<PARCCryptoHashType>(hash_type))),
+        managed_(true) {}
+
+  CryptoHasher(PARCCryptoHasher* hasher) : hasher_(hasher), managed_(false) {}
+
+  ~CryptoHasher() {
+    if (managed_) {
+      parcCryptoHasher_Release(&hasher_);
+    }
+  }
+
+  CryptoHasher& init() {
+    if (parcCryptoHasher_Init(hasher_) == -1) {
+      throw errors::RuntimeException("Cryptohash init failed.");
+    }
+
+    return *this;
+  }
+
+  template <typename T>
+  CryptoHasher& updateBytes(const T* buffer, std::size_t length) {
+    if (parcCryptoHasher_UpdateBytes(hasher_, buffer, length) == -1) {
+      throw errors::RuntimeException("Cryptohash updateBytes failed.");
+    }
+    return *this;
+  }
+
+  CryptoHash finalize() {
+    CryptoHash hash;
+    hash.hash_ = parcCryptoHasher_Finalize(hasher_);
+    return hash;
+  }
+
+ private:
+  PARCCryptoHasher* hasher_;
+  bool managed_;
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/crypto_suite.h b/libtransport/src/hicn/transport/utils/crypto_suite.h
new file mode 100755 (executable)
index 0000000..8ae32b8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+extern "C" {
+#include <parc/security/parc_CryptoSuite.h>
+};
+
+namespace utils {
+
+enum class CryptoSuite : uint8_t {
+  RSA_SHA256 = PARCCryptoSuite_RSA_SHA256,
+  DSA_SHA256 = PARCCryptoSuite_DSA_SHA256,
+  RSA_SHA512 = PARCCryptoSuite_RSA_SHA512,
+  HMAC_SHA256 = PARCCryptoSuite_HMAC_SHA256,
+  HMAC_SHA512 = PARCCryptoSuite_HMAC_SHA512,
+  NULL_CRC32C = PARCCryptoSuite_NULL_CRC32C,
+  ECDSA_256K1 = PARCCryptoSuite_ECDSA_SHA256,
+  UNKNOWN = PARCCryptoSuite_UNKNOWN
+};
+
+}
diff --git a/libtransport/src/hicn/transport/utils/daemonizator.cc b/libtransport/src/hicn/transport/utils/daemonizator.cc
new file mode 100755 (executable)
index 0000000..d9b3109
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/utils/daemonizator.h>
+#include <hicn/transport/utils/log.h>
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace utils {
+
+void Daemonizator::daemonize(bool close_fds) {
+  pid_t process_id = 0;
+  pid_t sid = 0;
+
+  // Create child process
+  process_id = fork();
+
+  // Indication of fork() failure
+  if (process_id < 0) {
+    throw errors::RuntimeException("Fork failed.");
+  }
+
+  // PARENT PROCESS. Need to kill it.
+  if (process_id > 0) {
+    TRANSPORT_LOGE("Process id of child process %d", process_id);
+    // return success in exit status
+    exit(EXIT_SUCCESS);
+  }
+
+  // unmask the file mode
+  umask(0);
+
+  // set new session
+  sid = setsid();
+  if (sid < 0) {
+    // Return failure
+    exit(EXIT_FAILURE);
+  }
+
+  // Change the current working directory to root.
+  int ret = chdir("/");
+
+  if (ret < 0) {
+    throw errors::RuntimeException("Error changing working directory to root");
+  }
+
+  // Close stdin. Redirect stdout and stderr to file if possible
+
+  if (close_fds) {
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+  }
+
+  close(STDIN_FILENO);
+
+  // Really start application
+}
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/daemonizator.h b/libtransport/src/hicn/transport/utils/daemonizator.h
new file mode 100755 (executable)
index 0000000..a21ce8a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+#include <cstdlib>
+namespace utils {
+
+class Daemonizator {
+ public:
+  static void daemonize(bool close_fds = true);
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/deadline_timer.h b/libtransport/src/hicn/transport/utils/deadline_timer.h
new file mode 100755 (executable)
index 0000000..61f9061
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/utils/event_reactor.h>
+
+#include <chrono>
+#include <cstddef>
+#include <cstring>
+#include <utility>
+
+namespace std {
+namespace chrono {
+namespace detail {
+
+template <typename From, typename To>
+struct posix_duration_cast;
+
+// chrono -> timespec caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<std::chrono::duration<Rep, Period>,
+                           struct timespec> {
+  static struct timespec cast(std::chrono::duration<Rep, Period> const &d) {
+    struct timespec tv;
+
+    std::chrono::seconds const sec =
+        std::chrono::duration_cast<std::chrono::seconds>(d);
+
+    tv.tv_sec = sec.count();
+    tv.tv_nsec =
+        std::chrono::duration_cast<std::chrono::nanoseconds>(d - sec).count();
+
+    return tv;
+  }
+};
+
+// timespec -> chrono caster
+template <typename Rep, typename Period>
+struct posix_duration_cast<struct timespec,
+                           std::chrono::duration<Rep, Period>> {
+  static std::chrono::duration<Rep, Period> cast(struct timespec const &tv) {
+    return std::chrono::duration_cast<std::chrono::duration<Rep, Period>>(
+        std::chrono::seconds(tv.tv_sec) + std::chrono::nanoseconds(tv.tv_nsec));
+  }
+};
+
+}  // namespace detail
+
+// chrono -> timespec
+template <typename T, typename Rep, typename Period>
+auto duration_cast(std::chrono::duration<Rep, Period> const &d) ->
+    typename std::enable_if<std::is_same<T, struct timespec>::value,
+                            struct timespec>::type {
+  return detail::posix_duration_cast<std::chrono::duration<Rep, Period>,
+                                     timespec>::cast(d);
+}
+
+// timespec -> chrono
+template <typename Duration>
+Duration duration_cast(struct timespec const &tv) {
+  return detail::posix_duration_cast<struct timespec, Duration>::cast(tv);
+}
+
+}  // namespace chrono
+}  // namespace std
+
+namespace utils {
+
+template <typename Implementation>
+class DeadlineTimer {
+ public:
+  virtual ~DeadlineTimer() = default;
+
+  template <typename WaitHandler>
+  void asyncWait(WaitHandler &&callback) {
+    static_cast<Implementation *>(this)->asyncWaitImpl(
+        std::forward<WaitHandler>(callback));
+  }
+
+  void wait() { static_cast<Implementation *>(this)->waitImpl(); }
+
+  template <typename T, typename R>
+  void expiresFromNow(std::chrono::duration<T, R> &&duration) {
+    static_cast<Implementation *>(this)->expiresFromNowImpl(
+        std::forward<std::chrono::duration<T, R>>(duration));
+  }
+
+  template <typename TimePoint,
+            typename = typename std::enable_if<
+                std::is_same<std::remove_reference_t<TimePoint>,
+                             std::chrono::steady_clock::time_point>::value,
+                TimePoint>::type>
+  void expiresAt(TimePoint &&time_point) {
+    static_cast<Implementation *>(this)->expiresAtImpl(
+        std::forward<TimePoint>(time_point));
+  }
+
+  void cancel() { static_cast<Implementation *>(this)->cancelImpl(); }
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/endianess.h b/libtransport/src/hicn/transport/utils/endianess.h
new file mode 100755 (executable)
index 0000000..a3ec21c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+
+#include <arpa/inet.h>
+#include <cstring>
+
+namespace utils {
+
+namespace {
+
+template <size_t Size>
+struct uint_types_by_size;
+
+#define GENERATOR(sz, fn)                                                    \
+  static TRANSPORT_ALWAYS_INLINE uint##sz##_t byteswap_gen(uint##sz##_t v) { \
+    return fn(v);                                                            \
+  }                                                                          \
+  template <>                                                                \
+  struct uint_types_by_size<sz / 8> {                                        \
+    using type = uint##sz##_t;                                               \
+  };
+
+GENERATOR(8, uint8_t)
+#ifdef _MSC_VER
+GENERATOR(64, _byteswap_uint64)
+GENERATOR(32, _byteswap_ulong)
+GENERATOR(16, _byteswap_ushort)
+#else
+GENERATOR(64, __builtin_bswap64)
+GENERATOR(32, __builtin_bswap32)
+GENERATOR(16, __builtin_bswap16)
+#endif
+
+template <typename T>
+struct EndianInt {
+  static_assert(
+      (std::is_integral<T>::value && !std::is_same<T, bool>::value) ||
+          std::is_floating_point<T>::value,
+      "template type parameter must be non-bool integral or floating point");
+
+  static T swap(T x) {
+    // we implement this with memcpy because that is defined behavior in C++
+    // we rely on compilers to optimize away the memcpy calls
+    constexpr auto s = sizeof(T);
+    using B = typename uint_types_by_size<s>::type;
+    B b;
+    std::memcpy(&b, &x, s);
+    b = byteswap_gen(b);
+    std::memcpy(&x, &b, s);
+    return x;
+  }
+  static T big(T x) {
+    return portability::little_endian_arch ? EndianInt::swap(x) : x;
+  }
+  static T little(T x) {
+    return portability::big_endian_arch ? EndianInt::swap(x) : x;
+  }
+};
+
+}  // namespace
+
+// big* convert between native and big-endian representations
+// little* convert between native and little-endian representations
+// swap* convert between big-endian and little-endian representations
+//
+// ntohs, htons == big16
+// ntohl, htonl == big32
+#define GENERATOR1(fn, t, sz) \
+  static t fn##sz(t x) { return fn<t>(x); }
+
+#define GENERATOR2(t, sz) \
+  GENERATOR1(swap, t, sz) \
+  GENERATOR1(big, t, sz)  \
+  GENERATOR1(little, t, sz)
+
+#define GENERATOR3(sz)         \
+  GENERATOR2(uint##sz##_t, sz) \
+  GENERATOR2(int##sz##_t, sz)
+
+class Endian {
+ public:
+  enum class Order : uint8_t { LITTLE, BIG };
+
+  static constexpr Order order =
+      portability::little_endian_arch ? Order::LITTLE : Order::BIG;
+
+  template <typename T>
+  static T swap(T x) {
+    return EndianInt<T>::swap(x);
+  }
+
+  template <typename T>
+  static T big(T x) {
+    return EndianInt<T>::big(x);
+  }
+
+  template <typename T>
+  static T little(T x) {
+    return EndianInt<T>::little(x);
+  }
+
+#if !defined(__ANDROID__)
+  GENERATOR3(64)
+  GENERATOR3(32)
+  GENERATOR3(16)
+  GENERATOR3(8)
+#endif
+};
+
+template <typename T>
+static TRANSPORT_ALWAYS_INLINE T ntoh(T x) {
+  return Endian::order == Endian::Order::LITTLE ? Endian::little(x) : x;
+}
+
+template <typename T>
+static TRANSPORT_ALWAYS_INLINE T hton(T x) {
+  return Endian::order == Endian::Order::LITTLE ? Endian::big(x) : x;
+}
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc b/libtransport/src/hicn/transport/utils/epoll_event_reactor.cc
new file mode 100755 (executable)
index 0000000..81b4718
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/utils/branch_prediction.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/fd_deadline_timer.h>
+
+#include <signal.h>
+#include <unistd.h>
+#include <iostream>
+
+namespace utils {
+
+EpollEventReactor::EpollEventReactor()
+    : epoll_fd_(epoll_create(20000)), run_event_loop_(true) {}
+
+EpollEventReactor::~EpollEventReactor() { close(epoll_fd_); }
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events) {
+  if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+    TRANSPORT_LOGE("invalid fd %d", fd);
+    return -1;
+  }
+
+  struct epoll_event evt;
+  std::memset(&evt, 0, sizeof(evt));
+  evt.events = events;
+  evt.data.fd = fd;
+
+  if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &evt) <
+                             0)) {
+    TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+    return -1;
+  }
+
+  return 0;
+}
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events,
+                                         EventCallback &callback) {
+  auto it = event_callback_map_.find(fd);
+  event_callback_map_[fd] = callback;
+  if (it != event_callback_map_.end()) {
+    event_callback_map_[fd] = callback;
+  } else {
+    return addFileDescriptor(fd, events);
+  }
+
+  return 0;
+}
+
+int EpollEventReactor::addFileDescriptor(int fd, uint32_t events,
+                                         EventCallback &&callback) {
+  auto it = event_callback_map_.find(fd);
+  event_callback_map_[fd] = callback;
+  if (it != event_callback_map_.end()) {
+    event_callback_map_[fd] = callback;
+  } else {
+    return addFileDescriptor(fd, events);
+  }
+
+  return 0;
+}
+
+int EpollEventReactor::modFileDescriptor(int fd, uint32_t events) {
+  if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+    TRANSPORT_LOGE("invalid fd %d", fd);
+    return -1;
+  }
+
+  struct epoll_event evt;
+  memset(&evt, 0, sizeof(evt));
+  evt.events = events;
+  evt.data.fd = fd;
+
+  if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &evt) <
+                             0)) {
+    TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+    return -1;
+  }
+
+  return 0;
+}
+
+std::size_t EpollEventReactor::mapSize() { return event_callback_map_.size(); }
+
+int EpollEventReactor::delFileDescriptor(int fd) {
+  if (TRANSPORT_EXPECT_FALSE(fd < 0)) {
+    TRANSPORT_LOGE("invalid fd %d", fd);
+    return -1;
+  }
+
+  struct epoll_event evt;
+  memset(&evt, 0, sizeof(evt));
+
+  if (TRANSPORT_EXPECT_FALSE(epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &evt) <
+                             0)) {
+    TRANSPORT_LOGE("epoll_ctl: %s fd %d", strerror(errno), fd);
+    return -1;
+  }
+
+  event_callback_map_.erase(fd);
+
+  return 0;
+}
+
+void EpollEventReactor::runEventLoop(int timeout) {
+  Event evt[128];
+  int en = 0;
+
+  // evt.events = EPOLLIN | EPOLLOUT;
+  sigset_t sigset;
+  sigemptyset(&sigset);
+
+  while (run_event_loop_) {
+    memset(&evt, 0, sizeof(evt));
+
+    en = epoll_pwait(epoll_fd_, evt, 128, timeout, &sigset);
+
+    if (TRANSPORT_EXPECT_FALSE(en < 0)) {
+      TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+      return;
+    }
+
+    for (int i = 0; i < en; i++) {
+      if (evt[i].data.fd > 0) {
+        auto it = event_callback_map_.find(evt[i].data.fd);
+        if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
+          TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+        } else {
+          event_callback_map_[evt[i].data.fd](evt[i]);
+        }
+      } else {
+        TRANSPORT_LOGE("unexpected event. fd %d", evt[i].data.fd);
+      }
+    }
+  }
+}
+
+void EpollEventReactor::runOneEvent() {
+  Event evt;
+  int en = 0;
+
+  //  evt.events = EPOLLIN | EPOLLOUT;
+  sigset_t sigset;
+  sigemptyset(&sigset);
+
+  memset(&evt, 0, sizeof(evt));
+
+  en = epoll_pwait(epoll_fd_, &evt, 1, -1, &sigset);
+
+  if (TRANSPORT_EXPECT_FALSE(en < 0)) {
+    TRANSPORT_LOGE("epoll_pwait: %s", strerror(errno));
+    return;
+  }
+
+  if (TRANSPORT_EXPECT_TRUE(evt.data.fd > 0)) {
+    auto it = event_callback_map_.find(evt.data.fd);
+    if (TRANSPORT_EXPECT_FALSE(it == event_callback_map_.end())) {
+      TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+    } else {
+      event_callback_map_[evt.data.fd](evt);
+    }
+  } else {
+    TRANSPORT_LOGE("unexpected event. fd %d", evt.data.fd);
+  }
+}
+
+void EpollEventReactor::stop() { run_event_loop_ = false; }
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/epoll_event_reactor.h b/libtransport/src/hicn/transport/utils/epoll_event_reactor.h
new file mode 100755 (executable)
index 0000000..bb4db3e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/utils/event_reactor.h>
+
+#include <sys/epoll.h>
+#include <cstddef>
+#include <functional>
+#include <mutex>
+#include <unordered_map>
+
+#define FD_NUMBER 20000
+
+namespace utils {
+
+typedef struct epoll_event Event;
+typedef std::function<int(const Event &)> EventCallback;
+typedef std::unordered_map<int, EventCallback> EventCallbackMap;
+
+class EpollEventReactor : public EventReactor {
+ public:
+  explicit EpollEventReactor();
+
+  ~EpollEventReactor();
+
+  int addFileDescriptor(int fd, uint32_t events, EventCallback &callback);
+
+  int addFileDescriptor(int fd, uint32_t events, EventCallback &&callback);
+
+  int delFileDescriptor(int fd);
+
+  int modFileDescriptor(int fd, uint32_t events);
+
+  void runEventLoop(int timeout = -1) override;
+
+  void runOneEvent() override;
+
+  void stop() override;
+
+  std::size_t mapSize();
+
+ private:
+  int addFileDescriptor(int fd, uint32_t events);
+
+  int epoll_fd_;
+  volatile bool run_event_loop_;
+  EventCallbackMap event_callback_map_;
+  std::mutex event_callback_map_mutex_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/event_reactor.h b/libtransport/src/hicn/transport/utils/event_reactor.h
new file mode 100755 (executable)
index 0000000..4f8b582
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <functional>
+#include <system_error>
+
+namespace utils {
+
+typedef std::function<void(const std::error_code &ec)> UserCallback;
+
+class EventReactor {
+ public:
+  virtual ~EventReactor() = default;
+
+  virtual void runEventLoop(int timeout = -1) = 0;
+
+  virtual void runOneEvent() = 0;
+
+  virtual void stop() = 0;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/event_thread.h b/libtransport/src/hicn/transport/utils/event_thread.h
new file mode 100755 (executable)
index 0000000..3bf08c9
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/errors/runtime_exception.h>
+#include <memory>
+
+#include <asio.hpp>
+
+namespace utils {
+
+class EventThread {
+ private:
+  // No copies
+  EventThread(const EventThread&) = delete;  // non construction-copyable
+  EventThread& operator=(const EventThread&) = delete;  // non copyable
+
+ public:
+  explicit EventThread(asio::io_service& io_service)
+      : internal_io_service_(nullptr),
+        io_service_(io_service),
+        work_(io_service_),
+        thread_(nullptr) {
+    run();
+  }
+
+  explicit EventThread()
+      : internal_io_service_(std::make_unique<asio::io_service>()),
+        io_service_(*internal_io_service_),
+        work_(io_service_),
+        thread_(nullptr) {
+    run();
+  }
+
+  ~EventThread() { stop(); }
+
+  void run() {
+    if (stopped()) {
+      io_service_.reset();
+    }
+
+    thread_ = std::make_unique<std::thread>([this]() { io_service_.run(); });
+  }
+
+  std::thread::id getThreadId() const {
+    if (thread_) {
+      return thread_->get_id();
+    } else {
+      throw errors::RuntimeException("Event thread is not running.");
+    }
+  }
+
+  template <typename Func>
+  void add(Func&& f) {
+    // If the function f
+    // TODO USe post in mac os, asio->post in xenial
+    io_service_.post(std::forward<Func&&>(f));
+  }
+
+  template <typename Func>
+  void tryRunHandlerNow(Func&& f) {
+    io_service_.dispatch(std::forward<Func&&>(f));
+  }
+
+  void stop() {
+    TRANSPORT_LOGI("Stopping event thread!");
+
+    io_service_.stop();
+
+    if (thread_ && thread_->joinable()) {
+      thread_->join();
+    }
+
+    thread_.reset();
+  }
+
+  bool stopped() { return io_service_.stopped(); }
+
+  asio::io_service& getIoService() { return io_service_; }
+
+ private:
+  std::unique_ptr<asio::io_service> internal_io_service_;
+  asio::io_service& io_service_;
+  asio::io_service::work work_;
+  std::unique_ptr<std::thread> thread_;
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/fd_deadline_timer.h b/libtransport/src/hicn/transport/utils/fd_deadline_timer.h
new file mode 100755 (executable)
index 0000000..3ed4590
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/utils/deadline_timer.h>
+#include <hicn/transport/utils/epoll_event_reactor.h>
+#include <hicn/transport/utils/log.h>
+
+#include <chrono>
+#include <cstddef>
+
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+namespace utils {
+
+class FdDeadlineTimer : public DeadlineTimer<FdDeadlineTimer> {
+ public:
+  explicit FdDeadlineTimer(EpollEventReactor &reactor)
+      : reactor_(reactor),
+        timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)),
+        flags_(0) {
+    if (timer_fd_ == -1) {
+      throw errors::RuntimeException("Impossible to create the timer!");
+    }
+  }
+
+  ~FdDeadlineTimer() { close(timer_fd_); }
+
+  template <typename WaitHandler>
+  void asyncWaitImpl(WaitHandler &&callback) {
+    // ASIO_WAIT_HANDLER_CHECK(WaitHandler, callback) type_check;
+
+    if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) {
+      throw errors::RuntimeException("Impossible to set the timer!");
+    }
+
+    uint32_t events = EPOLLIN;
+
+    reactor_.addFileDescriptor(
+        timer_fd_, events,
+        [callback{move(callback)}](const Event &event) -> int {
+          uint64_t s = 0;
+          std::error_code ec;
+
+          if (read(event.data.fd, &s, sizeof(s)) == -1) {
+            TRANSPORT_LOGE("Read error!!");
+          }
+
+          if (!(event.events & EPOLLIN)) {
+            ec = std::make_error_code(std::errc::operation_canceled);
+          }
+
+          callback(ec);
+
+          return 0;
+        });
+  }
+
+  void waitImpl() {
+    if (timerfd_settime(timer_fd_, flags_, &new_value_, NULL) == -1) {
+      throw errors::RuntimeException("Impossible to set the timer!");
+    }
+
+    uint64_t ret;
+
+    if (read(timer_fd_, &ret, sizeof(ret)) == -1) {
+      throw errors::RuntimeException(
+          "Error while waiting for the timer expiration.");
+    }
+  }
+
+  template <typename T, typename R>
+  void expiresFromNowImpl(std::chrono::duration<T, R> &&duration) {
+    std::memset(&new_value_, 0, sizeof(new_value_));
+    new_value_.it_value = std::chrono::duration_cast<struct timespec>(
+        std::forward<std::chrono::duration<T, R>>(duration));
+  }
+
+  template <typename TimePoint,
+            typename = std::enable_if_t<
+                std::is_same<std::remove_reference_t<TimePoint>,
+                             std::chrono::steady_clock::time_point>::value,
+                TimePoint>>
+  void expiresAtImpl(TimePoint &&time_point) {
+    std::memset(&new_value_, 0, sizeof(new_value_));
+
+    new_value_.it_value = std::chrono::duration_cast<struct timespec>(
+        time_point.time_since_epoch());
+    flags_ |= TFD_TIMER_ABSTIME;
+  }
+
+  void cancelImpl() {
+    std::memset(&new_value_, 0, sizeof(new_value_));
+
+    if (timerfd_settime(timer_fd_, 0, &new_value_, NULL) == -1) {
+      throw errors::RuntimeException("Impossible to cancel the timer!");
+    }
+
+    // reactor_.delFileDescriptor(timer_fd_);
+  }
+
+  EventReactor &getEventReactor() { return reactor_; }
+
+ private:
+  EpollEventReactor &reactor_;
+  int timer_fd_;
+  EventCallback callback_;
+  struct itimerspec new_value_;
+  int flags_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/hash.h b/libtransport/src/hicn/transport/utils/hash.h
new file mode 100755 (executable)
index 0000000..6815ca4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace utils {
+
+namespace hash {
+
+/*
+ * Fowler / Noll / Vo (FNV) Hash
+ *     http://www.isthe.com/chongo/tech/comp/fnv/
+ */
+
+const uint32_t FNV_32_HASH_START = 2166136261UL;
+const uint64_t FNV_64_HASH_START = 14695981039346656037ULL;
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const char *s,
+                                       uint32_t hash = FNV_32_HASH_START) {
+  for (; *s; ++s) {
+    hash +=
+        (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+    hash ^= *s;
+  }
+  return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32_buf(const void *buf, size_t n,
+                                           uint32_t hash = FNV_32_HASH_START) {
+  // forcing signed char, since other platforms can use unsigned
+  const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+  for (size_t i = 0; i < n; ++i) {
+    hash +=
+        (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
+    hash ^= char_buf[i];
+  }
+
+  return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint32_t fnv32(const std::string &str,
+                                       uint32_t hash = FNV_32_HASH_START) {
+  return fnv32_buf(str.data(), str.size(), hash);
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const char *s,
+                                       uint64_t hash = FNV_64_HASH_START) {
+  for (; *s; ++s) {
+    hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+            (hash << 8) + (hash << 40);
+    hash ^= *s;
+  }
+  return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64_buf(const void *buf, size_t n,
+                                           uint64_t hash = FNV_64_HASH_START) {
+  // forcing signed char, since other platforms can use unsigned
+  const signed char *char_buf = reinterpret_cast<const signed char *>(buf);
+
+  for (size_t i = 0; i < n; ++i) {
+    hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) +
+            (hash << 8) + (hash << 40);
+    hash ^= char_buf[i];
+  }
+  return hash;
+}
+
+TRANSPORT_ALWAYS_INLINE uint64_t fnv64(const std::string &str,
+                                       uint64_t hash = FNV_64_HASH_START) {
+  return fnv64_buf(str.data(), str.size(), hash);
+}
+
+}  // namespace hash
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/identity.cc b/libtransport/src/hicn/transport/utils/identity.cc
new file mode 100755 (executable)
index 0000000..bdf7f29
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/utils/identity.h>
+
+extern "C" {
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+}
+
+namespace utils {
+
+Identity::Identity(const std::string &keystore_name,
+                   const std::string &keystore_password, CryptoSuite suite,
+                   unsigned int key_length, unsigned int validity_days,
+                   const std::string &subject_name) {
+  parcSecurity_Init();
+
+  bool success = parcPkcs12KeyStore_CreateFile(
+      keystore_name.c_str(), keystore_password.c_str(), subject_name.c_str(),
+      parcCryptoSuite_GetSigningAlgorithm(static_cast<PARCCryptoSuite>(suite)),
+      key_length, validity_days);
+
+  parcAssertTrue(success,
+             "parcPkcs12KeyStore_CreateFile('%s', '%s', '%s', %d, %d) failed.",
+             keystore_name.c_str(), keystore_password.c_str(),
+             subject_name.c_str(), static_cast<int>(key_length), validity_days);
+
+  PARCIdentityFile *identity_file =
+      parcIdentityFile_Create(keystore_name.c_str(), keystore_password.c_str());
+
+  identity_ =
+      parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+  PARCSigner *signer = parcIdentity_CreateSigner(
+      identity_,
+      parcCryptoSuite_GetCryptoHash(static_cast<PARCCryptoSuite>(suite)));
+
+  signer_ = std::make_shared<Signer>(signer);
+
+  signature_length_ = parcSigner_GetSignatureSize(signer);
+
+  parcSigner_Release(&signer);
+  parcIdentityFile_Release(&identity_file);
+}
+
+Identity::Identity(const Identity &other)
+    : signer_(other.signer_),
+      hash_algorithm_(other.hash_algorithm_),
+      signature_length_(other.signature_length_) {
+  parcSecurity_Init();
+  identity_ = parcIdentity_Acquire(other.identity_);
+}
+
+Identity Identity::generateIdentity(const std::string &subject_name) {
+  std::string keystore_name = "keystore";
+  std::string keystore_password = "password";
+  std::size_t key_length = 1024;
+  unsigned int validity_days = 30;
+  CryptoSuite suite = CryptoSuite::RSA_SHA256;
+
+  return utils::Identity(keystore_name, keystore_password, suite, key_length,
+                         validity_days, subject_name);
+}
+
+Identity::Identity(std::string &file_name, std::string &password,
+                   transport::core::HashAlgorithm hash_algorithm)
+    : hash_algorithm_(hash_algorithm) {
+  parcSecurity_Init();
+
+  PARCIdentityFile *identity_file =
+      parcIdentityFile_Create(file_name.c_str(), password.c_str());
+
+  identity_ =
+      parcIdentity_Create(identity_file, PARCIdentityFileAsPARCIdentity);
+
+  PARCSigner *signer = parcIdentity_CreateSigner(
+      identity_, static_cast<PARCCryptoHashType>(hash_algorithm));
+
+  signer_ = std::make_shared<Signer>(signer);
+
+  signature_length_ = parcSigner_GetSignatureSize(signer);
+
+  parcSigner_Release(&signer);
+  parcIdentityFile_Release(&identity_file);
+}
+
+// Identity::Identity(Identity &&other) {
+//  identity_ = parcIdentity_Acquire(other.identity_);
+//}
+
+// Identity& Identity::operator=(const Identity& other) {
+//   signer_ = other.signer_;
+//   hash_algorithm_ = other.hash_algorithm_;
+//   signature_length_ = other.signature_length_;
+//   identity_ = parcIdentity_Acquire(other.identity_);
+
+//   parcSecurity_Init();
+// }
+
+Identity::~Identity() {
+  parcIdentity_Release(&identity_);
+  parcSecurity_Fini();
+}
+
+std::string Identity::getFileName() {
+  return std::string(parcIdentity_GetFileName(identity_));
+}
+
+std::string Identity::getPassword() {
+  return std::string(parcIdentity_GetPassWord(identity_));
+}
+
+Signer &Identity::getSigner() { return *signer_; }
+
+unsigned int Identity::getSignatureLength() const { return signature_length_; }
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/identity.h b/libtransport/src/hicn/transport/utils/identity.h
new file mode 100755 (executable)
index 0000000..018842e
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/manifest_format.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/signer.h>
+
+extern "C" {
+#include <parc/security/parc_Identity.h>
+#include <parc/security/parc_IdentityFile.h>
+#include <parc/security/parc_Pkcs12KeyStore.h>
+};
+
+#include <string>
+
+namespace utils {
+
+class Identity {
+ public:
+  Identity(const std::string &keystore_name,
+           const std::string &keystore_password, CryptoSuite suite,
+           unsigned int signature_length, unsigned int validity_days,
+           const std::string &subject_name);
+
+  // No copies
+  Identity(const Identity &other);
+
+  Identity(std::string &file_name, std::string &password,
+           transport::core::HashAlgorithm hash_algorithm);
+
+  ~Identity();
+
+  static Identity generateIdentity(const std::string &subject_name);
+
+  std::string getFileName();
+
+  std::string getPassword();
+
+  Signer &getSigner();
+
+  unsigned int getSignatureLength() const;
+
+ private:
+  PARCIdentity *identity_;
+  std::shared_ptr<Signer> signer_;
+  transport::core::HashAlgorithm hash_algorithm_;
+  unsigned int signature_length_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/key_id.h b/libtransport/src/hicn/transport/utils/key_id.h
new file mode 100755 (executable)
index 0000000..d67b73d
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <utility>
+
+namespace utils {
+
+using KeyId = std::pair<uint8_t*, uint8_t>;
+
+}
diff --git a/libtransport/src/hicn/transport/utils/linux.h b/libtransport/src/hicn/transport/utils/linux.h
new file mode 100755 (executable)
index 0000000..5820528
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#ifdef __linux__
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <string>
+
+#define LINK_LOCAL_PREFIX 0xfe80
+
+namespace utils {
+
+static TRANSPORT_ALWAYS_INLINE int retrieveInterfaceAddress(
+    const std::string &interface_name, struct sockaddr_in6 *address) {
+  struct ifaddrs *ifap, *ifa;
+  char addr[INET6_ADDRSTRLEN];
+
+  getifaddrs(&ifap);
+
+  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+    if (ifa->ifa_addr->sa_family == AF_INET6 &&
+        strcmp(ifa->ifa_name, interface_name.c_str()) == 0) {
+      struct sockaddr_in6 *tmp = (struct sockaddr_in6 *)ifa->ifa_addr;
+      uint16_t prefix = 0;
+      memcpy(&prefix, tmp->sin6_addr.s6_addr, sizeof(uint16_t));
+
+      if (htons(LINK_LOCAL_PREFIX) != prefix) {
+        *address = *(struct sockaddr_in6 *)ifa->ifa_addr;
+        getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
+                    sizeof(addr), NULL, 0, NI_NUMERICHOST);
+        TRANSPORT_LOGI("Interface: %s\tAddress: %s", ifa->ifa_name, addr);
+      }
+    }
+  }
+
+  freeifaddrs(ifap);
+
+  return 0;
+}
+
+}  // namespace utils
+
+#endif  // __linux__
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/literals.h b/libtransport/src/hicn/transport/utils/literals.h
new file mode 100755 (executable)
index 0000000..bd00e0a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+
+#include <cstdint>
+
+TRANSPORT_ALWAYS_INLINE std::uint8_t operator"" _U8(unsigned long long value) {
+  return static_cast<std::uint8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint16_t operator"" _U16(
+    unsigned long long value) {
+  return static_cast<std::uint16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint32_t operator"" _U32(
+    unsigned long long value) {
+  return static_cast<std::uint32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::uint64_t operator"" _U64(
+    unsigned long long value) {
+  return static_cast<std::uint64_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int8_t operator"" _I8(unsigned long long value) {
+  return static_cast<std::int8_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int16_t operator"" _I16(unsigned long long value) {
+  return static_cast<std::int16_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int32_t operator"" _I32(unsigned long long value) {
+  return static_cast<std::int32_t>(value);
+}
+
+TRANSPORT_ALWAYS_INLINE std::int64_t operator"" _I64(unsigned long long value) {
+  return static_cast<std::int64_t>(value);
+}
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/log.cc b/libtransport/src/hicn/transport/utils/log.cc
new file mode 100755 (executable)
index 0000000..064625e
--- /dev/null
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 wonder-mice
+ *
+ * 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.
+ */
+
+/* When defined, Android log (android/log.h) will be used by default instead of
+ * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
+ * will be provided by Android log. Android log features will be used to output
+ * log level and tag.
+ */
+#ifdef TRANSPORT_LOG_USE_ANDROID_LOG
+#undef TRANSPORT_LOG_USE_ANDROID_LOG
+#if defined(__ANDROID__)
+#define TRANSPORT_LOG_USE_ANDROID_LOG 1
+#else
+#define TRANSPORT_LOG_USE_ANDROID_LOG 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_ANDROID_LOG 0
+#endif
+/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
+ * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
+ * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
+ * non-public CFLog() function. Both use Apple System Log internally, but it's
+ * easier to call CFLog() from C than NSLog(). Current implementation doesn't
+ * support "%@" format specifier.
+ */
+#ifdef TRANSPORT_LOG_USE_NSLOG
+#undef TRANSPORT_LOG_USE_NSLOG
+#if defined(__APPLE__) && defined(__MACH__)
+#define TRANSPORT_LOG_USE_NSLOG 1
+#else
+#define TRANSPORT_LOG_USE_NSLOG 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_NSLOG 0
+#endif
+/* When defined, OutputDebugString() will be used instead of stderr (ignored on
+ * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
+ * UTF-8 data.
+ */
+#ifdef TRANSPORT_LOG_USE_DEBUGSTRING
+#undef TRANSPORT_LOG_USE_DEBUGSTRING
+#if defined(_WIN32) || defined(_WIN64)
+#define TRANSPORT_LOG_USE_DEBUGSTRING 1
+#else
+#define TRANSPORT_LOG_USE_DEBUGSTRING 0
+#endif
+#else
+#define TRANSPORT_LOG_USE_DEBUGSTRING 0
+#endif
+/* When defined, TRANSPORT_LOG library will not contain definition of tag prefix
+ * variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX macro, for example:
+ *
+ *   TRANSPORT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_TAG_PREFIX
+#undef TRANSPORT_LOG_EXTERN_TAG_PREFIX
+#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 1
+#else
+#define TRANSPORT_LOG_EXTERN_TAG_PREFIX 0
+#endif
+/* When defined, TRANSPORT_LOG library will not contain definition of global
+ * format variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
+ *
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT 0
+#endif
+/* When defined, transport_log library will not contain definition of global
+ * output variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
+ *
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD,
+ * custom_output_callback};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT 0
+#endif
+/* When defined, transport_log library will not contain definition of global
+ * output level variable. In that case it must be defined elsewhere using
+ * TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
+ *
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = TRANSPORT_LOG_WARN;
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+#undef TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
+#else
+#define TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
+#endif
+/* When defined, implementation will prefer smaller code size over speed.
+ * Very rough estimate is that code will be up to 2x smaller and up to 2x
+ * slower. Disabled by default.
+ */
+#ifdef TRANSPORT_LOG_OPTIMIZE_SIZE
+#undef TRANSPORT_LOG_OPTIMIZE_SIZE
+#define TRANSPORT_LOG_OPTIMIZE_SIZE 1
+#else
+#define TRANSPORT_LOG_OPTIMIZE_SIZE 0
+#endif
+/* Size of the log line buffer. The buffer is allocated on stack. It limits
+ * maximum length of a log line.
+ */
+#ifndef TRANSPORT_LOG_BUF_SZ
+#define TRANSPORT_LOG_BUF_SZ 512
+#endif
+/* Default number of bytes in one line of memory output. For large values
+ * TRANSPORT_LOG_BUF_SZ also must be increased.
+ */
+#ifndef TRANSPORT_LOG_MEM_WIDTH
+#define TRANSPORT_LOG_MEM_WIDTH 32
+#endif
+/* String to put in the end of each log line (can be empty). Its value used by
+ * stderr output callback. Its size used as a default value for
+ * TRANSPORT_LOG_EOL_SZ.
+ */
+#ifndef TRANSPORT_LOG_EOL
+#define TRANSPORT_LOG_EOL "\n"
+#endif
+/* Default delimiter that separates parts of log message. Can NOT contain '%'
+ * or '\0'.
+ *
+ * Log message format specifications can override (or ignore) this value. For
+ * more details see TRANSPORT_LOG_MESSAGE_CTX_FORMAT,
+ * TRANSPORT_LOG_MESSAGE_SRC_FORMAT and TRANSPORT_LOG_MESSAGE_TAG_FORMAT.
+ */
+#ifndef TRANSPORT_LOG_DEF_DELIMITER
+#define TRANSPORT_LOG_DEF_DELIMITER " "
+#endif
+/* Specifies log message context format. Log message context includes date,
+ * time, process id, thread id and message's log level. Custom information can
+ * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
+ * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * Must be defined as a tuple, for example:
+ *
+ *   #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY,
+ * S(" > "))
+ *
+ * In that case, resulting log message will be:
+ *
+ *   2016.12.22 > TAG function@filename.c:line Message text
+ *
+ * Note, that tag, source location and message text are not impacted by
+ * this setting. See TRANSPORT_LOG_MESSAGE_TAG_FORMAT and
+ * TRANSPORT_LOG_MESSAGE_SRC_FORMAT.
+ *
+ * If message context must be visually separated from the rest of the message,
+ * it must be reflected in context format (notice trailing S(" > ") in the
+ * example above).
+ *
+ * S(str) adds constant string str. String can NOT contain '%' or '\0'.
+ *
+ * F_INIT(statements) adds initialization statement(s) that will be evaluated
+ * once for each log message. All statements are evaluated in specified order.
+ * Several F_INIT() fields can be used in every log message format
+ * specification. Fields, like F_UINT(width, value), are allowed to use results
+ * of initialization statements. If statement introduces variables (or other
+ * names, like structures) they must be prefixed with "f_". Statements  must be
+ * enclosed into additional "()". Example:
+ *
+ *   #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \
+ *       (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
+ *        YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ *        F_UINT(5, f_ru.ru_nsignals), \
+ *        S(" "))
+ *
+ * F_UINT(width, value) adds unsigned integer value extended with up to width
+ * spaces (for alignment purposes). Value can be any expression that evaluates
+ * to unsigned integer. If expression contains non-standard functions, they
+ * must be declared with F_INIT(). Example:
+ *
+ *   #define TRANSPORT_LOG_MESSAGE_CTX_FORMAT \
+ *        (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ *        F_INIT(( unsigned tickcount(); )), \
+ *        F_UINT(5, tickcount()), \
+ *        S(" "))
+ *
+ * Other log message format specifications follow same rules, but have a
+ * different set of supported fields.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_CTX_FORMAT
+#define TRANSPORT_LOG_MESSAGE_CTX_FORMAT                                       \
+  (MONTH, S("-"), DAY, S(TRANSPORT_LOG_DEF_DELIMITER), HOUR, S(":"), MINUTE,   \
+   S(":"), SECOND, S("."), MILLISECOND, S(TRANSPORT_LOG_DEF_DELIMITER), PID,   \
+   S(TRANSPORT_LOG_DEF_DELIMITER), TID, S(TRANSPORT_LOG_DEF_DELIMITER), LEVEL, \
+   S(TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Example:
+ */
+/* Specifies log message tag format. It includes tag prefix and tag. Custom
+ * information can be added as well. Supported fields:
+ * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
+ *
+ *   PREFIX<prefix_delimiter>TAG<tag_delimiter>
+ *
+ * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
+ * will be used only when prefixed tag is not empty. Example:
+ *
+ *   #define TRANSPORT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
+ *
+ * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_TAG_FORMAT
+#define TRANSPORT_LOG_MESSAGE_TAG_FORMAT (TAG(".", TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Specifies log message source location format. It includes function name,
+ * file name and file line. Custom information can be added as well. Supported
+ * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef TRANSPORT_LOG_MESSAGE_SRC_FORMAT
+#define TRANSPORT_LOG_MESSAGE_SRC_FORMAT \
+  (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(TRANSPORT_LOG_DEF_DELIMITER))
+#endif
+/* Fields that can be used in log message format specifications (see above).
+ * Mentioning them here explicitly, so we know that nobody else defined them
+ * before us. See TRANSPORT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#define YEAR YEAR
+#define MONTH MONTH
+#define DAY DAY
+#define MINUTE MINUTE
+#define SECOND SECOND
+#define MILLISECOND MILLISECOND
+#define PID PID
+#define TID TID
+#define LEVEL LEVEL
+#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
+#define FUNCTION FUNCTION
+#define FILENAME FILENAME
+#define FILELINE FILELINE
+#define S(str) S(str)
+#define F_INIT(statements) F_INIT(statements)
+#define F_UINT(width, value) F_UINT(width, value)
+/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
+ * Must be larger than or equal to length of TRANSPORT_LOG_EOL with terminating
+ * null.
+ */
+#ifndef TRANSPORT_LOG_EOL_SZ
+#define TRANSPORT_LOG_EOL_SZ sizeof(TRANSPORT_LOG_EOL)
+#endif
+/* Compile instrumented version of the library to facilitate unit testing.
+ */
+#ifndef TRANSPORT_LOG_INSTRUMENTED
+#define TRANSPORT_LOG_INSTRUMENTED 0
+#endif
+
+#if defined(__linux__)
+#if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+#endif
+#if defined(__MINGW32__)
+#ifdef __STRICT_ANSI__
+#undef __STRICT_ANSI__
+#endif
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <hicn/transport/utils/log.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#if defined(__linux__)
+#include <linux/limits.h>
+#else
+#include <sys/syslimits.h>
+#endif
+#endif
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+#include <sys/types.h>
+#if !defined(__ANDROID__)
+#include <sys/syscall.h>
+#endif
+#endif
+#if defined(__MACH__)
+#include <pthread.h>
+#endif
+
+#define INLINE _TRANSPORT_LOG_INLINE
+#define VAR_UNUSED(var) (void)var
+#define RETVAL_UNUSED(expr) \
+  do {                      \
+    while (expr) break;     \
+  } while (0)
+#define STATIC_ASSERT(name, cond) typedef char assert_##name[(cond) ? 1 : -1]
+#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
+#ifndef _countof
+#define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
+#endif
+
+#if TRANSPORT_LOG_INSTRUMENTED
+#define INSTRUMENTED_CONST
+#else
+#define INSTRUMENTED_CONST const
+#endif
+
+#define _PP_PASTE_2(a, b) a##b
+#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
+
+#define _PP_PASTE_3(a, b, c) a##b##c
+#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
+
+/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
+ * as a single token and requires additional expansion to realize that it's
+ * actually a list. If not for it, there would be no need in this extra
+ * expansion.
+ */
+#define _PP_ID(x) x
+#define _PP_NARGS_N(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
+                    _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, \
+                    _24, ...)                                              \
+  _24
+#define _PP_NARGS(...)                                                        \
+  _PP_ID(_PP_NARGS_N(__VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, \
+                     13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+
+/* There is a more efficient way to implement this, but it requires
+ * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
+ * have one.
+ */
+#define _PP_HEAD__(x, ...) x
+#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
+#define _PP_HEAD(xs) _PP_HEAD_ xs
+#define _PP_TAIL_(x, ...) (__VA_ARGS__)
+#define _PP_TAIL(xs) _PP_TAIL_ xs
+#define _PP_UNTUPLE_(...) __VA_ARGS__
+#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
+
+/* Apply function macro to each element in tuple. Output is not
+ * enforced to be a tuple.
+ */
+#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
+#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
+#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
+#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
+#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
+#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
+#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
+#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
+#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
+#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
+#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
+#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
+#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
+#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
+#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
+#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
+#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
+#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
+#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
+#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
+#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
+#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
+#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
+#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs)(f, xs)
+
+/* Apply function macro to each element in tuple in reverse order.
+ * Output is not enforced to be a tuple.
+ */
+#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs)(f, xs)
+
+/* Used to implement _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All
+ * possible fields must be mentioned here. Not counting F_INIT() here because
+ * it's somewhat special and is handled spearatly (at least for now).
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__ (0 << 0)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__YEAR (1 << 1)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MONTH (1 << 2)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__DAY (1 << 3)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__HOUR (1 << 4)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MINUTE (1 << 5)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__SECOND (1 << 6)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1 << 7)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__PID (1 << 8)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TID (1 << 9)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__LEVEL (1 << 10)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1 << 11)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1 << 12)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILENAME (1 << 13)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__FILELINE (1 << 14)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__S(s) (1 << 15)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0 << 16)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1 << 17)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_MASK_, _, field)
+
+/* Logical "or" of masks of fields used in specified format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format) \
+  (0 _PP_MAP(| _TRANSPORT_LOG_MESSAGE_FORMAT_MASK, format))
+
+/* Expands to expressions that evaluates to true if field is used in
+ * specified format specification. Example:
+ *
+ *   #if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT,
+ * TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+ *       ...
+ *   #endif
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
+  (_TRANSPORT_LOG_MESSAGE_FORMAT_MASK(field) &                \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(format))
+
+/* Same, but checks all supported format specifications.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_FIELD_USED(field)                        \
+  (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field,                               \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field,                               \
+                                          TRANSPORT_LOG_MESSAGE_TAG_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(field,                               \
+                                          TRANSPORT_LOG_MESSAGE_SRC_FORMAT))
+
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED                            \
+  (_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR,                                \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH,                               \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(DAY,                                 \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR,                                \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE,                              \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND,                              \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT) || \
+   _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND,                         \
+                                          TRANSPORT_LOG_MESSAGE_CTX_FORMAT))
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#pragma warning(disable : 4204) /* nonstandard extension used: non-constant \
+                                   aggregate initializer */
+#define memccpy _memccpy
+#endif
+
+#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)
+#define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
+static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap) {
+  const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);
+  return 0 < n ? n : (int)sz + 1; /* no need in _vscprintf() for now */
+}
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+#define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
+static int fake_snprintf(char *s, size_t sz, const char *fmt, ...) {
+  va_list va;
+  va_start(va, fmt);
+  const int n = fake_vsnprintf(s, sz, fmt, va);
+  va_end(va);
+  return n;
+}
+#endif
+#endif
+
+typedef void (*time_cb)(struct tm *const tm, unsigned *const usec);
+typedef void (*pid_cb)(int *const pid, int *const tid);
+typedef void (*buffer_cb)(transport_log_message *msg, char *buf);
+
+typedef struct src_location {
+  const char *const func;
+  const char *const file;
+  const unsigned line;
+} src_location;
+
+typedef struct mem_block {
+  const void *const d;
+  const unsigned d_sz;
+} mem_block;
+
+static void time_callback(struct tm *const tm, unsigned *const usec);
+static void pid_callback(int *const pid, int *const tid);
+static void buffer_callback(transport_log_message *msg, char *buf);
+
+STATIC_ASSERT(eol_fits_eol_sz,
+              sizeof(TRANSPORT_LOG_EOL) <= TRANSPORT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_greater_than_zero, 0 < TRANSPORT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_less_than_buf_sz,
+              TRANSPORT_LOG_EOL_SZ < TRANSPORT_LOG_BUF_SZ);
+#if !defined(_WIN32) && !defined(_WIN64)
+STATIC_ASSERT(buf_sz_less_than_pipe_buf, TRANSPORT_LOG_BUF_SZ <= PIPE_BUF);
+#endif
+static const char c_hex[] = "0123456789abcdef";
+
+static INSTRUMENTED_CONST unsigned g_buf_sz =
+    TRANSPORT_LOG_BUF_SZ - TRANSPORT_LOG_EOL_SZ;
+static INSTRUMENTED_CONST time_cb g_time_cb = time_callback;
+static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;
+static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;
+
+#if TRANSPORT_LOG_USE_ANDROID_LOG
+#include <android/log.h>
+
+static INLINE int android_lvl(const int lvl) {
+  switch (lvl) {
+    case TRANSPORT_LOG_VERBOSE:
+      return ANDROID_LOG_VERBOSE;
+    case TRANSPORT_LOG_DEBUG:
+      return ANDROID_LOG_DEBUG;
+    case TRANSPORT_LOG_INFO:
+      return ANDROID_LOG_INFO;
+    case TRANSPORT_LOG_WARN:
+      return ANDROID_LOG_WARN;
+    case TRANSPORT_LOG_ERROR:
+      return ANDROID_LOG_ERROR;
+    case TRANSPORT_LOG_FATAL:
+      return ANDROID_LOG_FATAL;
+    default:
+      ASSERT_UNREACHABLE("Bad log level");
+      return ANDROID_LOG_UNKNOWN;
+  }
+}
+
+static void out_android_callback(const transport_log_message *const msg,
+                                 void *arg) {
+  VAR_UNUSED(arg);
+  *msg->p = 0;
+  const char *tag = msg->p;
+  if (msg->tag_e != msg->tag_b) {
+    tag = msg->tag_b;
+    *msg->tag_e = 0;
+  }
+  __android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);
+}
+
+enum { OUT_ANDROID_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX };
+#define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
+#endif
+
+#if TRANSPORT_LOG_USE_NSLOG
+#include <CoreFoundation/CoreFoundation.h>
+CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);
+
+static INLINE int apple_lvl(const int lvl) {
+  switch (lvl) {
+    case TRANSPORT_LOG_VERBOSE:
+      return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */
+      ;
+    case TRANSPORT_LOG_DEBUG:
+      return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */
+      ;
+    case TRANSPORT_LOG_INFO:
+      return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */
+      ;
+    case TRANSPORT_LOG_WARN:
+      return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */
+      ;
+    case TRANSPORT_LOG_ERROR:
+      return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */
+      ;
+    case TRANSPORT_LOG_FATAL:
+      return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */
+      ;
+    default:
+      ASSERT_UNREACHABLE("Bad log level");
+      return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */
+      ;
+  }
+}
+
+static void out_nslog_callback(const transport_log_message *const msg,
+                               void *arg) {
+  VAR_UNUSED(arg);
+  *msg->p = 0;
+  CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b);
+}
+
+enum { OUT_NSLOG_MASK = TRANSPORT_LOG_PUT_STD & ~TRANSPORT_LOG_PUT_CTX };
+#define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
+#endif
+
+#if TRANSPORT_LOG_USE_DEBUGSTRING
+#include <windows.h>
+
+static void out_debugstring_callback(const transport_log_message *const msg,
+                                     void *arg) {
+  VAR_UNUSED(arg);
+  msg->p[0] = '\n';
+  msg->p[1] = '\0';
+  OutputDebugStringA(msg->buf);
+}
+
+enum { OUT_DEBUGSTRING_MASK = TRANSPORT_LOG_PUT_STD };
+#define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
+#endif
+
+void transport_log_out_stderr_callback(const transport_log_message *const msg,
+                                       void *arg) {
+  VAR_UNUSED(arg);
+  const size_t eol_len = sizeof(TRANSPORT_LOG_EOL) - 1;
+  memcpy(msg->p, TRANSPORT_LOG_EOL, eol_len);
+#if defined(_WIN32) || defined(_WIN64)
+  /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
+     without FILE_WRITE_DATA */
+  DWORD written;
+  WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,
+            (DWORD)(msg->p - msg->buf + eol_len), &written, 0);
+#else
+  /* write() is atomic for buffers less than or equal to PIPE_BUF. */
+  RETVAL_UNUSED(
+      write(STDERR_FILENO, msg->buf, (size_t)(msg->p - msg->buf) + eol_len));
+#endif
+}
+
+static const transport_log_output out_stderr = {TRANSPORT_LOG_OUT_STDERR};
+
+#if !TRANSPORT_LOG_EXTERN_TAG_PREFIX
+TRANSPORT_LOG_DEFINE_TAG_PREFIX = 0;
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {TRANSPORT_LOG_MEM_WIDTH};
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+#if TRANSPORT_LOG_USE_ANDROID_LOG
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};
+#elif TRANSPORT_LOG_USE_NSLOG
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};
+#elif TRANSPORT_LOG_USE_DEBUGSTRING
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};
+#else
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR};
+#endif
+#endif
+
+#if !TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;
+#endif
+
+const transport_log_spec _transport_log_stderr_spec = {
+    TRANSPORT_LOG_GLOBAL_FORMAT,
+    &out_stderr,
+};
+
+static const transport_log_spec global_spec = {
+    TRANSPORT_LOG_GLOBAL_FORMAT,
+    TRANSPORT_LOG_GLOBAL_OUTPUT,
+};
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, \
+                                           TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+static char lvl_char(const int lvl) {
+  switch (lvl) {
+    case TRANSPORT_LOG_VERBOSE:
+      return 'V';
+    case TRANSPORT_LOG_DEBUG:
+      return 'D';
+    case TRANSPORT_LOG_INFO:
+      return 'I';
+    case TRANSPORT_LOG_WARN:
+      return 'W';
+    case TRANSPORT_LOG_ERROR:
+      return 'E';
+    case TRANSPORT_LOG_FATAL:
+      return 'F';
+    default:
+      ASSERT_UNREACHABLE("Bad log level");
+      return '?';
+  }
+}
+#endif
+
+#define GCCVER_LESS(MAJOR, MINOR, PATCH)                                  \
+  (__GNUC__ < MAJOR || (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR ||   \
+                                              (__GNUC_MINOR__ == MINOR && \
+                                               __GNUC_PATCHLEVEL__ < PATCH))))
+
+#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4, 7, 0)
+#define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
+#define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
+#define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
+#define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
+#define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
+/* Note: will not store old value of *vp in *ep (non-standard behaviour) */
+#define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
+  __sync_bool_compare_and_swap(vp, *(ep), d)
+#endif
+
+#if !TRANSPORT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
+#define TCACHE
+#define TCACHE_STALE (0x40000000)
+#define TCACHE_FLUID (0x40000000 | 0x80000000)
+static unsigned g_tcache_mode = TCACHE_STALE;
+static struct timeval g_tcache_tv = {0, 0};
+static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static INLINE int tcache_get(const struct timeval *const tv,
+                             struct tm *const tm) {
+  unsigned mode;
+  mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);
+  if (0 == (mode & TCACHE_FLUID)) {
+    mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);
+    if (0 == (mode & TCACHE_FLUID)) {
+      if (g_tcache_tv.tv_sec == tv->tv_sec) {
+        *tm = g_tcache_tm;
+        __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+        return !0;
+      }
+      __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);
+    }
+    __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+  }
+  return 0;
+}
+
+static INLINE void tcache_set(const struct timeval *const tv,
+                              struct tm *const tm) {
+  unsigned stale = TCACHE_STALE;
+  if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID, 0,
+                                  __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
+    g_tcache_tv = *tv;
+    g_tcache_tm = *tm;
+    __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);
+  }
+}
+#endif
+
+static void time_callback(struct tm *const tm, unsigned *const msec) {
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED
+  VAR_UNUSED(tm);
+  VAR_UNUSED(msec);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+  SYSTEMTIME st;
+  GetLocalTime(&st);
+  tm->tm_year = st.wYear;
+  tm->tm_mon = st.wMonth - 1;
+  tm->tm_mday = st.wDay;
+  tm->tm_wday = st.wDayOfWeek;
+  tm->tm_hour = st.wHour;
+  tm->tm_min = st.wMinute;
+  tm->tm_sec = st.wSecond;
+  *msec = st.wMilliseconds;
+#else
+  struct timeval tv;
+  gettimeofday(&tv, 0);
+#ifndef TCACHE
+  localtime_r(&tv.tv_sec, tm);
+#else
+  if (!tcache_get(&tv, tm)) {
+    localtime_r(&tv.tv_sec, tm);
+    tcache_set(&tv, tm);
+  }
+#endif
+  *msec = (unsigned)tv.tv_usec / 1000;
+#endif
+#endif
+}
+
+static void pid_callback(int *const pid, int *const tid) {
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(PID, \
+                                            TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+  VAR_UNUSED(pid);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+  *pid = GetCurrentProcessId();
+#else
+  *pid = getpid();
+#endif
+#endif
+
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \
+                                            TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+  VAR_UNUSED(tid);
+#else
+#if defined(_WIN32) || defined(_WIN64)
+  *tid = GetCurrentThreadId();
+#elif defined(__ANDROID__)
+  *tid = gettid();
+#elif defined(__linux__)
+  *tid = syscall(SYS_gettid);
+#elif defined(__MACH__)
+  *tid = (int)pthread_mach_thread_np(pthread_self());
+#else
+#define Platform not supported
+#endif
+#endif
+}
+
+static void buffer_callback(transport_log_message *msg, char *buf) {
+  msg->e = (msg->p = msg->buf = buf) + g_buf_sz;
+}
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, \
+                                           TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+static const char *funcname(const char *func) { return func ? func : ""; }
+#endif
+
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, \
+                                           TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+static const char *filename(const char *file) {
+  const char *f = file;
+  for (const char *p = file; 0 != *p; ++p) {
+    if ('/' == *p || '\\' == *p) {
+      f = p + 1;
+    }
+  }
+  return f;
+}
+#endif
+
+static INLINE size_t nprintf_size(transport_log_message *const msg) {
+  // *nprintf() always puts 0 in the end when input buffer is not empty. This
+  // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
+  // leaves space for one more character. Some put_xxx() functions don't use
+  // *nprintf() and could use that last character. In that case log line will
+  // have multiple (two) half-written parts which is confusing. To workaround
+  // that we allow *nprintf() to write its 0 in the eol area (which is always
+  // not empty).
+  return (size_t)(msg->e - msg->p + 1);
+}
+
+static INLINE void put_nprintf(transport_log_message *const msg, const int n) {
+  if (0 < n) {
+    msg->p = n < msg->e - msg->p ? msg->p + n : msg->e;
+  }
+}
+
+static INLINE char *put_padding_r(const unsigned w, const char wc, char *p,
+                                  char *e) {
+  for (char *const b = e - w; b < p; *--p = wc) {
+  }
+  return p;
+}
+
+static char *put_integer_r(unsigned v, const int sign, const unsigned w,
+                           const char wc, char *const e) {
+  static const char _signs[] = {'-', '0', '+'};
+  static const char *const signs = _signs + 1;
+  char *p = e;
+  do {
+    *--p = '0' + v % 10;
+  } while (0 != (v /= 10));
+  if (0 == sign) return put_padding_r(w, wc, p, e);
+  if ('0' != wc) {
+    *--p = signs[sign];
+    return put_padding_r(w, wc, p, e);
+  }
+  p = put_padding_r(w, wc, p, e + 1);
+  *--p = signs[sign];
+  return p;
+}
+
+static INLINE char *put_uint_r(const unsigned v, const unsigned w,
+                               const char wc, char *const e) {
+  return put_integer_r(v, 0, w, wc, e);
+}
+
+static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
+                              char *const e) {
+  return 0 <= v ? put_integer_r((unsigned)v, 0, w, wc, e)
+                : put_integer_r((unsigned)-v, -1, w, wc, e);
+}
+
+static INLINE char *put_stringn(const char *const s_p, const char *const s_e,
+                                char *const p, char *const e) {
+  const ptrdiff_t m = e - p;
+  ptrdiff_t n = s_e - s_p;
+  if (n > m) {
+    n = m;
+  }
+  memcpy(p, s_p, n);
+  return p + n;
+}
+
+static INLINE char *put_string(const char *s, char *p, char *const e) {
+  const ptrdiff_t n = e - p;
+  char *const c = (char *)memccpy(p, s, '\0', n);
+  return 0 != c ? c - 1 : e;
+}
+
+static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
+                             char *const p, char *const e) {
+  char buf[16];
+  char *const se = buf + _countof(buf);
+  char *sp = put_uint_r(v, w, wc, se);
+  return put_stringn(sp, se, p, e);
+}
+
+#define PUT_CSTR_R(p, STR)                         \
+  do {                                             \
+    for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
+      *--(p) = (STR)[i];                           \
+    }                                              \
+  }                                                \
+  _TRANSPORT_LOG_ONCE
+
+#define PUT_CSTR_CHECKED(p, e, STR)                                 \
+  do {                                                              \
+    for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
+      *(p)++ = (STR)[i];                                            \
+    }                                                               \
+  }                                                                 \
+  _TRANSPORT_LOG_ONCE
+
+/* F_INIT field support.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__YEAR
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MONTH
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__DAY
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__HOUR
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MINUTE
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__SECOND
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__PID
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TID
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__LEVEL
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILENAME
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__FILELINE
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__S(s)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_INIT(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT_, _, field)
+
+/* Implements generation of printf-like format string for log message
+ * format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__ ""
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR "%04u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND "%02u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND "%03u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID "%5i"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID "%5i"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL "%c"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION "%s"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME "%s"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE "%u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s) s
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
+
+/* Implements generation of printf-like format parameters for log message
+ * format specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR \
+  , (unsigned)(tm.tm_year + 1900)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH \
+  , (unsigned)(tm.tm_mon + 1)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY , (unsigned)tm.tm_mday
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR , (unsigned)tm.tm_hour
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE , (unsigned)tm.tm_min
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND , (unsigned)tm.tm_sec
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND , (unsigned)msec
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID , pid
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID , tid
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL \
+  , (char)lvl_char(msg->lvl)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION , funcname(src->func)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME , filename(src->file)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE , src->line
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) , v
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
+
+/* Implements generation of put_xxx_t statements for log message specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__YEAR \
+  p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MONTH \
+  p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__DAY \
+  p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__HOUR \
+  p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE \
+  p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__SECOND \
+  p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND \
+  p = put_uint_r(msec, 3, '0', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__PID p = put_int_r(pid, 5, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TID p = put_int_r(tid, 5, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL *--p = lvl_char(msg->lvl);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__TAG UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__S(s) PUT_CSTR_R(p, s);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) \
+  p = put_uint_r(v, w, ' ', p);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
+
+static void put_ctx(transport_log_message *const msg) {
+  _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+  VAR_UNUSED(msg);
+#else
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_DATETIME_USED
+  struct tm tm;
+  unsigned msec;
+  g_time_cb(&tm, &msec);
+#endif
+#if _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(     \
+    PID, TRANSPORT_LOG_MESSAGE_CTX_FORMAT) ||   \
+    _TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TID, \
+                                           TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+  int pid, tid;
+  g_pid_cb(&pid, &tid);
+#endif
+
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+  int n;
+  n = snprintf(msg->p, nprintf_size(msg),
+               _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT,
+                       TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+                   _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL,
+                           TRANSPORT_LOG_MESSAGE_CTX_FORMAT));
+  put_nprintf(msg, n);
+#else
+  char buf[64];
+  char *const e = buf + sizeof(buf);
+  char *p = e;
+  _PP_RMAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_R,
+           TRANSPORT_LOG_MESSAGE_CTX_FORMAT)
+  msg->p = put_stringn(p, e, msg->p, msg->e);
+#endif
+#endif
+}
+
+#define PUT_TAG(msg, tag, prefix_delim, tag_delim)                       \
+  do {                                                                   \
+    const char *ch;                                                      \
+    msg->tag_b = msg->p;                                                 \
+    if (0 != (ch = _transport_log_tag_prefix)) {                         \
+      for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \
+      }                                                                  \
+    }                                                                    \
+    if (0 != (ch = tag) && 0 != tag[0]) {                                \
+      if (msg->tag_b != msg->p) {                                        \
+        PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim);                  \
+      }                                                                  \
+      for (; msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) { \
+      }                                                                  \
+    }                                                                    \
+    msg->tag_e = msg->p;                                                 \
+    if (msg->tag_b != msg->p) {                                          \
+      PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim);                       \
+    }                                                                    \
+  }                                                                      \
+  _TRANSPORT_LOG_ONCE
+
+/* Implements simple put statements for log message specification.
+ */
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__YEAR UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MONTH UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__DAY UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__HOUR UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MINUTE UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__SECOND UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__PID UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TID UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__LEVEL UNDEFINED
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td) \
+  PUT_TAG(msg, tag, pd, td);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FUNCTION \
+  msg->p = put_string(funcname(src->func), msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILENAME \
+  msg->p = put_string(filename(src->file), msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__FILELINE \
+  msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__S(s) \
+  PUT_CSTR_CHECKED(msg->p, msg->e, s);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) \
+  msg->p = put_uint(v, w, ' ', msg->p, msg->e);
+#define _TRANSPORT_LOG_MESSAGE_FORMAT_PUT(field) \
+  _PP_CONCAT_3(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT_, _, field)
+
+static void put_tag(transport_log_message *const msg, const char *const tag) {
+  _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, \
+                                            TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+  VAR_UNUSED(tag);
+#endif
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+  VAR_UNUSED(msg);
+#else
+  _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_TAG_FORMAT)
+#endif
+}
+
+static void put_src(transport_log_message *const msg,
+                    const src_location *const src) {
+  _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_INIT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(           \
+    FUNCTION, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) &&     \
+    !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(           \
+        FILENAME, TRANSPORT_LOG_MESSAGE_SRC_FORMAT) && \
+    !_TRANSPORT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE,  \
+                                            TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+  VAR_UNUSED(src);
+#endif
+#if !_TRANSPORT_LOG_MESSAGE_FORMAT_FIELDS(TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+  VAR_UNUSED(msg);
+#else
+#if TRANSPORT_LOG_OPTIMIZE_SIZE
+  int n;
+  n = snprintf(msg->p, nprintf_size(msg),
+               _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_FMT,
+                       TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+                   _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PRINTF_VAL,
+                           TRANSPORT_LOG_MESSAGE_SRC_FORMAT));
+  put_nprintf(msg, n);
+#else
+  _PP_MAP(_TRANSPORT_LOG_MESSAGE_FORMAT_PUT, TRANSPORT_LOG_MESSAGE_SRC_FORMAT)
+#endif
+#endif
+}
+
+static void put_msg(transport_log_message *const msg, const char *const fmt,
+                    va_list va) {
+  int n;
+  msg->msg_b = msg->p;
+  n = vsnprintf(msg->p, nprintf_size(msg), fmt, va);
+  put_nprintf(msg, n);
+}
+
+static void output_mem(const transport_log_spec *log,
+                       transport_log_message *const msg,
+                       const mem_block *const mem) {
+  if (0 == mem->d || 0 == mem->d_sz) {
+    return;
+  }
+  const unsigned char *mem_p = (const unsigned char *)mem->d;
+  const unsigned char *const mem_e = mem_p + mem->d_sz;
+  const unsigned char *mem_cut;
+  const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;
+  char *const hex_b = msg->msg_b;
+  char *const ascii_b = hex_b + 2 * mem_width + 2;
+  char *const ascii_e = ascii_b + mem_width;
+  if (msg->e < ascii_e) {
+    return;
+  }
+  while (mem_p != mem_e) {
+    char *hex = hex_b;
+    char *ascii = ascii_b;
+    for (mem_cut = mem_width < mem_e - mem_p ? mem_p + mem_width : mem_e;
+         mem_cut != mem_p; ++mem_p) {
+      const unsigned char ch = *mem_p;
+      *hex++ = c_hex[(0xf0 & ch) >> 4];
+      *hex++ = c_hex[(0x0f & ch)];
+      *ascii++ = isprint(ch) ? (char)ch : '?';
+    }
+    while (hex != ascii_b) {
+      *hex++ = ' ';
+    }
+    msg->p = ascii;
+    log->output->callback(msg, log->output->arg);
+  }
+}
+
+void transport_log_set_tag_prefix(const char *const prefix) {
+  _transport_log_tag_prefix = prefix;
+}
+
+void transport_log_set_mem_width(const unsigned w) {
+  _transport_log_global_format.mem_width = w;
+}
+
+void transport_log_set_output_level(const int lvl) {
+  _transport_log_global_output_lvl = lvl;
+}
+
+void transport_log_set_output_v(const unsigned mask, void *const arg,
+                                const transport_log_output_cb callback) {
+  _transport_log_global_output.mask = mask;
+  _transport_log_global_output.arg = arg;
+  _transport_log_global_output.callback = callback;
+}
+
+static void _transport_log_write_imp(const transport_log_spec *log,
+                                     const src_location *const src,
+                                     const mem_block *const mem, const int lvl,
+                                     const char *const tag,
+                                     const char *const fmt, va_list va) {
+  transport_log_message msg;
+  char buf[TRANSPORT_LOG_BUF_SZ];
+  const unsigned mask = log->output->mask;
+  msg.lvl = lvl;
+  msg.tag = tag;
+  g_buffer_cb(&msg, buf);
+  if (TRANSPORT_LOG_PUT_CTX & mask) {
+    put_ctx(&msg);
+  }
+  if (TRANSPORT_LOG_PUT_TAG & mask) {
+    put_tag(&msg, tag);
+  }
+  if (0 != src && TRANSPORT_LOG_PUT_SRC & mask) {
+    put_src(&msg, src);
+  }
+  if (TRANSPORT_LOG_PUT_MSG & mask) {
+    put_msg(&msg, fmt, va);
+  }
+  log->output->callback(&msg, log->output->arg);
+  if (0 != mem && TRANSPORT_LOG_PUT_MSG & mask) {
+    output_mem(log, &msg, mem);
+  }
+}
+
+void _transport_log_write_d(const char *const func, const char *const file,
+                            const unsigned line, const int lvl,
+                            const char *const tag, const char *const fmt, ...) {
+  const src_location src = {func, file, line};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_aux_d(const char *const func, const char *const file,
+                                const unsigned line,
+                                const transport_log_spec *const log,
+                                const int lvl, const char *const tag,
+                                const char *const fmt, ...) {
+  const src_location src = {func, file, line};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(log, &src, 0, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write(const int lvl, const char *const tag,
+                          const char *const fmt, ...) {
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_aux(const transport_log_spec *const log,
+                              const int lvl, const char *const tag,
+                              const char *const fmt, ...) {
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(log, 0, 0, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_mem_d(const char *const func, const char *const file,
+                                const unsigned line, const int lvl,
+                                const char *const tag, const void *const d,
+                                const unsigned d_sz, const char *const fmt,
+                                ...) {
+  const src_location src = {func, file, line};
+  const mem_block mem = {d, d_sz};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_mem_aux_d(const char *const func,
+                                    const char *const file, const unsigned line,
+                                    const transport_log_spec *const log,
+                                    const int lvl, const char *const tag,
+                                    const void *const d, const unsigned d_sz,
+                                    const char *const fmt, ...) {
+  const src_location src = {func, file, line};
+  const mem_block mem = {d, d_sz};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_mem(const int lvl, const char *const tag,
+                              const void *const d, const unsigned d_sz,
+                              const char *const fmt, ...) {
+  const mem_block mem = {d, d_sz};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);
+  va_end(va);
+}
+
+void _transport_log_write_mem_aux(const transport_log_spec *const log,
+                                  const int lvl, const char *const tag,
+                                  const void *const d, const unsigned d_sz,
+                                  const char *const fmt, ...) {
+  const mem_block mem = {d, d_sz};
+  va_list va;
+  va_start(va, fmt);
+  _transport_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);
+  va_end(va);
+}
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/log.h b/libtransport/src/hicn/transport/utils/log.h
new file mode 100755 (executable)
index 0000000..17e47e7
--- /dev/null
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 wonder-mice
+ *
+ * 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.
+ */
+
+#pragma once
+
+/* To detect incompatible changes you can define TRANSPORT_LOG_VERSION_REQUIRED
+ * to be the current value of TRANSPORT_LOG_VERSION before including this file
+ * (or via compiler command line):
+ *
+ *   #define TRANSPORT_LOG_VERSION_REQUIRED 4
+ *   #include <hicn/transport_log.h>
+ *
+ * Compilation will fail when included file has different version.
+ */
+#define TRANSPORT_LOG_VERSION 4
+#if defined(TRANSPORT_LOG_VERSION_REQUIRED)
+#if TRANSPORT_LOG_VERSION_REQUIRED != TRANSPORT_LOG_VERSION
+#error different transport_log version required
+#endif
+#endif
+
+/* Log level guideline:
+ * - TRANSPORT_LOG_FATAL - happened something impossible and absolutely
+ * unexpected. Process can't continue and must be terminated. Example: division
+ * by zero, unexpected modifications from other thread.
+ * - TRANSPORT_LOG_ERROR - happened something possible, but highly unexpected.
+ * The process is able to recover and continue execution. Example: out of memory
+ * (could also be FATAL if not handled properly).
+ * - TRANSPORT_LOG_WARN - happened something that *usually* should not happen
+ * and significantly changes application behavior for some period of time.
+ *   Example: configuration file not found, auth error.
+ * - TRANSPORT_LOG_INFO - happened significant life cycle event or major state
+ *   transition.
+ *   Example: app started, user logged in.
+ * - TRANSPORT_LOG_DEBUG - minimal set of events that could help to reconstruct
+ * the execution path. Usually disabled in release builds.
+ * - TRANSPORT_LOG_VERBOSE - all other events. Usually disabled in release
+ * builds.
+ *
+ * *Ideally*, log file of debugged, well tested, production ready application
+ * should be empty or very small. Choosing a right log level is as important as
+ * providing short and self descriptive log message.
+ */
+#define TRANSPORT_LOG_VERBOSE 1
+#define TRANSPORT_LOG_DEBUG 2
+#define TRANSPORT_LOG_INFO 3
+#define TRANSPORT_LOG_WARN 4
+#define TRANSPORT_LOG_ERROR 5
+#define TRANSPORT_LOG_FATAL 6
+#define TRANSPORT_LOG_NONE 0xFF
+
+/* "Current" log level is a compile time check and has no runtime overhead. Log
+ * level that is below current log level it said to be "disabled". Otherwise,
+ * it's "enabled". Log messages that are disabled has no runtime overhead - they
+ * are converted to no-op by preprocessor and then eliminated by compiler.
+ * Current log level is configured per compilation module (.c/.cpp/.m file) by
+ * defining TRANSPORT_LOG_DEF_LEVEL or TRANSPORT_LOG_LEVEL. TRANSPORT_LOG_LEVEL
+ * has higer priority and when defined overrides value provided by
+ * TRANSPORT_LOG_DEF_LEVEL.
+ *
+ * Common practice is to define default current log level with
+ * TRANSPORT_LOG_DEF_LEVEL in build script (e.g. Makefile, CMakeLists.txt, gyp,
+ * etc.) for the entire project or target:
+ *
+ *   CC_ARGS := -DTRANSPORT_LOG_DEF_LEVEL=TRANSPORT_LOG_INFO
+ *
+ * And when necessary to override it with TRANSPORT_LOG_LEVEL in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ *   #define TRANSPORT_LOG_LEVEL TRANSPORT_LOG_VERBOSE
+ *   #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_LEVEL and TRANSPORT_LOG_LEVEL are undefined, then
+ * TRANSPORT_LOG_INFO will be used for release builds (NDEBUG is defined) and
+ * TRANSPORT_LOG_DEBUG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_LEVEL
+#elif defined(TRANSPORT_LOG_DEF_LEVEL)
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEF_LEVEL
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_INFO
+#else
+#define _TRANSPORT_LOG_LEVEL TRANSPORT_LOG_DEBUG
+#endif
+#endif
+
+/* "Output" log level is a runtime check. When log level is below output log
+ * level it said to be "turned off" (or just "off" for short). Otherwise it's
+ * "turned on" (or just "on"). Log levels that were "disabled" (see
+ * TRANSPORT_LOG_LEVEL and TRANSPORT_LOG_DEF_LEVEL) can't be "turned on", but
+ * "enabled" log levels could be "turned off". Only messages with log level
+ * which is "turned on" will reach output facility. All other messages will be
+ * ignored (and their arguments will not be evaluated). Output log level is a
+ * global property and configured per process using
+ * transport_log_set_output_level() function which can be called at any time.
+ *
+ * Though in some cases it could be useful to configure output log level per
+ * compilation module or per library. There are two ways to achieve that:
+ * - Define TRANSPORT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired
+ * output log level.
+ * - Copy transport_log.h and transport_log.c files into your library and build
+ * it with TRANSPORT_LOG_LIBRARY_PREFIX defined to library specific prefix. See
+ *   TRANSPORT_LOG_LIBRARY_PREFIX for more details.
+ *
+ * When defined, TRANSPORT_LOG_OUTPUT_LEVEL must evaluate to integral value that
+ * corresponds to desired output log level. Use it only when compilation module
+ * is required to have output log level which is different from global output
+ * log level set by transport_log_set_output_level() function. For other cases,
+ * consider defining TRANSPORT_LOG_LEVEL or using
+ * transport_log_set_output_level() function.
+ *
+ * Example:
+ *
+ *   #define TRANSPORT_LOG_OUTPUT_LEVEL g_module_log_level
+ *   #include <hicn/transport_log.h>
+ *   static int g_module_log_level = TRANSPORT_LOG_INFO;
+ *   static void foo() {
+ *       TRANSPORT_LOGI("Will check g_module_log_level for output log level");
+ *   }
+ *   void debug_log(bool on) {
+ *       g_module_log_level = on? TRANSPORT_LOG_DEBUG: TRANSPORT_LOG_INFO;
+ *   }
+ *
+ * Note on performance. This expression will be evaluated each time message is
+ * logged (except when message log level is "disabled" - see TRANSPORT_LOG_LEVEL
+ * for details). Keep this expression as simple as possible, otherwise it will
+ * not only add runtime overhead, but also will increase size of call site
+ * (which will result in larger executable). The prefered way is to use integer
+ * variable (as in example above). If structure must be used, log_level field
+ * must be the first field in this structure:
+ *
+ *   #define TRANSPORT_LOG_OUTPUT_LEVEL (g_config.log_level)
+ *   #include <hicn/transport_log.h>
+ *   struct config {
+ *       int log_level;
+ *       unsigned other_field;
+ *       [...]
+ *   };
+ *   static config g_config = {TRANSPORT_LOG_INFO, 0, ...};
+ *
+ * This allows compiler to generate more compact load instruction (no need to
+ * specify offset since it's zero). Calling a function to get output log level
+ * is generaly a bad idea, since it will increase call site size and runtime
+ * overhead even further.
+ */
+#if defined(TRANSPORT_LOG_OUTPUT_LEVEL)
+#define _TRANSPORT_LOG_OUTPUT_LEVEL TRANSPORT_LOG_OUTPUT_LEVEL
+#else
+#define _TRANSPORT_LOG_OUTPUT_LEVEL _transport_log_global_output_lvl
+#endif
+
+/* "Tag" is a compound string that could be associated with a log message. It
+ * consists of tag prefix and tag (both are optional).
+ *
+ * Tag prefix is a global property and configured per process using
+ * transport_log_set_tag_prefix() function. Tag prefix identifies context in
+ * which component or module is running (e.g. process name). For example, the
+ * same library could be used in both client and server processes that work on
+ * the same machine. Tag prefix could be used to easily distinguish between
+ * them. For more details about tag prefix see transport_log_set_tag_prefix()
+ * function. Tag prefix
+ *
+ * Tag identifies component or module. It is configured per compilation module
+ * (.c/.cpp/.m file) by defining TRANSPORT_LOG_TAG or TRANSPORT_LOG_DEF_TAG.
+ * TRANSPORT_LOG_TAG has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_TAG. When defined, value must evaluate to
+ * (const char *), so for strings double quotes must be used.
+ *
+ * Default tag could be defined with TRANSPORT_LOG_DEF_TAG in build script (e.g.
+ * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
+ *
+ *   CC_ARGS := -DTRANSPORT_LOG_DEF_TAG=\"MISC\"
+ *
+ * And when necessary could be overriden with TRANSPORT_LOG_TAG in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ *   #define TRANSPORT_LOG_TAG "MAIN"
+ *   #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_TAG and TRANSPORT_LOG_TAG are undefined no tag will
+ * be added to the log message (tag prefix still could be added though).
+ *
+ * Output example:
+ *
+ *   04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1
+ *                                    |     |
+ *                                    |     +- tag (e.g. module)
+ *                                    +- tag prefix (e.g. process name)
+ */
+#if defined(TRANSPORT_LOG_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_TAG
+#elif defined(TRANSPORT_LOG_DEF_TAG)
+#define _TRANSPORT_LOG_TAG TRANSPORT_LOG_DEF_TAG
+#else
+#define _TRANSPORT_LOG_TAG 0
+#endif
+
+/* Source location is part of a log line that describes location (function or
+ * method name, file name and line number, e.g. "runloop@main.cpp:68") of a
+ * log statement that produced it.
+ * Source location formats are:
+ * - TRANSPORT_LOG_SRCLOC_NONE - don't add source location to log line.
+ * - TRANSPORT_LOG_SRCLOC_SHORT - add source location in short form (file and
+ * line number, e.g. "@main.cpp:68").
+ * - TRANSPORT_LOG_SRCLOC_LONG - add source location in long form (function or
+ * method name, file and line number, e.g. "runloop@main.cpp:68").
+ */
+#define TRANSPORT_LOG_SRCLOC_NONE 0
+#define TRANSPORT_LOG_SRCLOC_SHORT 1
+#define TRANSPORT_LOG_SRCLOC_LONG 2
+
+/* Source location format is configured per compilation module (.c/.cpp/.m
+ * file) by defining TRANSPORT_LOG_DEF_SRCLOC or TRANSPORT_LOG_SRCLOC.
+ * TRANSPORT_LOG_SRCLOC has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_SRCLOC.
+ *
+ * Common practice is to define default format with TRANSPORT_LOG_DEF_SRCLOC in
+ * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ *   CC_ARGS := -DTRANSPORT_LOG_DEF_SRCLOC=TRANSPORT_LOG_SRCLOC_LONG
+ *
+ * And when necessary to override it with TRANSPORT_LOG_SRCLOC in .c/.cpp/.m
+ * files before including transport_log.h:
+ *
+ *   #define TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+ *   #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_SRCLOC and TRANSPORT_LOG_SRCLOC are undefined, then
+ * TRANSPORT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined)
+ * and TRANSPORT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
+ */
+#if defined(TRANSPORT_LOG_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC
+#elif defined(TRANSPORT_LOG_DEF_SRCLOC)
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_DEF_SRCLOC
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_NONE
+#else
+#define _TRANSPORT_LOG_SRCLOC TRANSPORT_LOG_SRCLOC_LONG
+#endif
+#endif
+#if TRANSPORT_LOG_SRCLOC_LONG == _TRANSPORT_LOG_SRCLOC
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION _TRANSPORT_LOG_FUNCTION
+#else
+#define _TRANSPORT_LOG_SRCLOC_FUNCTION 0
+#endif
+
+/* Censoring provides conditional logging of secret information, also known as
+ * Personally Identifiable Information (PII) or Sensitive Personal Information
+ * (SPI). Censoring can be either enabled (TRANSPORT_LOG_CENSORED) or disabled
+ * (TRANSPORT_LOG_UNCENSORED). When censoring is enabled, log statements marked
+ * as "secrets" will be ignored and will have zero overhead (arguments also will
+ * not be evaluated).
+ */
+#define TRANSPORT_LOG_CENSORED 1
+#define TRANSPORT_LOG_UNCENSORED 0
+
+/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
+ * TRANSPORT_LOG_DEF_CENSORING or TRANSPORT_LOG_CENSORING.
+ * TRANSPORT_LOG_CENSORING has higer priority and when defined overrides value
+ * provided by TRANSPORT_LOG_DEF_CENSORING.
+ *
+ * Common practice is to define default censoring with
+ * TRANSPORT_LOG_DEF_CENSORING in build script (e.g. Makefile, CMakeLists.txt,
+ * gyp, etc.) for the entire project or target:
+ *
+ *   CC_ARGS := -DTRANSPORT_LOG_DEF_CENSORING=TRANSPORT_LOG_CENSORED
+ *
+ * And when necessary to override it with TRANSPORT_LOG_CENSORING in .c/.cpp/.m
+ * files before including transport_log.h (consider doing it only for debug
+ * purposes and be very careful not to push such temporary changes to source
+ * control):
+ *
+ *   #define TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+ *   #include <hicn/transport_log.h>
+ *
+ * If both TRANSPORT_LOG_DEF_CENSORING and TRANSPORT_LOG_CENSORING are
+ * undefined, then TRANSPORT_LOG_CENSORED will be used for release builds
+ * (NDEBUG is defined) and TRANSPORT_LOG_UNCENSORED otherwise (NDEBUG is not
+ * defined).
+ */
+#if defined(TRANSPORT_LOG_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORING
+#elif defined(TRANSPORT_LOG_DEF_CENSORING)
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_DEF_CENSORING
+#else
+#ifdef NDEBUG
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_CENSORED
+#else
+#define _TRANSPORT_LOG_CENSORING TRANSPORT_LOG_UNCENSORED
+#endif
+#endif
+
+/* Check censoring at compile time. Evaluates to true when censoring is disabled
+ * (i.e. when secrets will be logged). For example:
+ *
+ *   #if TRANSPORT_LOG_SECRETS
+ *       char ssn[16];
+ *       getSocialSecurityNumber(ssn);
+ *       TRANSPORT_LOGI("Customer ssn: %s", ssn);
+ *   #endif
+ *
+ * See TRANSPORT_LOG_SECRET() macro for a more convenient way of guarding single
+ * log statement.
+ */
+#define TRANSPORT_LOG_SECRETS \
+  (TRANSPORT_LOG_UNCENSORED == _TRANSPORT_LOG_CENSORING)
+
+/* Static (compile-time) initialization support allows to configure logging
+ * before entering main() function. This mostly useful in C++ where functions
+ * and methods could be called during initialization of global objects. Those
+ * functions and methods could record log messages too and for that reason
+ * static initialization of logging configuration is customizable.
+ *
+ * Macros below allow to specify values to use for initial configuration:
+ * - TRANSPORT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
+ *   TRANSPORT_LOG_MEM_WIDTH in transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default:
+ * stderr or platform specific, see TRANSPORT_LOG_USE_XXX macros in
+ * transport_log.c)
+ * - TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level
+ * (default: 0 - all levals are "turned on")
+ *
+ * For example, in log_config.c:
+ *
+ *   #include <hicn/transport_log.h>
+ *   TRANSPORT_LOG_DEFINE_TAG_PREFIX = "MyApp";
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_PUT_STD,
+ * custom_output_callback, 0}; TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL =
+ * TRANSPORT_LOG_INFO;
+ *
+ * However, to use any of those macros transport_log library must be compiled
+ * with following macros defined:
+ * - to use TRANSPORT_LOG_DEFINE_TAG_PREFIX define
+ * TRANSPORT_LOG_EXTERN_TAG_PREFIX
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_FORMAT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT define
+ * TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT
+ * - to use TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
+ *   TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+ *
+ * When transport_log library compiled with one of TRANSPORT_LOG_EXTERN_XXX
+ * macros defined, corresponding TRANSPORT_LOG_DEFINE_XXX macro MUST be used
+ * exactly once somewhere. Otherwise build will fail with link error (undefined
+ * symbol).
+ */
+#define TRANSPORT_LOG_DEFINE_TAG_PREFIX const char *_transport_log_tag_prefix
+#define TRANSPORT_LOG_DEFINE_GLOBAL_FORMAT \
+  transport_log_format _transport_log_global_format
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT \
+  transport_log_output _transport_log_global_output
+#define TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL \
+  int _transport_log_global_output_lvl
+
+/* Pointer to global format options. Direct modification is not allowed. Use
+ * transport_log_set_mem_width() instead. Could be used to initialize
+ * transport_log_spec structure:
+ *
+ *   const transport_log_output g_output = {TRANSPORT_LOG_PUT_STD,
+ * output_callback, 0}; const transport_log_spec g_spec =
+ * {TRANSPORT_LOG_GLOBAL_FORMAT, &g_output}; TRANSPORT_LOGI_AUX(&g_spec,
+ * "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_FORMAT \
+  ((const transport_log_format *)&_transport_log_global_format)
+
+/* Pointer to global output variable. Direct modification is not allowed. Use
+ * transport_log_set_output_v() or transport_log_set_output_p() instead. Could
+ * be used to initialize transport_log_spec structure:
+ *
+ *   const transport_log_format g_format = {40};
+ *   const transport_log_spec g_spec = {g_format, TRANSPORT_LOG_GLOBAL_OUTPUT};
+ *   TRANSPORT_LOGI_AUX(&g_spec, "Hello");
+ */
+#define TRANSPORT_LOG_GLOBAL_OUTPUT \
+  ((const transport_log_output *)&_transport_log_global_output)
+
+/* When defined, all library symbols produced by linker will be prefixed with
+ * provided value. That allows to use transport_log library privately in another
+ * libraries without exposing transport_log symbols in their original form (to
+ * avoid possible conflicts with other libraries / components that also could
+ * use transport_log for logging). Value must be without quotes, for example:
+ *
+ *   CC_ARGS := -DTRANSPORT_LOG_LIBRARY_PREFIX=my_lib_
+ *
+ * Note, that in this mode TRANSPORT_LOG_LIBRARY_PREFIX must be defined when
+ * building transport_log library AND it also must be defined to the same value
+ * when building a library that uses it. For example, consider fictional
+ * KittyHttp library that wants to use transport_log for logging. First approach
+ * that could be taken is to add transport_log.h and transport_log.c to the
+ * KittyHttp's source code tree directly. In that case it will be enough just to
+ * define TRANSPORT_LOG_LIBRARY_PREFIX in KittyHttp's build script:
+ *
+ *   // KittyHttp/CMakeLists.txt
+ *   target_compile_definitions(KittyHttp PRIVATE
+ *                              "TRANSPORT_LOG_LIBRARY_PREFIX=KittyHttp_")
+ *
+ * If KittyHttp doesn't want to include transport_log source code in its source
+ * tree and wants to build transport_log as a separate library than
+ * transport_log library must be built with TRANSPORT_LOG_LIBRARY_PREFIX defined
+ * to KittyHttp_ AND KittyHttp library itself also needs to define
+ * TRANSPORT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do so either in its build
+ * script, as in example above, or by providing a wrapper header that KittyHttp
+ * library will need to use instead of transport_log.h:
+ *
+ *   // KittyHttpLogging.h
+ *   #define TRANSPORT_LOG_LIBRARY_PREFIX KittyHttp_
+ *   #include <hicn/transport_log.h>
+ *
+ * Regardless of the method chosen, the end result is that transport_log symbols
+ * will be prefixed with "KittyHttp_", so if a user of KittyHttp (say
+ * DogeBrowser) also uses transport_log for logging, they will not interferer
+ * with each other. Both will have their own log level, output facility, format
+ * options etc.
+ */
+#ifdef TRANSPORT_LOG_LIBRARY_PREFIX
+#define _TRANSPORT_LOG_DECOR__(prefix, name) prefix##name
+#define _TRANSPORT_LOG_DECOR_(prefix, name) _TRANSPORT_LOG_DECOR__(prefix, name)
+#define _TRANSPORT_LOG_DECOR(name) \
+  _TRANSPORT_LOG_DECOR_(TRANSPORT_LOG_LIBRARY_PREFIX, name)
+
+#define transport_log_set_tag_prefix \
+  _TRANSPORT_LOG_DECOR(transport_log_set_tag_prefix)
+#define transport_log_set_mem_width \
+  _TRANSPORT_LOG_DECOR(transport_log_set_mem_width)
+#define transport_log_set_output_level \
+  _TRANSPORT_LOG_DECOR(transport_log_set_output_level)
+#define transport_log_set_output_v \
+  _TRANSPORT_LOG_DECOR(transport_log_set_output_v)
+#define transport_log_set_output_p \
+  _TRANSPORT_LOG_DECOR(transport_log_set_output_p)
+#define transport_log_out_stderr_callback \
+  _TRANSPORT_LOG_DECOR(transport_log_out_stderr_callback)
+#define _transport_log_tag_prefix \
+  _TRANSPORT_LOG_DECOR(_transport_log_tag_prefix)
+#define _transport_log_global_format \
+  _TRANSPORT_LOG_DECOR(_transport_log_global_format)
+#define _transport_log_global_output \
+  _TRANSPORT_LOG_DECOR(_transport_log_global_output)
+#define _transport_log_global_output_lvl \
+  _TRANSPORT_LOG_DECOR(_transport_log_global_output_lvl)
+#define _transport_log_write_d _TRANSPORT_LOG_DECOR(_transport_log_write_d)
+#define _transport_log_write_aux_d \
+  _TRANSPORT_LOG_DECOR(_transport_log_write_aux_d)
+#define _transport_log_write _TRANSPORT_LOG_DECOR(_transport_log_write)
+#define _transport_log_write_aux _TRANSPORT_LOG_DECOR(_transport_log_write_aux)
+#define _transport_log_write_mem_d \
+  _TRANSPORT_LOG_DECOR(_transport_log_write_mem_d)
+#define _transport_log_write_mem_aux_d \
+  _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux_d)
+#define _transport_log_write_mem _TRANSPORT_LOG_DECOR(_transport_log_write_mem)
+#define _transport_log_write_mem_aux \
+  _TRANSPORT_LOG_DECOR(_transport_log_write_mem_aux)
+#define _transport_log_stderr_spec \
+  _TRANSPORT_LOG_DECOR(_transport_log_stderr_spec)
+#endif
+
+#if defined(__printflike)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+  __printflike(str_index, first_to_check)
+#elif defined(__GNUC__)
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check) \
+  __attribute__((format(__printf__, str_index, first_to_check)))
+#else
+#define _TRANSPORT_LOG_PRINTFLIKE(str_index, first_to_check)
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
+#define _TRANSPORT_LOG_FUNCTION __FUNCTION__
+#else
+#define _TRANSPORT_LOG_FUNCTION __func__
+#endif
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+#define _TRANSPORT_LOG_INLINE __inline
+#define _TRANSPORT_LOG_IF(cond)                                       \
+  __pragma(warning(push)) __pragma(warning(disable : 4127)) if (cond) \
+      __pragma(warning(pop))
+#define _TRANSPORT_LOG_WHILE(cond)                                       \
+  __pragma(warning(push)) __pragma(warning(disable : 4127)) while (cond) \
+      __pragma(warning(pop))
+#else
+#define _TRANSPORT_LOG_INLINE inline
+#define _TRANSPORT_LOG_IF(cond) if (cond)
+#define _TRANSPORT_LOG_WHILE(cond) while (cond)
+#endif
+#define _TRANSPORT_LOG_NEVER _TRANSPORT_LOG_IF(0)
+#define _TRANSPORT_LOG_ONCE _TRANSPORT_LOG_WHILE(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
+ * Use 0 or empty string to disable (default). Common use is to set it to
+ * the process (or build target) name (e.g. to separate client and server
+ * processes). Function will NOT copy provided prefix string, but will store the
+ * pointer. Hence specified prefix string must remain valid. See
+ * TRANSPORT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main()
+ * function. See TRANSPORT_LOG_TAG for more information about tag and tag
+ * prefix.
+ */
+void transport_log_set_tag_prefix(const char *const prefix);
+
+/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
+ *
+ *   I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo
+ *                |<-          w bytes         ->|  |<-  w chars ->|
+ *
+ * See TRANSPORT_LOGF_MEM and TRANSPORT_LOGF_MEM_AUX for more details.
+ */
+void transport_log_set_mem_width(const unsigned w);
+
+/* Set "output" log level. See TRANSPORT_LOG_LEVEL and
+ * TRANSPORT_LOG_OUTPUT_LEVEL for more info about log levels.
+ */
+void transport_log_set_output_level(const int lvl);
+
+/* Put mask is a set of flags that define what fields will be added to each
+ * log message. Default value is TRANSPORT_LOG_PUT_STD and other flags could be
+ * used to alter its behavior. See transport_log_set_output_v() for more
+ * details.
+ *
+ * Note about TRANSPORT_LOG_PUT_SRC: it will be added only in debug builds
+ * (NDEBUG is not defined).
+ */
+enum {
+  TRANSPORT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
+  TRANSPORT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
+  TRANSPORT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
+  TRANSPORT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
+  TRANSPORT_LOG_PUT_STD = 0xffff, /* everything (default) */
+};
+
+typedef struct transport_log_message {
+  int lvl;         /* Log level of the message */
+  const char *tag; /* Associated tag (without tag prefix) */
+  char *buf;       /* Buffer start */
+  char *e; /* Buffer end (last position where EOL with 0 could be written) */
+  char *p; /* Buffer content end (append position) */
+  char *tag_b; /* Prefixed tag start */
+  char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
+  char *msg_b; /* Message start (expanded format string) */
+} transport_log_message;
+
+/* Type of output callback function. It will be called for each log line allowed
+ * by both "current" and "output" log levels ("enabled" and "turned on").
+ * Callback function is allowed to modify content of the buffers pointed by the
+ * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
+ * is UTF-8 encoded (no BOM mark).
+ */
+typedef void (*transport_log_output_cb)(const transport_log_message *msg,
+                                        void *arg);
+
+/* Format options. For more details see transport_log_set_mem_width().
+ */
+typedef struct transport_log_format {
+  unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
+} transport_log_format;
+
+/* Output facility.
+ */
+typedef struct transport_log_output {
+  unsigned
+      mask;  /* What to put into log line buffer (see TRANSPORT_LOG_PUT_XXX) */
+  void *arg; /* User provided output callback argument */
+  transport_log_output_cb callback; /* Output callback function */
+} transport_log_output;
+
+/* Set output callback function.
+ *
+ * Mask allows to control what information will be added to the log line buffer
+ * before callback function is invoked. Default mask value is
+ * TRANSPORT_LOG_PUT_STD.
+ */
+void transport_log_set_output_v(const unsigned mask, void *const arg,
+                                const transport_log_output_cb callback);
+static _TRANSPORT_LOG_INLINE void transport_log_set_output_p(
+    const transport_log_output *const output) {
+  transport_log_set_output_v(output->mask, output->arg, output->callback);
+}
+
+/* Used with _AUX macros and allows to override global format and output
+ * facility. Use TRANSPORT_LOG_GLOBAL_FORMAT and TRANSPORT_LOG_GLOBAL_OUTPUT for
+ * values from global configuration. Example:
+ *
+ *   static const transport_log_output module_output = {
+ *       TRANSPORT_LOG_PUT_STD, 0, custom_output_callback
+ *   };
+ *   static const transport_log_spec module_spec = {
+ *       TRANSPORT_LOG_GLOBAL_FORMAT, &module_output
+ *   };
+ *   TRANSPORT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
+ *
+ * See TRANSPORT_LOGF_AUX and TRANSPORT_LOGF_MEM_AUX for details.
+ */
+typedef struct transport_log_spec {
+  const transport_log_format *format;
+  const transport_log_output *output;
+} transport_log_spec;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Execute log statement if condition is true. Example:
+ *
+ *   TRANSPORT_LOG_IF(1 < 2, TRANSPORT_LOGI("Log this"));
+ *   TRANSPORT_LOG_IF(1 > 2, TRANSPORT_LOGI("Don't log this"));
+ *
+ * Keep in mind though, that if condition can't be evaluated at compile time,
+ * then it will be evaluated at run time. This will increase exectuable size
+ * and can have noticeable performance overhead. Try to limit conditions to
+ * expressions that can be evaluated at compile time.
+ */
+#define TRANSPORT_LOG_IF(cond, f)    \
+  do {                               \
+    _TRANSPORT_LOG_IF((cond)) { f; } \
+  }                                  \
+  _TRANSPORT_LOG_ONCE
+
+/* Mark log statement as "secret". Log statements that are marked as secrets
+ * will NOT be executed when censoring is enabled (see TRANSPORT_LOG_CENSORED).
+ * Example:
+ *
+ *   TRANSPORT_LOG_SECRET(TRANSPORT_LOGI("Credit card: %s", credit_card));
+ *   TRANSPORT_LOG_SECRET(TRANSPORT_LOGD_MEM(cipher, cipher_sz, "Cipher
+ * bytes:"));
+ */
+#define TRANSPORT_LOG_SECRET(f) TRANSPORT_LOG_IF(TRANSPORT_LOG_SECRETS, f)
+
+/* Check "current" log level at compile time (ignoring "output" log level).
+ * Evaluates to true when specified log level is enabled. For example:
+ *
+ *   #if TRANSPORT_LOG_ENABLED_DEBUG
+ *       const char *const g_enum_strings[] = {
+ *           "enum_value_0", "enum_value_1", "enum_value_2"
+ *       };
+ *   #endif
+ *   // ...
+ *   #if TRANSPORT_LOG_ENABLED_DEBUG
+ *       TRANSPORT_LOGD("enum value: %s", g_enum_strings[v]);
+ *   #endif
+ *
+ * See TRANSPORT_LOG_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ENABLED(lvl) ((lvl) >= _TRANSPORT_LOG_LEVEL)
+#define TRANSPORT_LOG_ENABLED_VERBOSE \
+  TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ENABLED_DEBUG TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ENABLED_INFO TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ENABLED_WARN TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ENABLED_ERROR TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ENABLED_FATAL TRANSPORT_LOG_ENABLED(TRANSPORT_LOG_FATAL)
+
+/* Check "output" log level at run time (taking into account "current" log
+ * level as well). Evaluates to true when specified log level is turned on AND
+ * enabled. For example:
+ *
+ *   if (TRANSPORT_LOG_ON_DEBUG)
+ *   {
+ *       char hash[65];
+ *       sha256(data_ptr, data_sz, hash);
+ *       TRANSPORT_LOGD("data: len=%u, sha256=%s", data_sz, hash);
+ *   }
+ *
+ * See TRANSPORT_LOG_OUTPUT_LEVEL for details.
+ */
+#define TRANSPORT_LOG_ON(lvl) \
+  (TRANSPORT_LOG_ENABLED((lvl)) && (lvl) >= _TRANSPORT_LOG_OUTPUT_LEVEL)
+#define TRANSPORT_LOG_ON_VERBOSE TRANSPORT_LOG_ON(TRANSPORT_LOG_VERBOSE)
+#define TRANSPORT_LOG_ON_DEBUG TRANSPORT_LOG_ON(TRANSPORT_LOG_DEBUG)
+#define TRANSPORT_LOG_ON_INFO TRANSPORT_LOG_ON(TRANSPORT_LOG_INFO)
+#define TRANSPORT_LOG_ON_WARN TRANSPORT_LOG_ON(TRANSPORT_LOG_WARN)
+#define TRANSPORT_LOG_ON_ERROR TRANSPORT_LOG_ON(TRANSPORT_LOG_ERROR)
+#define TRANSPORT_LOG_ON_FATAL TRANSPORT_LOG_ON(TRANSPORT_LOG_FATAL)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *_transport_log_tag_prefix;
+extern transport_log_format _transport_log_global_format;
+extern transport_log_output _transport_log_global_output;
+extern int _transport_log_global_output_lvl;
+extern const transport_log_spec _transport_log_stderr_spec;
+
+void _transport_log_write_d(const char *const func, const char *const file,
+                            const unsigned line, const int lvl,
+                            const char *const tag, const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+void _transport_log_write_aux_d(const char *const func, const char *const file,
+                                const unsigned line,
+                                const transport_log_spec *const log,
+                                const int lvl, const char *const tag,
+                                const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(7, 8);
+void _transport_log_write(const int lvl, const char *const tag,
+                          const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(3, 4);
+void _transport_log_write_aux(const transport_log_spec *const log,
+                              const int lvl, const char *const tag,
+                              const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(4, 5);
+void _transport_log_write_mem_d(const char *const func, const char *const file,
+                                const unsigned line, const int lvl,
+                                const char *const tag, const void *const d,
+                                const unsigned d_sz, const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(8, 9);
+void _transport_log_write_mem_aux_d(const char *const func,
+                                    const char *const file, const unsigned line,
+                                    const transport_log_spec *const log,
+                                    const int lvl, const char *const tag,
+                                    const void *const d, const unsigned d_sz,
+                                    const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(9, 10);
+void _transport_log_write_mem(const int lvl, const char *const tag,
+                              const void *const d, const unsigned d_sz,
+                              const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(5, 6);
+void _transport_log_write_mem_aux(const transport_log_spec *const log,
+                                  const int lvl, const char *const tag,
+                                  const void *const d, const unsigned d_sz,
+                                  const char *const fmt, ...)
+    _TRANSPORT_LOG_PRINTFLIKE(6, 7);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Message logging macros:
+ * - TRANSPORT_LOGV("format string", args, ...)
+ * - TRANSPORT_LOGD("format string", args, ...)
+ * - TRANSPORT_LOGI("format string", args, ...)
+ * - TRANSPORT_LOGW("format string", args, ...)
+ * - TRANSPORT_LOGE("format string", args, ...)
+ * - TRANSPORT_LOGF("format string", args, ...)
+ *
+ * Memory logging macros:
+ * - TRANSPORT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - TRANSPORT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
+ *
+ * Auxiliary logging macros:
+ * - TRANSPORT_LOGV_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGD_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGI_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGW_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGE_AUX(&log_instance, "format string", args, ...)
+ * - TRANSPORT_LOGF_AUX(&log_instance, "format string", args, ...)
+ *
+ * Auxiliary memory logging macros:
+ * - TRANSPORT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string",
+ * args, ...)
+ *
+ * Preformatted string logging macros:
+ * - TRANSPORT_LOGV_STR("preformatted string");
+ * - TRANSPORT_LOGD_STR("preformatted string");
+ * - TRANSPORT_LOGI_STR("preformatted string");
+ * - TRANSPORT_LOGW_STR("preformatted string");
+ * - TRANSPORT_LOGE_STR("preformatted string");
+ * - TRANSPORT_LOGF_STR("preformatted string");
+ *
+ * Explicit log level and tag macros:
+ * - TRANSPORT_LOG_WRITE(level, tag, "format string", args, ...)
+ * - TRANSPORT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string",
+ * args, ...)
+ * - TRANSPORT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args,
+ * ...)
+ * - TRANSPORT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
+ *                        "format string", args, ...)
+ *
+ * Format string follows printf() conventions. Both data_ptr and data_sz could
+ * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
+ * match format specifiers in format string.
+ *
+ * Library assuming UTF-8 encoding for all strings (char *), including format
+ * string itself.
+ */
+#if TRANSPORT_LOG_SRCLOC_NONE == _TRANSPORT_LOG_SRCLOC
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...)                                  \
+  do {                                                                      \
+    if (TRANSPORT_LOG_ON(lvl)) _transport_log_write(lvl, tag, __VA_ARGS__); \
+  }                                                                         \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...)         \
+  do {                                                          \
+    if (TRANSPORT_LOG_ON(lvl))                                  \
+      _transport_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
+  }                                                             \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...)         \
+  do {                                                      \
+    if (TRANSPORT_LOG_ON(lvl))                              \
+      _transport_log_write_aux(log, lvl, tag, __VA_ARGS__); \
+  }                                                         \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...)         \
+  do {                                                                   \
+    if (TRANSPORT_LOG_ON(lvl))                                           \
+      _transport_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
+  }                                                                      \
+  _TRANSPORT_LOG_ONCE
+#else
+#define TRANSPORT_LOG_WRITE(lvl, tag, ...)                             \
+  do {                                                                 \
+    if (TRANSPORT_LOG_ON(lvl))                                         \
+      _transport_log_write_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+                             __LINE__, lvl, tag, __VA_ARGS__);         \
+  }                                                                    \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...)                     \
+  do {                                                                      \
+    if (TRANSPORT_LOG_ON(lvl))                                              \
+      _transport_log_write_mem_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__,  \
+                                 __LINE__, lvl, tag, d, d_sz, __VA_ARGS__); \
+  }                                                                         \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_AUX(log, lvl, tag, ...)                        \
+  do {                                                                     \
+    if (TRANSPORT_LOG_ON(lvl))                                             \
+      _transport_log_write_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+                                 __LINE__, log, lvl, tag, __VA_ARGS__);    \
+  }                                                                        \
+  _TRANSPORT_LOG_ONCE
+#define TRANSPORT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...)               \
+  do {                                                                         \
+    if (TRANSPORT_LOG_ON(lvl))                                                 \
+      _transport_log_write_mem_aux_d(_TRANSPORT_LOG_SRCLOC_FUNCTION, __FILE__, \
+                                     __LINE__, log, lvl, tag, d, d_sz,         \
+                                     __VA_ARGS__);                             \
+  }                                                                            \
+  _TRANSPORT_LOG_ONCE
+#endif
+
+static _TRANSPORT_LOG_INLINE void _transport_log_unused(const int dummy, ...) {
+  (void)dummy;
+}
+
+#define _TRANSPORT_LOG_UNUSED(...)                              \
+  do {                                                          \
+    _TRANSPORT_LOG_NEVER _transport_log_unused(0, __VA_ARGS__); \
+  }                                                             \
+  _TRANSPORT_LOG_ONCE
+
+#if TRANSPORT_LOG_ENABLED_VERBOSE
+#define TRANSPORT_LOGV(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(log, ...)                                      \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(d, d_sz, ...)                                      \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(log, d, d_sz, ...)                            \
+  TRANSPORT_LOG_WRITE_MEM(log, TRANSPORT_LOG_VERBOSE, _TRANSPORT_LOG_TAG, d, \
+                          d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGV(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGV_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_DEBUG
+#define TRANSPORT_LOGD(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(log, ...)                                    \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(d, d_sz, ...)                                    \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(log, d, d_sz, ...)                              \
+  TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_DEBUG, _TRANSPORT_LOG_TAG, d, \
+                              d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGD(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGD_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_INFO
+#define TRANSPORT_LOGI(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(log, ...)                                   \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(d, d_sz, ...)                                   \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(log, d, d_sz, ...)                             \
+  TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_INFO, _TRANSPORT_LOG_TAG, d, \
+                              d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGI(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGI_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_WARN
+#define TRANSPORT_LOGW(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(log, ...)                                   \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(d, d_sz, ...)                                   \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(log, d, d_sz, ...)                             \
+  TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_WARN, _TRANSPORT_LOG_TAG, d, \
+                              d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGW(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGW_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_ERROR
+#define TRANSPORT_LOGE(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(log, ...)                                    \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(d, d_sz, ...)                                    \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(log, d, d_sz, ...)                              \
+  TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_ERROR, _TRANSPORT_LOG_TAG, d, \
+                              d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGE(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGE_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if TRANSPORT_LOG_ENABLED_FATAL
+#define TRANSPORT_LOGF(...) \
+  TRANSPORT_LOG_WRITE(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, __VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(log, ...)                                    \
+  TRANSPORT_LOG_WRITE_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(d, d_sz, ...)                                    \
+  TRANSPORT_LOG_WRITE_MEM(TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, d_sz, \
+                          __VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(log, d, d_sz, ...)                              \
+  TRANSPORT_LOG_WRITE_MEM_AUX(log, TRANSPORT_LOG_FATAL, _TRANSPORT_LOG_TAG, d, \
+                              d_sz, __VA_ARGS__)
+#else
+#define TRANSPORT_LOGF(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#define TRANSPORT_LOGF_MEM_AUX(...) _TRANSPORT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#define TRANSPORT_LOGV_STR(s) TRANSPORT_LOGV("%s", (s))
+#define TRANSPORT_LOGD_STR(s) TRANSPORT_LOGD("%s", (s))
+#define TRANSPORT_LOGI_STR(s) TRANSPORT_LOGI("%s", (s))
+#define TRANSPORT_LOGW_STR(s) TRANSPORT_LOGW("%s", (s))
+#define TRANSPORT_LOGE_STR(s) TRANSPORT_LOGE("%s", (s))
+#define TRANSPORT_LOGF_STR(s) TRANSPORT_LOGF("%s", (s))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Output to standard error stream. Library uses it by default, though in few
+ * cases it could be necessary to specify it explicitly. For example, when
+ * transport_log library is compiled with TRANSPORT_LOG_EXTERN_GLOBAL_OUTPUT,
+ * application must define and initialize global output variable:
+ *
+ *   TRANSPORT_LOG_DEFINE_GLOBAL_OUTPUT = {TRANSPORT_LOG_OUT_STDERR};
+ *
+ * Another example is when using custom output, stderr could be used as a
+ * fallback when custom output facility failed to initialize:
+ *
+ *   transport_log_set_output_v(TRANSPORT_LOG_OUT_STDERR);
+ */
+enum { TRANSPORT_LOG_OUT_STDERR_MASK = TRANSPORT_LOG_PUT_STD };
+void transport_log_out_stderr_callback(const transport_log_message *const msg,
+                                       void *arg);
+#define TRANSPORT_LOG_OUT_STDERR \
+  TRANSPORT_LOG_OUT_STDERR_MASK, 0, transport_log_out_stderr_callback
+
+/* Predefined spec for stderr. Uses global format options
+ * (TRANSPORT_LOG_GLOBAL_FORMAT) and TRANSPORT_LOG_OUT_STDERR. Could be used to
+ * force output to stderr for a particular message. Example:
+ *
+ *   f = fopen("foo.log", "w");
+ *   if (!f)
+ *       TRANSPORT_LOGE_AUX(TRANSPORT_LOG_STDERR, "Failed to open log file");
+ */
+#define TRANSPORT_LOG_STDERR (&_transport_log_stderr_spec)
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/membuf.cc b/libtransport/src/hicn/transport/utils/membuf.cc
new file mode 100755 (executable)
index 0000000..0ab1a60
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2013-present Facebook, 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.
+ */
+
+/*
+ * The code in this file if adapated from the IOBuf of folly:
+ * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h
+ */
+
+#include <hicn/transport/utils/membuf.h>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <stdexcept>
+#include <vector>
+
+using std::unique_ptr;
+
+namespace {
+
+enum : uint16_t {
+  kHeapMagic = 0xa5a5,
+  // This memory segment contains an MemBuf that is still in use
+  kMemBufInUse = 0x01,
+  // This memory segment contains buffer data that is still in use
+  kDataInUse = 0x02,
+};
+
+enum : std::size_t {
+  // When create() is called for buffers less than kDefaultCombinedBufSize,
+  // we allocate a single combined memory segment for the MemBuf and the data
+  // together.  See the comments for createCombined()/createSeparate() for more
+  // details.
+  //
+  // (The size of 1k is largely just a guess here.  We could could probably do
+  // benchmarks of real applications to see if adjusting this number makes a
+  // difference.  Callers that know their exact use case can also explicitly
+  // call createCombined() or createSeparate().)
+  kDefaultCombinedBufSize = 1024
+};
+
+// Helper function for MemBuf::takeOwnership()
+void takeOwnershipError(bool freeOnError, void* buf,
+                        utils::MemBuf::FreeFunction freeFn, void* userData) {
+  if (!freeOnError) {
+    return;
+  }
+  if (!freeFn) {
+    free(buf);
+    return;
+  }
+  try {
+    freeFn(buf, userData);
+  } catch (...) {
+    // The user's free function is not allowed to throw.
+    // (We are already in the middle of throwing an exception, so
+    // we cannot let this exception go unhandled.)
+    abort();
+  }
+}
+
+}  // namespace
+
+namespace utils {
+
+struct MemBuf::HeapPrefix {
+  explicit HeapPrefix(uint16_t flg) : magic(kHeapMagic), flags(flg) {}
+  ~HeapPrefix() {
+    // Reset magic to 0 on destruction.  This is solely for debugging purposes
+    // to help catch bugs where someone tries to use HeapStorage after it has
+    // been deleted.
+    magic = 0;
+  }
+
+  uint16_t magic;
+  std::atomic<uint16_t> flags;
+};
+
+struct MemBuf::HeapStorage {
+  HeapPrefix prefix;
+  // The MemBuf is last in the HeapStorage object.
+  // This way operator new will work even if allocating a subclass of MemBuf
+  // that requires more space.
+  utils::MemBuf buf;
+};
+
+struct MemBuf::HeapFullStorage {
+  // Make sure jemalloc allocates from the 64-byte class.  Putting this here
+  // because HeapStorage is private so it can't be at namespace level.
+  static_assert(sizeof(HeapStorage) <= 64,
+                "MemBuf may not grow over 56 bytes!");
+
+  HeapStorage hs;
+  SharedInfo shared;
+  std::max_align_t align;
+};
+
+MemBuf::SharedInfo::SharedInfo() : freeFn(nullptr), userData(nullptr) {
+  // Use relaxed memory ordering here.  Since we are creating a new SharedInfo,
+  // no other threads should be referring to it yet.
+  refcount.store(1, std::memory_order_relaxed);
+}
+
+MemBuf::SharedInfo::SharedInfo(FreeFunction fn, void* arg)
+    : freeFn(fn), userData(arg) {
+  // Use relaxed memory ordering here.  Since we are creating a new SharedInfo,
+  // no other threads should be referring to it yet.
+  refcount.store(1, std::memory_order_relaxed);
+}
+
+void* MemBuf::operator new(size_t size) {
+  size_t fullSize = offsetof(HeapStorage, buf) + size;
+  auto* storage = static_cast<HeapStorage*>(malloc(fullSize));
+
+  new (&storage->prefix) HeapPrefix(kMemBufInUse);
+  return &(storage->buf);
+}
+
+void* MemBuf::operator new(size_t /* size */, void* ptr) { return ptr; }
+
+void MemBuf::operator delete(void* ptr) {
+  auto* storageAddr = static_cast<uint8_t*>(ptr) - offsetof(HeapStorage, buf);
+  auto* storage = reinterpret_cast<HeapStorage*>(storageAddr);
+  releaseStorage(storage, kMemBufInUse);
+}
+
+void MemBuf::operator delete(void* /* ptr */, void* /* placement */) {
+  // Provide matching operator for `MemBuf::new` to avoid MSVC compilation
+  // warning (C4291) about memory leak when exception is thrown in the
+  // constructor.
+}
+
+void MemBuf::releaseStorage(HeapStorage* storage, uint16_t freeFlags) {
+  // Use relaxed memory order here.  If we are unlucky and happen to get
+  // out-of-date data the compare_exchange_weak() call below will catch
+  // it and load new data with memory_order_acq_rel.
+  auto flags = storage->prefix.flags.load(std::memory_order_acquire);
+
+  while (true) {
+    uint16_t newFlags = uint16_t(flags & ~freeFlags);
+    if (newFlags == 0) {
+      // The storage space is now unused.  Free it.
+      storage->prefix.HeapPrefix::~HeapPrefix();
+      free(storage);
+      return;
+    }
+
+    // This storage segment still contains portions that are in use.
+    // Just clear the flags specified in freeFlags for now.
+    auto ret = storage->prefix.flags.compare_exchange_weak(
+        flags, newFlags, std::memory_order_acq_rel);
+    if (ret) {
+      // We successfully updated the flags.
+      return;
+    }
+
+    // We failed to update the flags.  Some other thread probably updated them
+    // and cleared some of the other bits.  Continue around the loop to see if
+    // we are the last user now, or if we need to try updating the flags again.
+  }
+}
+
+void MemBuf::freeInternalBuf(void* /* buf */, void* userData) {
+  auto* storage = static_cast<HeapStorage*>(userData);
+  releaseStorage(storage, kDataInUse);
+}
+
+MemBuf::MemBuf(CreateOp, std::size_t capacity)
+    : next_(this),
+      prev_(this),
+      data_(nullptr),
+      length_(0),
+      flags_and_shared_info_(0) {
+  SharedInfo* info;
+  allocExtBuffer(capacity, &buf_, &info, &capacity_);
+  setSharedInfo(info);
+  data_ = buf_;
+}
+
+MemBuf::MemBuf(CopyBufferOp /* op */, const void* buf, std::size_t size,
+               std::size_t headroom, std::size_t min_tailroom)
+    : MemBuf(CREATE, headroom + size + min_tailroom) {
+  advance(headroom);
+  if (size > 0) {
+    assert(buf != nullptr);
+    memcpy(writableData(), buf, size);
+    append(size);
+  }
+}
+
+unique_ptr<MemBuf> MemBuf::create(std::size_t capacity) {
+  // For smaller-sized buffers, allocate the MemBuf, SharedInfo, and the buffer
+  // all with a single allocation.
+  //
+  // We don't do this for larger buffers since it can be wasteful if the user
+  // needs to reallocate the buffer but keeps using the same MemBuf object.
+  // In this case we can't free the data space until the MemBuf is also
+  // destroyed.  Callers can explicitly call createCombined() or
+  // createSeparate() if they know their use case better, and know if they are
+  // likely to reallocate the buffer later.
+  if (capacity <= kDefaultCombinedBufSize) {
+    return createCombined(capacity);
+  }
+  return createSeparate(capacity);
+}
+
+unique_ptr<MemBuf> MemBuf::createCombined(std::size_t capacity) {
+  // To save a memory allocation, allocate space for the MemBuf object, the
+  // SharedInfo struct, and the data itself all with a single call to malloc().
+  size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity;
+  size_t mallocSize = requiredStorage;
+  auto* storage = static_cast<HeapFullStorage*>(malloc(mallocSize));
+
+  new (&storage->hs.prefix) HeapPrefix(kMemBufInUse | kDataInUse);
+  new (&storage->shared) SharedInfo(freeInternalBuf, storage);
+
+  uint8_t* bufAddr = reinterpret_cast<uint8_t*>(&storage->align);
+  uint8_t* storageEnd = reinterpret_cast<uint8_t*>(storage) + mallocSize;
+  size_t actualCapacity = size_t(storageEnd - bufAddr);
+  unique_ptr<MemBuf> ret(new (&storage->hs.buf) MemBuf(
+      InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared),
+      bufAddr, actualCapacity, bufAddr, 0));
+  return ret;
+}
+
+unique_ptr<MemBuf> MemBuf::createSeparate(std::size_t capacity) {
+  return std::make_unique<MemBuf>(CREATE, capacity);
+}
+
+unique_ptr<MemBuf> MemBuf::createChain(size_t totalCapacity,
+                                       std::size_t maxBufCapacity) {
+  unique_ptr<MemBuf> out =
+      create(std::min(totalCapacity, size_t(maxBufCapacity)));
+  size_t allocatedCapacity = out->capacity();
+
+  while (allocatedCapacity < totalCapacity) {
+    unique_ptr<MemBuf> newBuf = create(
+        std::min(totalCapacity - allocatedCapacity, size_t(maxBufCapacity)));
+    allocatedCapacity += newBuf->capacity();
+    out->prependChain(std::move(newBuf));
+  }
+
+  return out;
+}
+
+MemBuf::MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity,
+               std::size_t length, FreeFunction freeFn, void* userData,
+               bool freeOnError)
+    : next_(this),
+      prev_(this),
+      data_(static_cast<uint8_t*>(buf)),
+      buf_(static_cast<uint8_t*>(buf)),
+      length_(length),
+      capacity_(capacity),
+      flags_and_shared_info_(
+          packFlagsAndSharedInfo(flag_free_shared_info, nullptr)) {
+  try {
+    setSharedInfo(new SharedInfo(freeFn, userData));
+  } catch (...) {
+    takeOwnershipError(freeOnError, buf, freeFn, userData);
+    throw;
+  }
+}
+
+unique_ptr<MemBuf> MemBuf::takeOwnership(void* buf, std::size_t capacity,
+                                         std::size_t length,
+                                         FreeFunction freeFn, void* userData,
+                                         bool freeOnError) {
+  try {
+    // TODO: We could allocate the MemBuf object and SharedInfo all in a single
+    // memory allocation.  We could use the existing HeapStorage class, and
+    // define a new kSharedInfoInUse flag.  We could change our code to call
+    // releaseStorage(flag_free_shared_info) when this flag_free_shared_info,
+    // rather than directly calling delete.
+    //
+    // Note that we always pass freeOnError as false to the constructor.
+    // If the constructor throws we'll handle it below.  (We have to handle
+    // allocation failures from std::make_unique too.)
+    return std::make_unique<MemBuf>(TAKE_OWNERSHIP, buf, capacity, length,
+                                    freeFn, userData, false);
+  } catch (...) {
+    takeOwnershipError(freeOnError, buf, freeFn, userData);
+    throw;
+  }
+}
+
+MemBuf::MemBuf(WrapBufferOp, const void* buf, std::size_t capacity) noexcept
+    : MemBuf(InternalConstructor(), 0,
+             // We cast away the const-ness of the buffer here.
+             // This is okay since MemBuf users must use unshare() to create a
+             // copy of this buffer before writing to the buffer.
+             static_cast<uint8_t*>(const_cast<void*>(buf)), capacity,
+             static_cast<uint8_t*>(const_cast<void*>(buf)), capacity) {}
+
+unique_ptr<MemBuf> MemBuf::wrapBuffer(const void* buf, std::size_t capacity) {
+  return std::make_unique<MemBuf>(WRAP_BUFFER, buf, capacity);
+}
+
+MemBuf MemBuf::wrapBufferAsValue(const void* buf,
+                                 std::size_t capacity) noexcept {
+  return MemBuf(WrapBufferOp::WRAP_BUFFER, buf, capacity);
+}
+
+MemBuf::MemBuf() noexcept {}
+
+MemBuf::MemBuf(MemBuf&& other) noexcept
+    : data_(other.data_),
+      buf_(other.buf_),
+      length_(other.length_),
+      capacity_(other.capacity_),
+      flags_and_shared_info_(other.flags_and_shared_info_) {
+  // Reset other so it is a clean state to be destroyed.
+  other.data_ = nullptr;
+  other.buf_ = nullptr;
+  other.length_ = 0;
+  other.capacity_ = 0;
+  other.flags_and_shared_info_ = 0;
+
+  // If other was part of the chain, assume ownership of the rest of its chain.
+  // (It's only valid to perform move assignment on the head of a chain.)
+  if (other.next_ != &other) {
+    next_ = other.next_;
+    next_->prev_ = this;
+    other.next_ = &other;
+
+    prev_ = other.prev_;
+    prev_->next_ = this;
+    other.prev_ = &other;
+  }
+}
+
+MemBuf::MemBuf(const MemBuf& other) { *this = other.cloneAsValue(); }
+
+MemBuf::MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
+               std::size_t capacity, uint8_t* data, std::size_t length) noexcept
+    : next_(this),
+      prev_(this),
+      data_(data),
+      buf_(buf),
+      length_(length),
+      capacity_(capacity),
+      flags_and_shared_info_(flagsAndSharedInfo) {
+  assert(data >= buf);
+  assert(data + length <= buf + capacity);
+}
+
+MemBuf::~MemBuf() {
+  // Destroying an MemBuf destroys the entire chain.
+  // Users of MemBuf should only explicitly delete the head of any chain.
+  // The other elements in the chain will be automatically destroyed.
+  while (next_ != this) {
+    // Since unlink() returns unique_ptr() and we don't store it,
+    // it will automatically delete the unlinked element.
+    (void)next_->unlink();
+  }
+
+  decrementRefcount();
+}
+
+MemBuf& MemBuf::operator=(MemBuf&& other) noexcept {
+  if (this == &other) {
+    return *this;
+  }
+
+  // If we are part of a chain, delete the rest of the chain.
+  while (next_ != this) {
+    // Since unlink() returns unique_ptr() and we don't store it,
+    // it will automatically delete the unlinked element.
+    (void)next_->unlink();
+  }
+
+  // Decrement our refcount on the current buffer
+  decrementRefcount();
+
+  // Take ownership of the other buffer's data
+  data_ = other.data_;
+  buf_ = other.buf_;
+  length_ = other.length_;
+  capacity_ = other.capacity_;
+  flags_and_shared_info_ = other.flags_and_shared_info_;
+  // Reset other so it is a clean state to be destroyed.
+  other.data_ = nullptr;
+  other.buf_ = nullptr;
+  other.length_ = 0;
+  other.capacity_ = 0;
+  other.flags_and_shared_info_ = 0;
+
+  // If other was part of the chain, assume ownership of the rest of its chain.
+  // (It's only valid to perform move assignment on the head of a chain.)
+  if (other.next_ != &other) {
+    next_ = other.next_;
+    next_->prev_ = this;
+    other.next_ = &other;
+
+    prev_ = other.prev_;
+    prev_->next_ = this;
+    other.prev_ = &other;
+  }
+
+  return *this;
+}
+
+MemBuf& MemBuf::operator=(const MemBuf& other) {
+  if (this != &other) {
+    *this = MemBuf(other);
+  }
+  return *this;
+}
+
+bool MemBuf::empty() const {
+  const MemBuf* current = this;
+  do {
+    if (current->length() != 0) {
+      return false;
+    }
+    current = current->next_;
+  } while (current != this);
+  return true;
+}
+
+size_t MemBuf::countChainElements() const {
+  size_t numElements = 1;
+  for (MemBuf* current = next_; current != this; current = current->next_) {
+    ++numElements;
+  }
+  return numElements;
+}
+
+std::size_t MemBuf::computeChainDataLength() const {
+  std::size_t fullLength = length_;
+  for (MemBuf* current = next_; current != this; current = current->next_) {
+    fullLength += current->length_;
+  }
+  return fullLength;
+}
+
+void MemBuf::prependChain(unique_ptr<MemBuf>&& iobuf) {
+  // Take ownership of the specified MemBuf
+  MemBuf* other = iobuf.release();
+
+  // Remember the pointer to the tail of the other chain
+  MemBuf* otherTail = other->prev_;
+
+  // Hook up prev_->next_ to point at the start of the other chain,
+  // and other->prev_ to point at prev_
+  prev_->next_ = other;
+  other->prev_ = prev_;
+
+  // Hook up otherTail->next_ to point at us,
+  // and prev_ to point back at otherTail,
+  otherTail->next_ = this;
+  prev_ = otherTail;
+}
+
+unique_ptr<MemBuf> MemBuf::clone() const {
+  return std::make_unique<MemBuf>(cloneAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneOne() const {
+  return std::make_unique<MemBuf>(cloneOneAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneCoalesced() const {
+  return std::make_unique<MemBuf>(cloneCoalescedAsValue());
+}
+
+unique_ptr<MemBuf> MemBuf::cloneCoalescedWithHeadroomTailroom(
+    std::size_t new_headroom, std::size_t new_tailroom) const {
+  return std::make_unique<MemBuf>(
+      cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom));
+}
+
+MemBuf MemBuf::cloneAsValue() const {
+  auto tmp = cloneOneAsValue();
+
+  for (MemBuf* current = next_; current != this; current = current->next_) {
+    tmp.prependChain(current->cloneOne());
+  }
+
+  return tmp;
+}
+
+MemBuf MemBuf::cloneOneAsValue() const {
+  if (SharedInfo* info = sharedInfo()) {
+    setFlags(flag_maybe_shared);
+    info->refcount.fetch_add(1, std::memory_order_acq_rel);
+  }
+  return MemBuf(InternalConstructor(), flags_and_shared_info_, buf_, capacity_,
+                data_, length_);
+}
+
+MemBuf MemBuf::cloneCoalescedAsValue() const {
+  const std::size_t new_headroom = headroom();
+  const std::size_t new_tailroom = prev()->tailroom();
+  return cloneCoalescedAsValueWithHeadroomTailroom(new_headroom, new_tailroom);
+}
+
+MemBuf MemBuf::cloneCoalescedAsValueWithHeadroomTailroom(
+    std::size_t new_headroom, std::size_t new_tailroom) const {
+  if (!isChained()) {
+    return cloneOneAsValue();
+  }
+  // Coalesce into newBuf
+  const std::size_t new_length = computeChainDataLength();
+  const std::size_t new_capacity = new_length + new_headroom + new_tailroom;
+  MemBuf newBuf{CREATE, new_capacity};
+  newBuf.advance(new_headroom);
+
+  auto current = this;
+  do {
+    if (current->length() > 0) {
+      memcpy(newBuf.writableTail(), current->data(), current->length());
+      newBuf.append(current->length());
+    }
+    current = current->next();
+  } while (current != this);
+
+  return newBuf;
+}
+
+void MemBuf::unshareOneSlow() {
+  // Allocate a new buffer for the data
+  uint8_t* buf;
+  SharedInfo* sharedInfo;
+  std::size_t actualCapacity;
+  allocExtBuffer(capacity_, &buf, &sharedInfo, &actualCapacity);
+
+  // Copy the data
+  // Maintain the same amount of headroom.  Since we maintained the same
+  // minimum capacity we also maintain at least the same amount of tailroom.
+  std::size_t headlen = headroom();
+  if (length_ > 0) {
+    assert(data_ != nullptr);
+    memcpy(buf + headlen, data_, length_);
+  }
+
+  // Release our reference on the old buffer
+  decrementRefcount();
+  // Make sure flag_maybe_shared and flag_free_shared_info are all cleared.
+  setFlagsAndSharedInfo(0, sharedInfo);
+
+  // Update the buffer pointers to point to the new buffer
+  data_ = buf + headlen;
+  buf_ = buf;
+}
+
+void MemBuf::unshareChained() {
+  // unshareChained() should only be called if we are part of a chain of
+  // multiple MemBufs.  The caller should have already verified this.
+  assert(isChained());
+
+  MemBuf* current = this;
+  while (true) {
+    if (current->isSharedOne()) {
+      // we have to unshare
+      break;
+    }
+
+    current = current->next_;
+    if (current == this) {
+      // None of the MemBufs in the chain are shared,
+      // so return without doing anything
+      return;
+    }
+  }
+
+  // We have to unshare.  Let coalesceSlow() do the work.
+  coalesceSlow();
+}
+
+void MemBuf::markExternallyShared() {
+  MemBuf* current = this;
+  do {
+    current->markExternallySharedOne();
+    current = current->next_;
+  } while (current != this);
+}
+
+void MemBuf::makeManagedChained() {
+  assert(isChained());
+
+  MemBuf* current = this;
+  while (true) {
+    current->makeManagedOne();
+    current = current->next_;
+    if (current == this) {
+      break;
+    }
+  }
+}
+
+void MemBuf::coalesceSlow() {
+  // coalesceSlow() should only be called if we are part of a chain of multiple
+  // MemBufs.  The caller should have already verified this.
+
+  // Compute the length of the entire chain
+  std::size_t new_length = 0;
+  MemBuf* end = this;
+  do {
+    new_length += end->length_;
+    end = end->next_;
+  } while (end != this);
+
+  coalesceAndReallocate(new_length, end);
+  // We should be only element left in the chain now
+}
+
+void MemBuf::coalesceSlow(size_t max_length) {
+  // coalesceSlow() should only be called if we are part of a chain of multiple
+  // MemBufs.  The caller should have already verified this.
+
+  // Compute the length of the entire chain
+  std::size_t new_length = 0;
+  MemBuf* end = this;
+  while (true) {
+    new_length += end->length_;
+    end = end->next_;
+    if (new_length >= max_length) {
+      break;
+    }
+    if (end == this) {
+      throw std::overflow_error(
+          "attempted to coalesce more data than "
+          "available");
+    }
+  }
+
+  coalesceAndReallocate(new_length, end);
+  // We should have the requested length now
+}
+
+void MemBuf::coalesceAndReallocate(size_t new_headroom, size_t new_length,
+                                   MemBuf* end, size_t new_tailroom) {
+  std::size_t new_capacity = new_length + new_headroom + new_tailroom;
+
+  // Allocate space for the coalesced buffer.
+  // We always convert to an external buffer, even if we happened to be an
+  // internal buffer before.
+  uint8_t* newBuf;
+  SharedInfo* newInfo;
+  std::size_t actualCapacity;
+  allocExtBuffer(new_capacity, &newBuf, &newInfo, &actualCapacity);
+
+  // Copy the data into the new buffer
+  uint8_t* new_data = newBuf + new_headroom;
+  uint8_t* p = new_data;
+  MemBuf* current = this;
+  size_t remaining = new_length;
+  do {
+    if (current->length_ > 0) {
+      assert(current->length_ <= remaining);
+      assert(current->data_ != nullptr);
+      remaining -= current->length_;
+      memcpy(p, current->data_, current->length_);
+      p += current->length_;
+    }
+    current = current->next_;
+  } while (current != end);
+  assert(remaining == 0);
+
+  // Point at the new buffer
+  decrementRefcount();
+
+  // Make sure flag_maybe_shared and flag_free_shared_info are all cleared.
+  setFlagsAndSharedInfo(0, newInfo);
+
+  capacity_ = actualCapacity;
+  buf_ = newBuf;
+  data_ = new_data;
+  length_ = new_length;
+
+  // Separate from the rest of our chain.
+  // Since we don't store the unique_ptr returned by separateChain(),
+  // this will immediately delete the returned subchain.
+  if (isChained()) {
+    (void)separateChain(next_, current->prev_);
+  }
+}
+
+void MemBuf::decrementRefcount() {
+  // Externally owned buffers don't have a SharedInfo object and aren't managed
+  // by the reference count
+  SharedInfo* info = sharedInfo();
+  if (!info) {
+    return;
+  }
+
+  // Decrement the refcount
+  uint32_t newcnt = info->refcount.fetch_sub(1, std::memory_order_acq_rel);
+  // Note that fetch_sub() returns the value before we decremented.
+  // If it is 1, we were the only remaining user; if it is greater there are
+  // still other users.
+  if (newcnt > 1) {
+    return;
+  }
+
+  // We were the last user.  Free the buffer
+  freeExtBuffer();
+
+  // Free the SharedInfo if it was allocated separately.
+  //
+  // This is only used by takeOwnership().
+  //
+  // To avoid this special case handling in decrementRefcount(), we could have
+  // takeOwnership() set a custom freeFn() that calls the user's free function
+  // then frees the SharedInfo object.  (This would require that
+  // takeOwnership() store the user's free function with its allocated
+  // SharedInfo object.)  However, handling this specially with a flag seems
+  // like it shouldn't be problematic.
+  if (flags() & flag_free_shared_info) {
+    delete sharedInfo();
+  }
+}
+
+void MemBuf::reserveSlow(std::size_t min_headroom, std::size_t min_tailroom) {
+  size_t new_capacity = (size_t)length_ + min_headroom + min_tailroom;
+
+  // // reserveSlow() is dangerous if anyone else is sharing the buffer, as we
+  // may
+  // // reallocate and free the original buffer.  It should only ever be called
+  // if
+  // // we are the only user of the buffer.
+
+  // We'll need to reallocate the buffer.
+  // There are a few options.
+  // - If we have enough total room, move the data around in the buffer
+  //   and adjust the data_ pointer.
+  // - If we're using an internal buffer, we'll switch to an external
+  //   buffer with enough headroom and tailroom.
+  // - If we have enough headroom (headroom() >= min_headroom) but not too much
+  //   (so we don't waste memory), we can try:
+  //   - If we don't have too much to copy, we'll use realloc() (note that
+  //   realloc might have to copy
+  //     headroom + data + tailroom)
+  // - Otherwise, bite the bullet and reallocate.
+  if (headroom() + tailroom() >= min_headroom + min_tailroom) {
+    uint8_t* new_data = writableBuffer() + min_headroom;
+    std::memmove(new_data, data_, length_);
+    data_ = new_data;
+    return;
+  }
+
+  size_t new_allocated_capacity = 0;
+  uint8_t* new_buffer = nullptr;
+  std::size_t new_headroom = 0;
+  std::size_t old_headroom = headroom();
+
+  // If we have a buffer allocated with malloc and we just need more tailroom,
+  // try to use realloc()/xallocx() to grow the buffer in place.
+  SharedInfo* info = sharedInfo();
+  if (info && (info->freeFn == nullptr) && length_ != 0 &&
+      old_headroom >= min_headroom) {
+    size_t head_slack = old_headroom - min_headroom;
+    new_allocated_capacity = goodExtBufferSize(new_capacity + head_slack);
+
+    size_t copySlack = capacity() - length_;
+    if (copySlack * 2 <= length_) {
+      void* p = realloc(buf_, new_allocated_capacity);
+      if (TRANSPORT_EXPECT_FALSE(p == nullptr)) {
+        throw std::bad_alloc();
+      }
+      new_buffer = static_cast<uint8_t*>(p);
+      new_headroom = old_headroom;
+    }
+  }
+
+  // None of the previous reallocation strategies worked (or we're using
+  // an internal buffer).  malloc/copy/free.
+  if (new_buffer == nullptr) {
+    new_allocated_capacity = goodExtBufferSize(new_capacity);
+    new_buffer = static_cast<uint8_t*>(malloc(new_allocated_capacity));
+    if (length_ > 0) {
+      assert(data_ != nullptr);
+      memcpy(new_buffer + min_headroom, data_, length_);
+    }
+    if (sharedInfo()) {
+      freeExtBuffer();
+    }
+    new_headroom = min_headroom;
+  }
+
+  std::size_t cap;
+  initExtBuffer(new_buffer, new_allocated_capacity, &info, &cap);
+
+  if (flags() & flag_free_shared_info) {
+    delete sharedInfo();
+  }
+
+  setFlagsAndSharedInfo(0, info);
+  capacity_ = cap;
+  buf_ = new_buffer;
+  data_ = new_buffer + new_headroom;
+  // length_ is unchanged
+}
+
+void MemBuf::freeExtBuffer() {
+  SharedInfo* info = sharedInfo();
+
+  if (info->freeFn) {
+    try {
+      info->freeFn(buf_, info->userData);
+    } catch (...) {
+      // The user's free function should never throw.  Otherwise we might
+      // throw from the MemBuf destructor.  Other code paths like coalesce()
+      // also assume that decrementRefcount() cannot throw.
+      abort();
+    }
+  } else {
+    free(buf_);
+  }
+}
+
+void MemBuf::allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
+                            SharedInfo** infoReturn,
+                            std::size_t* capacityReturn) {
+  size_t mallocSize = goodExtBufferSize(minCapacity);
+  uint8_t* buf = static_cast<uint8_t*>(malloc(mallocSize));
+  initExtBuffer(buf, mallocSize, infoReturn, capacityReturn);
+  *bufReturn = buf;
+}
+
+size_t MemBuf::goodExtBufferSize(std::size_t minCapacity) {
+  // Determine how much space we should allocate.  We'll store the SharedInfo
+  // for the external buffer just after the buffer itself.  (We store it just
+  // after the buffer rather than just before so that the code can still just
+  // use free(buf_) to free the buffer.)
+  size_t minSize = static_cast<size_t>(minCapacity) + sizeof(SharedInfo);
+  // Add room for padding so that the SharedInfo will be aligned on an 8-byte
+  // boundary.
+  minSize = (minSize + 7) & ~7;
+
+  // Use goodMallocSize() to bump up the capacity to a decent size to request
+  // from malloc, so we can use all of the space that malloc will probably give
+  // us anyway.
+  return minSize;
+}
+
+void MemBuf::initExtBuffer(uint8_t* buf, size_t mallocSize,
+                           SharedInfo** infoReturn,
+                           std::size_t* capacityReturn) {
+  // Find the SharedInfo storage at the end of the buffer
+  // and construct the SharedInfo.
+  uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo);
+  SharedInfo* sharedInfo = new (infoStart) SharedInfo;
+
+  *capacityReturn = std::size_t(infoStart - buf);
+  *infoReturn = sharedInfo;
+}
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/membuf.h b/libtransport/src/hicn/transport/utils/membuf.h
new file mode 100755 (executable)
index 0000000..944237e
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2013-present Facebook, 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.
+ */
+
+/*
+ * The code in this file if adapated from the IOBuf of folly:
+ * https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/branch_prediction.h>
+
+#include <atomic>
+#include <cassert>
+#include <cinttypes>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <type_traits>
+#include <vector>
+
+// Ignore shadowing warnings within this file, so includers can use -Wshadow.
+TRANSPORT_GNU_DISABLE_WARNING("-Wshadow")
+
+namespace utils {
+
+class MemBuf {
+ public:
+  enum CreateOp { CREATE };
+  enum WrapBufferOp { WRAP_BUFFER };
+  enum TakeOwnershipOp { TAKE_OWNERSHIP };
+  enum CopyBufferOp { COPY_BUFFER };
+
+  typedef void (*FreeFunction)(void* buf, void* userData);
+
+  static std::unique_ptr<MemBuf> create(std::size_t capacity);
+  MemBuf(CreateOp, std::size_t capacity);
+
+  /**
+   * Create a new MemBuf, using a single memory allocation to allocate space
+   * for both the MemBuf object and the data storage space.
+   *
+   * This saves one memory allocation.  However, it can be wasteful if you
+   * later need to grow the buffer using reserve().  If the buffer needs to be
+   * reallocated, the space originally allocated will not be freed() until the
+   * MemBuf object itself is also freed.  (It can also be slightly wasteful in
+   * some cases where you clone this MemBuf and then free the original MemBuf.)
+   */
+  static std::unique_ptr<MemBuf> createCombined(std::size_t capacity);
+
+  /**
+   * Create a new IOBuf, using separate memory allocations for the IOBuf object
+   * for the IOBuf and the data storage space.
+   *
+   * This requires two memory allocations, but saves space in the long run
+   * if you know that you will need to reallocate the data buffer later.
+   */
+  static std::unique_ptr<MemBuf> createSeparate(std::size_t capacity);
+
+  /**
+   * Allocate a new MemBuf chain with the requested total capacity, allocating
+   * no more than maxBufCapacity to each buffer.
+   */
+  static std::unique_ptr<MemBuf> createChain(size_t totalCapacity,
+                                             std::size_t maxBufCapacity);
+
+  static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+                                               FreeFunction freeFn = nullptr,
+                                               void* userData = nullptr,
+                                               bool freeOnError = true) {
+    return takeOwnership(buf, capacity, capacity, freeFn, userData,
+                         freeOnError);
+  }
+
+  MemBuf(TakeOwnershipOp op, void* buf, std::size_t capacity,
+         FreeFunction freeFn = nullptr, void* userData = nullptr,
+         bool freeOnError = true)
+      : MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {}
+
+  static std::unique_ptr<MemBuf> takeOwnership(void* buf, std::size_t capacity,
+                                               std::size_t length,
+                                               FreeFunction freeFn = nullptr,
+                                               void* userData = nullptr,
+                                               bool freeOnError = true);
+
+  MemBuf(TakeOwnershipOp, void* buf, std::size_t capacity, std::size_t length,
+         FreeFunction freeFn = nullptr, void* userData = nullptr,
+         bool freeOnError = true);
+
+  static std::unique_ptr<MemBuf> wrapBuffer(const void* buf,
+                                            std::size_t capacity);
+
+  static MemBuf wrapBufferAsValue(const void* buf,
+                                  std::size_t capacity) noexcept;
+
+  MemBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept;
+
+  /**
+   * Convenience function to create a new MemBuf object that copies data from a
+   * user-supplied buffer, optionally allocating a given amount of
+   * headroom and tailroom.
+   */
+  static std::unique_ptr<MemBuf> copyBuffer(const void* buf, std::size_t size,
+                                            std::size_t headroom = 0,
+                                            std::size_t minTailroom = 0);
+
+  MemBuf(CopyBufferOp op, const void* buf, std::size_t size,
+         std::size_t headroom = 0, std::size_t minTailroom = 0);
+
+  /**
+   * Convenience function to free a chain of MemBufs held by a unique_ptr.
+   */
+  static void destroy(std::unique_ptr<MemBuf>&& data) {
+    auto destroyer = std::move(data);
+  }
+
+  ~MemBuf();
+
+  bool empty() const;
+
+  const uint8_t* data() const { return data_; }
+
+  uint8_t* writableData() { return data_; }
+
+  const uint8_t* tail() const { return data_ + length_; }
+
+  uint8_t* writableTail() { return data_ + length_; }
+
+  std::size_t length() const { return length_; }
+
+  std::size_t headroom() const { return std::size_t(data_ - buffer()); }
+
+  std::size_t tailroom() const { return std::size_t(bufferEnd() - tail()); }
+
+  const uint8_t* buffer() const { return buf_; }
+
+  uint8_t* writableBuffer() { return buf_; }
+
+  const uint8_t* bufferEnd() const { return buf_ + capacity_; }
+
+  std::size_t capacity() const { return capacity_; }
+
+  MemBuf* next() { return next_; }
+
+  const MemBuf* next() const { return next_; }
+
+  MemBuf* prev() { return prev_; }
+
+  const MemBuf* prev() const { return prev_; }
+
+  /**
+   * Shift the data forwards in the buffer.
+   *
+   * This shifts the data pointer forwards in the buffer to increase the
+   * headroom.  This is commonly used to increase the headroom in a newly
+   * allocated buffer.
+   *
+   * The caller is responsible for ensuring that there is sufficient
+   * tailroom in the buffer before calling advance().
+   *
+   * If there is a non-zero data length, advance() will use memmove() to shift
+   * the data forwards in the buffer.  In this case, the caller is responsible
+   * for making sure the buffer is unshared, so it will not affect other MemBufs
+   * that may be sharing the same underlying buffer.
+   */
+  void advance(std::size_t amount) {
+    // In debug builds, assert if there is a problem.
+    assert(amount <= tailroom());
+
+    if (length_ > 0) {
+      memmove(data_ + amount, data_, length_);
+    }
+    data_ += amount;
+  }
+
+  /**
+   * Shift the data backwards in the buffer.
+   *
+   * The caller is responsible for ensuring that there is sufficient headroom
+   * in the buffer before calling retreat().
+   *
+   * If there is a non-zero data length, retreat() will use memmove() to shift
+   * the data backwards in the buffer.  In this case, the caller is responsible
+   * for making sure the buffer is unshared, so it will not affect other MemBufs
+   * that may be sharing the same underlying buffer.
+   */
+  void retreat(std::size_t amount) {
+    // In debug builds, assert if there is a problem.
+    assert(amount <= headroom());
+
+    if (length_ > 0) {
+      memmove(data_ - amount, data_, length_);
+    }
+    data_ -= amount;
+  }
+
+  void prepend(std::size_t amount) {
+    data_ -= amount;
+    length_ += amount;
+  }
+
+  void append(std::size_t amount) { length_ += amount; }
+
+  void trimStart(std::size_t amount) {
+    data_ += amount;
+    length_ -= amount;
+  }
+
+  void trimEnd(std::size_t amount) { length_ -= amount; }
+
+  void clear() {
+    data_ = writableBuffer();
+    length_ = 0;
+  }
+
+  void reserve(std::size_t minHeadroom, std::size_t minTailroom) {
+    // Maybe we don't need to do anything.
+    if (headroom() >= minHeadroom && tailroom() >= minTailroom) {
+      return;
+    }
+    // If the buffer is empty but we have enough total room (head + tail),
+    // move the data_ pointer around.
+    if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) {
+      data_ = writableBuffer() + minHeadroom;
+      return;
+    }
+    // Bah, we have to do actual work.
+    reserveSlow(minHeadroom, minTailroom);
+  }
+
+  bool isChained() const {
+    assert((next_ == this) == (prev_ == this));
+    return next_ != this;
+  }
+
+  size_t countChainElements() const;
+
+  std::size_t computeChainDataLength() const;
+
+  void prependChain(std::unique_ptr<MemBuf>&& iobuf);
+
+  void appendChain(std::unique_ptr<MemBuf>&& iobuf) {
+    // Just use prependChain() on the next element in our chain
+    next_->prependChain(std::move(iobuf));
+  }
+
+  std::unique_ptr<MemBuf> unlink() {
+    next_->prev_ = prev_;
+    prev_->next_ = next_;
+    prev_ = this;
+    next_ = this;
+    return std::unique_ptr<MemBuf>(this);
+  }
+
+  /**
+   * Remove this MemBuf from its current chain and return a unique_ptr to
+   * the MemBuf that formerly followed it in the chain.
+   */
+  std::unique_ptr<MemBuf> pop() {
+    MemBuf* next = next_;
+    next_->prev_ = prev_;
+    prev_->next_ = next_;
+    prev_ = this;
+    next_ = this;
+    return std::unique_ptr<MemBuf>((next == this) ? nullptr : next);
+  }
+
+  /**
+   * Remove a subchain from this chain.
+   *
+   * Remove the subchain starting at head and ending at tail from this chain.
+   *
+   * Returns a unique_ptr pointing to head.  (In other words, ownership of the
+   * head of the subchain is transferred to the caller.)  If the caller ignores
+   * the return value and lets the unique_ptr be destroyed, the subchain will
+   * be immediately destroyed.
+   *
+   * The subchain referenced by the specified head and tail must be part of the
+   * same chain as the current MemBuf, but must not contain the current MemBuf.
+   * However, the specified head and tail may be equal to each other (i.e.,
+   * they may be a subchain of length 1).
+   */
+  std::unique_ptr<MemBuf> separateChain(MemBuf* head, MemBuf* tail) {
+    assert(head != this);
+    assert(tail != this);
+
+    head->prev_->next_ = tail->next_;
+    tail->next_->prev_ = head->prev_;
+
+    head->prev_ = tail;
+    tail->next_ = head;
+
+    return std::unique_ptr<MemBuf>(head);
+  }
+
+  /**
+   * Return true if at least one of the MemBufs in this chain are shared,
+   * or false if all of the MemBufs point to unique buffers.
+   *
+   * Use isSharedOne() to only check this MemBuf rather than the entire chain.
+   */
+  bool isShared() const {
+    const MemBuf* current = this;
+    while (true) {
+      if (current->isSharedOne()) {
+        return true;
+      }
+      current = current->next_;
+      if (current == this) {
+        return false;
+      }
+    }
+  }
+
+  /**
+   * Return true if all MemBufs in this chain are managed by the usual
+   * refcounting mechanism (and so the lifetime of the underlying memory
+   * can be extended by clone()).
+   */
+  bool isManaged() const {
+    const MemBuf* current = this;
+    while (true) {
+      if (!current->isManagedOne()) {
+        return false;
+      }
+      current = current->next_;
+      if (current == this) {
+        return true;
+      }
+    }
+  }
+
+  /**
+   * Return true if this MemBuf is managed by the usual refcounting mechanism
+   * (and so the lifetime of the underlying memory can be extended by
+   * cloneOne()).
+   */
+  bool isManagedOne() const { return sharedInfo(); }
+
+  /**
+   * Return true if other MemBufs are also pointing to the buffer used by this
+   * MemBuf, and false otherwise.
+   *
+   * If this MemBuf points at a buffer owned by another (non-MemBuf) part of the
+   * code (i.e., if the MemBuf was created using wrapBuffer(), or was cloned
+   * from such an MemBuf), it is always considered shared.
+   *
+   * This only checks the current MemBuf, and not other MemBufs in the chain.
+   */
+  bool isSharedOne() const {
+    // If this is a user-owned buffer, it is always considered shared
+    if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) {
+      return true;
+    }
+
+    if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) {
+      return true;
+    }
+
+    if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) {
+      return false;
+    }
+
+    // flag_maybe_shared is set, so we need to check the reference count.
+    // (Checking the reference count requires an atomic operation, which is why
+    // we prefer to only check flag_maybe_shared if possible.)
+    bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
+    if (!shared) {
+      // we're the last one left
+      clearFlags(flag_maybe_shared);
+    }
+    return shared;
+  }
+
+  /**
+   * Ensure that this MemBuf has a unique buffer that is not shared by other
+   * MemBufs.
+   *
+   * unshare() operates on an entire chain of MemBuf objects.  If the chain is
+   * shared, it may also coalesce the chain when making it unique.  If the
+   * chain is coalesced, subsequent MemBuf objects in the current chain will be
+   * automatically deleted.
+   *
+   * Note that buffers owned by other (non-MemBuf) users are automatically
+   * considered shared.
+   *
+   * Throws std::bad_alloc on error.  On error the MemBuf chain will be
+   * unmodified.
+   *
+   * Currently unshare may also throw std::overflow_error if it tries to
+   * coalesce.  (TODO: In the future it would be nice if unshare() were smart
+   * enough not to coalesce the entire buffer if the data is too large.
+   * However, in practice this seems unlikely to become an issue.)
+   */
+  void unshare() {
+    if (isChained()) {
+      unshareChained();
+    } else {
+      unshareOne();
+    }
+  }
+
+  /**
+   * Ensure that this MemBuf has a unique buffer that is not shared by other
+   * MemBufs.
+   *
+   * unshareOne() operates on a single MemBuf object.  This MemBuf will have a
+   * unique buffer after unshareOne() returns, but other MemBufs in the chain
+   * may still be shared after unshareOne() returns.
+   *
+   * Throws std::bad_alloc on error.  On error the MemBuf will be unmodified.
+   */
+  void unshareOne() {
+    if (isSharedOne()) {
+      unshareOneSlow();
+    }
+  }
+
+  /**
+   * Mark the underlying buffers in this chain as shared with external memory
+   * management mechanism. This will make isShared() always returns true.
+   *
+   * This function is not thread-safe, and only safe to call immediately after
+   * creating an MemBuf, before it has been shared with other threads.
+   */
+  void markExternallyShared();
+
+  /**
+   * Mark the underlying buffer that this MemBuf refers to as shared with
+   * external memory management mechanism. This will make isSharedOne() always
+   * returns true.
+   *
+   * This function is not thread-safe, and only safe to call immediately after
+   * creating an MemBuf, before it has been shared with other threads.
+   */
+  void markExternallySharedOne() {
+    SharedInfo* info = sharedInfo();
+    if (info) {
+      info->externallyShared = true;
+    }
+  }
+
+  /**
+   * Ensure that the memory that MemBufs in this chain refer to will continue to
+   * be allocated for as long as the MemBufs of the chain (or any clone()s
+   * created from this point onwards) is alive.
+   *
+   * This only has an effect for user-owned buffers (created with the
+   * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+   * those buffers are unshared.
+   */
+  void makeManaged() {
+    if (isChained()) {
+      makeManagedChained();
+    } else {
+      makeManagedOne();
+    }
+  }
+
+  /**
+   * Ensure that the memory that this MemBuf refers to will continue to be
+   * allocated for as long as this MemBuf (or any clone()s created from this
+   * point onwards) is alive.
+   *
+   * This only has an effect for user-owned buffers (created with the
+   * WRAP_BUFFER constructor or wrapBuffer factory function), in which case
+   * those buffers are unshared.
+   */
+  void makeManagedOne() {
+    if (!isManagedOne()) {
+      // We can call the internal function directly; unmanaged implies shared.
+      unshareOneSlow();
+    }
+  }
+
+  // /**
+  //  * Coalesce this MemBuf chain into a single buffer.
+  //  *
+  //  * This method moves all of the data in this MemBuf chain into a single
+  //  * contiguous buffer, if it is not already in one buffer.  After coalesce()
+  //  * returns, this MemBuf will be a chain of length one.  Other MemBufs in
+  //  the
+  //  * chain will be automatically deleted.
+  //  *
+  //  * After coalescing, the MemBuf will have at least as much headroom as the
+  //  * first MemBuf in the chain, and at least as much tailroom as the last
+  //  MemBuf
+  //  * in the chain.
+  //  *
+  //  * Throws std::bad_alloc on error.  On error the MemBuf chain will be
+  //  * unmodified.
+  //  *
+  //  * Returns ByteRange that points to the data MemBuf stores.
+  //  */
+  // ByteRange coalesce() {
+  //   const std::size_t newHeadroom = headroom();
+  //   const std::size_t newTailroom = prev()->tailroom();
+  //   return coalesceWithHeadroomTailroom(newHeadroom, newTailroom);
+  // }
+
+  // /**
+  //  * This is similar to the coalesce() method, except this allows to set a
+  //  * headroom and tailroom after coalescing.
+  //  *
+  //  * Returns ByteRange that points to the data MemBuf stores.
+  //  */
+  // ByteRange coalesceWithHeadroomTailroom(
+  //     std::size_t newHeadroom,
+  //     std::size_t newTailroom) {
+  //   if (isChained()) {
+  //     coalesceAndReallocate(
+  //         newHeadroom, computeChainDataLength(), this, newTailroom);
+  //   }
+  //   return ByteRange(data_, length_);
+  // }
+
+  /**
+   * Ensure that this chain has at least maxLength bytes available as a
+   * contiguous memory range.
+   *
+   * This method coalesces whole buffers in the chain into this buffer as
+   * necessary until this buffer's length() is at least maxLength.
+   *
+   * After coalescing, the MemBuf will have at least as much headroom as the
+   * first MemBuf in the chain, and at least as much tailroom as the last MemBuf
+   * that was coalesced.
+   *
+   * Throws std::bad_alloc or std::overflow_error on error.  On error the MemBuf
+   * chain will be unmodified.  Throws std::overflow_error if maxLength is
+   * longer than the total chain length.
+   *
+   * Upon return, either enough of the chain was coalesced into a contiguous
+   * region, or the entire chain was coalesced.  That is,
+   * length() >= maxLength || !isChained() is true.
+   */
+  void gather(std::size_t maxLength) {
+    if (!isChained() || length_ >= maxLength) {
+      return;
+    }
+    coalesceSlow(maxLength);
+  }
+
+  /**
+   * Return a new MemBuf chain sharing the same data as this chain.
+   *
+   * The new MemBuf chain will normally point to the same underlying data
+   * buffers as the original chain.  (The one exception to this is if some of
+   * the MemBufs in this chain contain small internal data buffers which cannot
+   * be shared.)
+   */
+  std::unique_ptr<MemBuf> clone() const;
+
+  /**
+   * Similar to clone(). But returns MemBuf by value rather than heap-allocating
+   * it.
+   */
+  MemBuf cloneAsValue() const;
+
+  /**
+   * Return a new MemBuf with the same data as this MemBuf.
+   *
+   * The new MemBuf returned will not be part of a chain (even if this MemBuf is
+   * part of a larger chain).
+   */
+  std::unique_ptr<MemBuf> cloneOne() const;
+
+  /**
+   * Similar to cloneOne(). But returns MemBuf by value rather than
+   * heap-allocating it.
+   */
+  MemBuf cloneOneAsValue() const;
+
+  /**
+   * Return a new unchained MemBuf that may share the same data as this chain.
+   *
+   * If the MemBuf chain is not chained then the new MemBuf will point to the
+   * same underlying data buffer as the original chain. Otherwise, it will clone
+   * and coalesce the MemBuf chain.
+   *
+   * The new MemBuf will have at least as much headroom as the first MemBuf in
+   * the chain, and at least as much tailroom as the last MemBuf in the chain.
+   *
+   * Throws std::bad_alloc on error.
+   */
+  std::unique_ptr<MemBuf> cloneCoalesced() const;
+
+  /**
+   * This is similar to the cloneCoalesced() method, except this allows to set a
+   * headroom and tailroom for the new MemBuf.
+   */
+  std::unique_ptr<MemBuf> cloneCoalescedWithHeadroomTailroom(
+      std::size_t newHeadroom, std::size_t newTailroom) const;
+
+  /**
+   * Similar to cloneCoalesced(). But returns MemBuf by value rather than
+   * heap-allocating it.
+   */
+  MemBuf cloneCoalescedAsValue() const;
+
+  /**
+   * This is similar to the cloneCoalescedAsValue() method, except this allows
+   * to set a headroom and tailroom for the new MemBuf.
+   */
+  MemBuf cloneCoalescedAsValueWithHeadroomTailroom(
+      std::size_t newHeadroom, std::size_t newTailroom) const;
+
+  /**
+   * Similar to Clone(). But use other as the head node. Other nodes in the
+   * chain (if any) will be allocted on heap.
+   */
+  void cloneInto(MemBuf& other) const { other = cloneAsValue(); }
+
+  /**
+   * Similar to CloneOne(). But to fill an existing MemBuf instead of a new
+   * MemBuf.
+   */
+  void cloneOneInto(MemBuf& other) const { other = cloneOneAsValue(); }
+
+  /**
+   * Return an iovector suitable for e.g. writev()
+   *
+   *   auto iov = buf->getIov();
+   *   auto xfer = writev(fd, iov.data(), iov.size());
+   *
+   * Naturally, the returned iovector is invalid if you modify the buffer
+   * chain.
+   */
+  std::vector<struct iovec> getIov() const;
+
+  /**
+   * Update an existing iovec array with the MemBuf data.
+   *
+   * New iovecs will be appended to the existing vector; anything already
+   * present in the vector will be left unchanged.
+   *
+   * Naturally, the returned iovec data will be invalid if you modify the
+   * buffer chain.
+   */
+  void appendToIov(std::vector<struct iovec>* iov) const;
+
+  /**
+   * Fill an iovec array with the MemBuf data.
+   *
+   * Returns the number of iovec filled. If there are more buffer than
+   * iovec, returns 0. This version is suitable to use with stack iovec
+   * arrays.
+   *
+   * Naturally, the filled iovec data will be invalid if you modify the
+   * buffer chain.
+   */
+  size_t fillIov(struct iovec* iov, size_t len) const;
+
+  /**
+   * A helper that wraps a number of iovecs into an MemBuf chain.  If count ==
+   * 0, then a zero length buf is returned.  This function never returns
+   * nullptr.
+   */
+  static std::unique_ptr<MemBuf> wrapIov(const iovec* vec, size_t count);
+
+  /**
+   * A helper that takes ownerships a number of iovecs into an MemBuf chain.  If
+   * count == 0, then a zero length buf is returned.  This function never
+   * returns nullptr.
+   */
+  static std::unique_ptr<MemBuf> takeOwnershipIov(const iovec* vec,
+                                                  size_t count,
+                                                  FreeFunction freeFn = nullptr,
+                                                  void* userData = nullptr,
+                                                  bool freeOnError = true);
+
+  /*
+   * Overridden operator new and delete.
+   * These perform specialized memory management to help support
+   * createCombined(), which allocates MemBuf objects together with the buffer
+   * data.
+   */
+  void* operator new(size_t size);
+  void* operator new(size_t size, void* ptr);
+  void operator delete(void* ptr);
+  void operator delete(void* ptr, void* placement);
+
+  // /**
+  //  * Iteration support: a chain of MemBufs may be iterated through using
+  //  * STL-style iterators over const ByteRanges.  Iterators are only
+  //  invalidated
+  //  * if the MemBuf that they currently point to is removed.
+  //  */
+  // Iterator cbegin() const;
+  // Iterator cend() const;
+  // Iterator begin() const;
+  // Iterator end() const;
+
+  /**
+   * Allocate a new null buffer.
+   *
+   * This can be used to allocate an empty MemBuf on the stack.  It will have no
+   * space allocated for it.  This is generally useful only to later use move
+   * assignment to fill out the MemBuf.
+   */
+  MemBuf() noexcept;
+
+  /**
+   * Move constructor and assignment operator.
+   *
+   * In general, you should only ever move the head of an MemBuf chain.
+   * Internal nodes in an MemBuf chain are owned by the head of the chain, and
+   * should not be moved from.  (Technically, nothing prevents you from moving
+   * a non-head node, but the moved-to node will replace the moved-from node in
+   * the chain.  This has implications for ownership, since non-head nodes are
+   * owned by the chain head.  You are then responsible for relinquishing
+   * ownership of the moved-to node, and manually deleting the moved-from
+   * node.)
+   *
+   * With the move assignment operator, the destination of the move should be
+   * the head of an MemBuf chain or a solitary MemBuf not part of a chain.  If
+   * the move destination is part of a chain, all other MemBufs in the chain
+   * will be deleted.
+   */
+  MemBuf(MemBuf&& other) noexcept;
+  MemBuf& operator=(MemBuf&& other) noexcept;
+
+  MemBuf(const MemBuf& other);
+  MemBuf& operator=(const MemBuf& other);
+
+ private:
+  enum FlagsEnum : uintptr_t {
+    // Adding any more flags would not work on 32-bit architectures,
+    // as these flags are stashed in the least significant 2 bits of a
+    // max-align-aligned pointer.
+    flag_free_shared_info = 0x1,
+    flag_maybe_shared = 0x2,
+    flag_mask = flag_free_shared_info | flag_maybe_shared
+  };
+
+  struct SharedInfo {
+    SharedInfo();
+    SharedInfo(FreeFunction fn, void* arg);
+
+    // A pointer to a function to call to free the buffer when the refcount
+    // hits 0.  If this is null, free() will be used instead.
+    FreeFunction freeFn;
+    void* userData;
+    std::atomic<uint32_t> refcount;
+    bool externallyShared{false};
+  };
+  // Helper structs for use by operator new and delete
+  struct HeapPrefix;
+  struct HeapStorage;
+  struct HeapFullStorage;
+
+  /**
+   * Create a new MemBuf pointing to an external buffer.
+   *
+   * The caller is responsible for holding a reference count for this new
+   * MemBuf.  The MemBuf constructor does not automatically increment the
+   * reference count.
+   */
+  struct InternalConstructor {};  // avoid conflicts
+  MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
+         std::size_t capacity, uint8_t* data, std::size_t length) noexcept;
+
+  void unshareOneSlow();
+  void unshareChained();
+  void makeManagedChained();
+  void coalesceSlow();
+  void coalesceSlow(size_t maxLength);
+  // newLength must be the entire length of the buffers between this and
+  // end (no truncation)
+  void coalesceAndReallocate(size_t newHeadroom, size_t newLength, MemBuf* end,
+                             size_t newTailroom);
+  void coalesceAndReallocate(size_t newLength, MemBuf* end) {
+    coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom());
+  }
+  void decrementRefcount();
+  void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
+  void freeExtBuffer();
+
+  static size_t goodExtBufferSize(std::size_t minCapacity);
+  static void initExtBuffer(uint8_t* buf, size_t mallocSize,
+                            SharedInfo** infoReturn,
+                            std::size_t* capacityReturn);
+  static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
+                             SharedInfo** infoReturn,
+                             std::size_t* capacityReturn);
+  static void releaseStorage(HeapStorage* storage, uint16_t freeFlags);
+  static void freeInternalBuf(void* buf, void* userData);
+
+  /*
+   * Member variables
+   */
+
+  /*
+   * Links to the next and the previous MemBuf in this chain.
+   *
+   * The chain is circularly linked (the last element in the chain points back
+   * at the head), and next_ and prev_ can never be null.  If this MemBuf is the
+   * only element in the chain, next_ and prev_ will both point to this.
+   */
+  MemBuf* next_{this};
+  MemBuf* prev_{this};
+
+  /*
+   * A pointer to the start of the data referenced by this MemBuf, and the
+   * length of the data.
+   *
+   * This may refer to any subsection of the actual buffer capacity.
+   */
+  uint8_t* data_{nullptr};
+  uint8_t* buf_{nullptr};
+  std::size_t length_{0};
+  std::size_t capacity_{0};
+
+  // Pack flags in least significant 2 bits, sharedInfo in the rest
+  mutable uintptr_t flags_and_shared_info_{0};
+
+  static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags,
+                                                 SharedInfo* info) {
+    uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+    return flags | uinfo;
+  }
+
+  inline SharedInfo* sharedInfo() const {
+    return reinterpret_cast<SharedInfo*>(flags_and_shared_info_ & ~flag_mask);
+  }
+
+  inline void setSharedInfo(SharedInfo* info) {
+    uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
+    flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo;
+  }
+
+  inline uintptr_t flags() const { return flags_and_shared_info_ & flag_mask; }
+
+  // flags_ are changed from const methods
+  inline void setFlags(uintptr_t flags) const {
+    flags_and_shared_info_ |= flags;
+  }
+
+  inline void clearFlags(uintptr_t flags) const {
+    flags_and_shared_info_ &= ~flags;
+  }
+
+  inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) {
+    flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info);
+  }
+
+  struct DeleterBase {
+    virtual ~DeleterBase() {}
+    virtual void dispose(void* p) = 0;
+  };
+
+  template <class UniquePtr>
+  struct UniquePtrDeleter : public DeleterBase {
+    typedef typename UniquePtr::pointer Pointer;
+    typedef typename UniquePtr::deleter_type Deleter;
+
+    explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {}
+    void dispose(void* p) override {
+      try {
+        deleter_(static_cast<Pointer>(p));
+        delete this;
+      } catch (...) {
+        abort();
+      }
+    }
+
+   private:
+    Deleter deleter_;
+  };
+
+  static void freeUniquePtrBuffer(void* ptr, void* userData) {
+    static_cast<DeleterBase*>(userData)->dispose(ptr);
+  }
+};
+
+// template <class UniquePtr>
+// typename std::enable_if<
+//     detail::IsUniquePtrToSL<UniquePtr>::value,
+//     std::unique_ptr<MemBuf>>::type
+// MemBuf::takeOwnership(UniquePtr&& buf, size_t count) {
+//   size_t size = count * sizeof(typename UniquePtr::element_type);
+//   auto deleter = new UniquePtrDeleter<UniquePtr>(buf.get_deleter());
+//   return takeOwnership(
+//       buf.release(), size, &MemBuf::freeUniquePtrBuffer, deleter);
+// }
+
+inline std::unique_ptr<MemBuf> MemBuf::copyBuffer(const void* data,
+                                                  std::size_t size,
+                                                  std::size_t headroom,
+                                                  std::size_t minTailroom) {
+  std::size_t capacity = headroom + size + minTailroom;
+  std::unique_ptr<MemBuf> buf = MemBuf::create(capacity);
+  buf->advance(headroom);
+  if (size != 0) {
+    memcpy(buf->writableData(), data, size);
+  }
+  buf->append(size);
+  return buf;
+}
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/min_filter.h b/libtransport/src/hicn/transport/utils/min_filter.h
new file mode 100755 (executable)
index 0000000..acb081e
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017-2019 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.sudo make instamake install
+ */
+
+#pragma once
+
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/log.h>
+
+#include <deque>
+#include <iostream>
+#include <set>
+#include <type_traits>
+#include <vector>
+
+namespace utils {
+
+template <typename T>
+class MinFilter {
+ public:
+  MinFilter(std::size_t size) : size_(size) {}
+
+  std::size_t size() { return by_arrival_.size(); }
+
+  template <typename R>
+  TRANSPORT_ALWAYS_INLINE void pushBack(R&& value) {
+    if (by_arrival_.size() > size_) {
+      by_order_.erase(by_arrival_.back());
+      by_arrival_.pop_back();
+    }
+
+    by_arrival_.push_front(by_order_.insert(std::forward<R>(value)));
+  }
+
+  TRANSPORT_ALWAYS_INLINE const T& begin() { return *by_order_.cbegin(); }
+
+  TRANSPORT_ALWAYS_INLINE const T& rBegin() { return *by_order_.crbegin(); }
+
+ private:
+  std::multiset<T> by_order_;
+  std::deque<typename std::multiset<T>::const_iterator> by_arrival_;
+  std::size_t size_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/object_pool.h b/libtransport/src/hicn/transport/utils/object_pool.h
new file mode 100755 (executable)
index 0000000..d4d8e18
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+// TODO
+#include <hicn/transport/utils/spinlock.h>
+
+#include <deque>
+#include <memory>
+#include <mutex>
+
+namespace utils {
+
+template <typename T>
+class ObjectPool {
+  class ObjectDeleter {
+   public:
+    ObjectDeleter(ObjectPool<T> *pool = nullptr) : pool_(pool) {}
+
+    void operator()(T *t) {
+      if (pool_) {
+        pool_->add(t);
+      } else {
+        delete t;
+      }
+    }
+
+   private:
+    ObjectPool<T> *pool_;
+  };
+
+ public:
+  using Ptr = std::unique_ptr<T, ObjectDeleter>;
+
+  ObjectPool() {}
+
+  std::pair<bool, Ptr> get() {
+    if (object_pool_.empty()) {
+      return std::make_pair<bool, Ptr>(false, makePtr(nullptr));
+    }
+
+    utils::SpinLock::Acquire locked(object_pool_lock_);
+    auto ret = std::move(object_pool_.front());
+    object_pool_.pop_front();
+    return std::make_pair<bool, Ptr>(true, std::move(ret));
+  }
+
+  void add(T *object) {
+    utils::SpinLock::Acquire locked(object_pool_lock_);
+    object_pool_.emplace_back(makePtr(object));
+  }
+
+  Ptr makePtr(T *object) { return Ptr(object, ObjectDeleter(this)); }
+
+ private:
+  // No copies
+  ObjectPool(const ObjectPool &other) = delete;
+
+  utils::SpinLock object_pool_lock_;
+  std::deque<Ptr> object_pool_;
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/ring_buffer.h b/libtransport/src/hicn/transport/utils/ring_buffer.h
new file mode 100755 (executable)
index 0000000..52bcd81
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <cstddef>
+
+namespace utils {
+
+/**
+ * NOTE: Single consumer single producer ring buffer
+ */
+template <typename Element, std::size_t Size>
+class CircularFifo {
+ public:
+  enum { Capacity = Size + 1 };
+
+  CircularFifo() : tail_(0), head_(0), size_(0) {}
+  virtual ~CircularFifo() {}
+
+  bool push(const Element& item);
+  bool push(Element&& item);
+  bool pop(Element& item);
+
+  bool wasEmpty() const;
+  bool wasFull() const;
+  bool isLockFree() const;
+  std::size_t size() const;
+
+ private:
+  std::size_t increment(std::size_t idx) const;
+  std::atomic<std::size_t> tail_;  // tail(input) index
+  Element array_[Capacity];
+  std::atomic<std::size_t> head_;  // head(output) index
+  std::atomic<std::size_t> size_;
+};
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(const Element& item) {
+  const auto current_tail = tail_.load(std::memory_order_relaxed);
+  const auto next_tail = increment(current_tail);
+  if (next_tail != head_.load(std::memory_order_acquire)) {
+    array_[current_tail] = item;
+    tail_.store(next_tail, std::memory_order_release);
+    size_++;
+    return true;
+  }
+
+  // full queue
+  return false;
+}
+
+/**
+ * Push by move
+ */
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::push(Element&& item) {
+  const auto current_tail = tail_.load(std::memory_order_relaxed);
+  const auto next_tail = increment(current_tail);
+  if (next_tail != head_.load(std::memory_order_acquire)) {
+    array_[current_tail] = std::move(item);
+    tail_.store(next_tail, std::memory_order_release);
+    size_++;
+    return true;
+  }
+
+  // full queue
+  return false;
+}
+
+// Pop by Consumer can only update the head
+// (load with relaxed, store with release)
+// the tail must be accessed with at least acquire
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::pop(Element& item) {
+  const auto current_head = head_.load(std::memory_order_relaxed);
+  if (current_head == tail_.load(std::memory_order_acquire)) {
+    return false;  // empty queue
+  }
+
+  item = std::move(array_[current_head]);
+  head_.store(increment(current_head), std::memory_order_release);
+  size_--;
+  return true;
+}
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasEmpty() const {
+  // snapshot with acceptance of that this comparison operation is not atomic
+  return (head_.load() == tail_.load());
+}
+
+// snapshot with acceptance that this comparison is not atomic
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::wasFull() const {
+  const auto next_tail =
+      increment(tail_.load());  // acquire, we dont know who call
+  return (next_tail == head_.load());
+}
+
+template <typename Element, std::size_t Size>
+bool CircularFifo<Element, Size>::isLockFree() const {
+  return (tail_.is_lock_free() && head_.is_lock_free());
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::increment(std::size_t idx) const {
+  return (idx + 1) % Capacity;
+}
+
+template <typename Element, std::size_t Size>
+std::size_t CircularFifo<Element, Size>::size() const {
+  return size_.load(std::memory_order_relaxed);
+}
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/sharable_vector.h b/libtransport/src/hicn/transport/utils/sharable_vector.h
new file mode 100755 (executable)
index 0000000..31adff1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+namespace utils {
+
+template <class T>
+class SharableVector : public std::vector<T>,
+                       public std::enable_shared_from_this<SharableVector<T>> {
+ public:
+  virtual ~SharableVector(){};
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/signer.cc b/libtransport/src/hicn/transport/utils/signer.cc
new file mode 100755 (executable)
index 0000000..c11d5e1
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Copyright 2017 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hicn/transport/errors/malformed_ahpacket_exception.h>
+#include <hicn/transport/utils/endianess.h>
+#include <hicn/transport/utils/membuf.h>
+#include <hicn/transport/utils/signer.h>
+#include <hicn/transport/utils/key_id.h>
+
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+#include <parc/security/parc_PublicKeySigner.h>
+#include <parc/security/parc_Security.h>
+#include <parc/security/parc_SymmetricKeySigner.h>
+}
+
+#include <chrono>
+
+#define ALLOW_UNALIGNED_READS 1
+
+namespace utils {
+
+uint8_t Signer::zeros[200] = {0};
+
+/*One signer_ per Private Key*/
+Signer::Signer(PARCKeyStore *keyStore, PARCCryptoSuite suite) {
+  switch (suite) {
+    case PARCCryptoSuite_NULL_CRC32C:
+      break;
+    case PARCCryptoSuite_ECDSA_SHA256:
+    case PARCCryptoSuite_RSA_SHA256:
+    case PARCCryptoSuite_DSA_SHA256:
+    case PARCCryptoSuite_RSA_SHA512:
+      this->signer_ =
+          parcSigner_Create(parcPublicKeySigner_Create(keyStore, suite),
+                            PARCPublicKeySignerAsSigner);
+      this->key_id_ = parcSigner_CreateKeyId(this->signer_);
+      break;
+
+    case PARCCryptoSuite_HMAC_SHA512:
+    case PARCCryptoSuite_HMAC_SHA256:
+    default:
+      this->signer_ = parcSigner_Create(
+          parcSymmetricKeySigner_Create((PARCSymmetricKeyStore *)keyStore,
+                                        parcCryptoSuite_GetCryptoHash(suite)),
+          PARCSymmetricKeySignerAsSigner);
+      this->key_id_ = parcSigner_CreateKeyId(this->signer_);
+      break;
+  }
+}
+
+Signer::Signer(const PARCSigner *signer)
+    : signer_(parcSigner_Acquire(signer)),
+      key_id_(parcSigner_CreateKeyId(this->signer_)) {}
+
+Signer::~Signer() {
+  parcSigner_Release(&signer_);
+  parcKeyId_Release(&key_id_);
+}
+
+void Signer::sign(Packet &packet) {
+  // header chain points to the IP + TCP hicn header
+  utils::MemBuf *header_chain = packet.header_head_;
+  utils::MemBuf * payload_chain = packet.payload_head_;
+  uint8_t *hicn_packet = header_chain->writableData();
+  Packet::Format format = packet.getFormat();
+  std::size_t sign_len_bytes = parcSigner_GetSignatureSize(signer_);
+
+  if (!(format & HFO_AH)) {
+    throw errors::MalformedAHPacketException();
+  }
+
+  // Copy IP+TCP/ICMP header before zeroing them
+  hicn_header_t header_copy;
+  if (format & HFO_INET) {
+    memcpy(&header_copy, hicn_packet, sizeof(hicn_v4_hdr_t));
+  } else if (format & HFO_INET6) {
+    memcpy(&header_copy, hicn_packet, sizeof(hicn_v6_hdr_t));
+  }
+
+  std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+  packet.resetForHash();
+  packet.setSignatureSize(sign_len_bytes);
+
+  /* Fill the hicn_ah header */
+  using namespace std::chrono;
+  auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+  packet.setSignatureTimestamp(now);
+  // *reinterpret_cast<uint64_t*>(ah->signTime) = utils::hton<uint64_t>(now);
+  // // std::memcpy(&ah->hicn_ah.signTime, &sign_time, sizeof(ah->hicn_ah.signTime));
+
+  packet.setValidationAlgorithm(CryptoSuite(parcSigner_GetCryptoSuite(this->signer_)));
+  // ah->validationAlgorithm = parcSigner_GetCryptoSuite(this->signer_);
+
+  KeyId key_id;
+  key_id.first = (uint8_t *)parcBuffer_Overlay((PARCBuffer *) parcKeyId_GetKeyId(this->key_id_), 0);
+  packet.setKeyId(key_id);
+
+  // memcpy(ah->keyId,
+  //        parcBuffer_Overlay((PARCBuffer *) parcKeyId_GetKeyId(this->key_id_), 0),
+  //        sizeof(_ah_header_t::keyId));
+
+  // Calculate hash
+  utils::CryptoHasher hasher(parcSigner_GetCryptoHasher(signer_));
+  hasher.init();
+  hasher.updateBytes(hicn_packet, header_len);
+  hasher.updateBytes(zeros, sign_len_bytes);
+  
+  for (utils::MemBuf *current = payload_chain; current != header_chain; current = current->next()) {
+    hasher.updateBytes(current->data(), current->length());
+  }
+
+  utils::CryptoHash hash = hasher.finalize();
+  
+  PARCSignature *signature = parcSigner_SignDigest(this->signer_, hash.hash_);
+  PARCBuffer *buffer = parcSignature_GetSignature(signature);
+
+  PARCByteArray * byte_array = parcBuffer_Array(buffer);
+  uint8_t * bytes = parcByteArray_Array(byte_array);
+  size_t bytes_len = parcBuffer_Remaining(buffer);
+
+  if (bytes_len > sign_len_bytes) {
+    throw errors::MalformedAHPacketException();
+  }
+
+    /* Restore the resetted fields */
+  if (format & HFO_INET) {
+    memcpy(hicn_packet, &header_copy, sizeof(hicn_v4_hdr_t));
+  } else if (format & HFO_INET6) {
+    memcpy(hicn_packet, &header_copy, sizeof(hicn_v6_hdr_t));
+  }
+
+  int offset = sign_len_bytes - bytes_len;
+
+  std::unique_ptr<utils::MemBuf> signature_buffer;
+  std::unique_ptr<utils::MemBuf> tmp_buf = utils::MemBuf::takeOwnership(
+    bytes,
+    bytes_len,
+    bytes_len,
+    [](void* buf, void* userData){ parcSignature_Release((PARCSignature **)&userData); },
+    signature,
+    true);
+
+  if (offset) {
+    signature_buffer = utils::MemBuf::create(offset);
+    memset(signature_buffer->writableData(), 0, offset);
+    signature_buffer->append(offset);
+    signature_buffer->appendChain(std::move(tmp_buf));
+  } else {
+    signature_buffer = std::move(tmp_buf);
+  }
+
+  packet.setSignature(std::move(signature_buffer));
+}
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/signer.h b/libtransport/src/hicn/transport/utils/signer.h
new file mode 100755 (executable)
index 0000000..7b54b63
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/packet.h>
+
+extern "C" {
+#include <parc/security/parc_CryptoHashType.h>
+#include <parc/security/parc_CryptoSuite.h>
+#include <parc/security/parc_KeyStore.h>
+#include <parc/security/parc_Signer.h>
+}
+
+namespace utils {
+
+using Packet = transport::core::Packet;
+
+/**
+ * A signer can use a single key (asymmetric or symmetric) to sign a packet.
+ */
+class Signer {
+  friend class Identity;
+
+ public:
+  /**
+   * Create a Signer
+   *
+   * @param keyStore A keystore containing a private key or simmetric key to
+   * use to sign packet with this Signer.
+   * @param suite CryptoSuite to use to verify the signature
+   */
+  Signer(PARCKeyStore *keyStore, PARCCryptoSuite suite);
+
+  Signer(const PARCSigner *signer);
+
+  ~Signer();
+
+  /**
+   * @brief Sign a packet
+   *
+   * This method is general and must be used for Public-private key signature,
+   * HMAC and CRC.
+   *
+   * @param packet A pointer to the header of the packet to sign. Mutable
+   * field in the packet must be set to 0.
+   * @param key_id Indentifier of the key to use to generate the signature.
+   */
+  void sign(Packet &packet);
+
+ private:
+  PARCSigner *signer_;
+  PARCKeyId *key_id_;
+  static uint8_t zeros[200];
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/socket.h b/libtransport/src/hicn/transport/utils/socket.h
new file mode 100755 (executable)
index 0000000..ab8578f
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/config.h>
+#include <hicn/transport/core/content_object.h>
+#include <hicn/transport/core/facade.h>
+#include <hicn/transport/core/interest.h>
+#include <hicn/transport/core/manifest_format_fixed.h>
+#include <hicn/transport/core/manifest_inline.h>
+#include <hicn/transport/core/name.h>
+#include <hicn/transport/transport/download_observer.h>
+#include <hicn/transport/transport/socket_options_default_values.h>
+#include <hicn/transport/transport/socket_options_keys.h>
+#include <hicn/transport/utils/crypto_suite.h>
+#include <hicn/transport/utils/identity.h>
+#include <hicn/transport/utils/verifier.h>
+
+#define SOCKET_OPTION_GET 0
+#define SOCKET_OPTION_NOT_GET 1
+#define SOCKET_OPTION_SET 2
+#define SOCKET_OPTION_NOT_SET 3
+#define SOCKET_OPTION_DEFAULT 12345
+
+#define VOID_HANDLER 0
+
+namespace transport {
+
+namespace transport {
+
+template <typename PortalType>
+class Socket;
+class ConsumerSocket;
+class ProducerSocket;
+
+using Interest = core::Interest;
+using ContentObject = core::ContentObject;
+using Name = core::Name;
+using ContentObjectManifest = core::ManifestInline<ContentObject, core::Fixed>;
+using InterestManifest = core::ManifestInline<Interest, core::Fixed>;
+using HashAlgorithm = core::HashAlgorithm;
+using CryptoSuite = utils::CryptoSuite;
+using Identity = utils::Identity;
+using Verifier = utils::Verifier;
+
+using HicnForwarderPortal = core::HicnForwarderPortal;
+
+#ifdef __linux__
+#ifndef __ANDROID__
+using RawSocketPortal = core::RawSocketPortal;
+#endif
+#endif
+
+#ifdef __vpp__
+using VPPForwarderPortal = core::VPPForwarderPortal;
+using BaseSocket = Socket<VPPForwarderPortal>;
+using BasePortal = VPPForwarderPortal;
+#else
+using BaseSocket = Socket<HicnForwarderPortal>;
+using BasePortal = HicnForwarderPortal;
+#endif
+
+using PayloadType = core::PayloadType;
+using Prefix = core::Prefix;
+using Array = utils::Array<uint8_t>;
+
+using ConsumerInterestCallback =
+    std::function<void(ConsumerSocket &, const Interest &)>;
+
+using ConsumerContentCallback =
+    std::function<void(ConsumerSocket &, std::size_t, const std::error_code &)>;
+
+using ConsumerTimerCallback =
+    std::function<void(ConsumerSocket &, std::size_t,
+                       std::chrono::milliseconds &, float, uint32_t, uint32_t)>;
+
+using ProducerContentCallback = std::function<void(
+    ProducerSocket &, const std::error_code &, uint64_t bytes_written)>;
+
+using ConsumerContentObjectCallback =
+    std::function<void(ConsumerSocket &, const ContentObject &)>;
+
+using ConsumerContentObjectVerificationCallback =
+    std::function<bool(ConsumerSocket &, const ContentObject &)>;
+
+using ConsumerManifestCallback =
+    std::function<void(ConsumerSocket &, const ContentObjectManifest &)>;
+
+using ProducerContentObjectCallback =
+    std::function<void(ProducerSocket &, ContentObject &)>;
+
+using ProducerInterestCallback =
+    std::function<void(ProducerSocket &, const Interest &)>;
+
+using ProducerInterestCallback =
+    std::function<void(ProducerSocket &, const Interest &)>;
+
+template <typename PortalType>
+class Socket {
+  static_assert(std::is_same<PortalType, HicnForwarderPortal>::value
+#ifdef __linux__
+#ifndef __ANDROID__
+                    || std::is_same<PortalType, RawSocketPortal>::value
+#ifdef __vpp__
+                    || std::is_same<PortalType, VPPForwarderPortal>::value
+#endif
+#endif
+                ,
+#else
+                ,
+
+#endif
+                "This class is not allowed as Portal");
+
+ public:
+  typedef PortalType Portal;
+
+  virtual asio::io_service &getIoService() = 0;
+
+  virtual void connect() = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              uint32_t socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              double socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              bool socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              Name socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              std::list<Prefix> socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ProducerInterestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ProducerContentCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerInterestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerContentCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerManifestCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              IcnObserver *socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              HashAlgorithm socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              CryptoSuite socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              const Identity &socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              ConsumerTimerCallback socket_option_value) = 0;
+
+  virtual int setSocketOption(int socket_option_key,
+                              const std::string &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              uint32_t &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              double &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              bool &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              Name &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::list<Prefix> &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ProducerContentObjectCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ProducerInterestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectVerificationCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key,
+      ConsumerContentObjectCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ConsumerInterestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ConsumerContentCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(
+      int socket_option_key, ConsumerManifestCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ProducerContentCallback &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::shared_ptr<Portal> &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              IcnObserver **socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              HashAlgorithm &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              CryptoSuite &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              Identity &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              std::string &socket_option_value) = 0;
+
+  virtual int getSocketOption(int socket_option_key,
+                              ConsumerTimerCallback &socket_option_value) = 0;
+
+ protected:
+  virtual ~Socket(){};
+
+ protected:
+  std::string output_interface_;
+};
+
+}  // namespace transport
+
+}  // namespace transport
diff --git a/libtransport/src/hicn/transport/utils/spinlock.h b/libtransport/src/hicn/transport/utils/spinlock.h
new file mode 100755 (executable)
index 0000000..33e5cda
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <atomic>
+
+namespace utils {
+
+class SpinLock : private std::atomic_flag {
+ public:
+  class Acquire {
+   public:
+    Acquire(SpinLock& spin_lock) : spin_lock_(spin_lock) { spin_lock_.lock(); }
+
+    ~Acquire() { spin_lock_.unlock(); }
+
+    // No copies
+    Acquire& operator=(const Acquire&) = delete;
+    Acquire(const Acquire&) = delete;
+
+   private:
+    SpinLock& spin_lock_;
+  };
+
+  SpinLock() : std::atomic_flag(false) {}
+
+  void lock() {
+    // busy-wait
+    while (std::atomic_flag::test_and_set(std::memory_order_acquire))
+      ;
+  }
+
+  void unlock() { clear(std::memory_order_release); }
+
+  bool tryLock() {
+    return std::atomic_flag::test_and_set(std::memory_order_acquire);
+  }
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/stream_buffer.h b/libtransport/src/hicn/transport/utils/stream_buffer.h
new file mode 100755 (executable)
index 0000000..adfb696
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <streambuf>
+
+namespace utils {
+
+template <typename char_type>
+struct ostreambuf
+    : public std::basic_streambuf<char_type, std::char_traits<char_type> > {
+  ostreambuf(char_type* buffer, std::streamsize buffer_length) {
+    // set the "put" pointer the start of the buffer and record it's length.
+    setp(buffer, buffer + buffer_length);
+  }
+};
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.cc b/libtransport/src/hicn/transport/utils/string_tokenizer.cc
new file mode 100755 (executable)
index 0000000..9d19110
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/errors/errors.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+namespace utils {
+
+StringTokenizer::StringTokenizer(const std::string &str)
+    : str_(str), delimiter_(" ") {}
+
+StringTokenizer::StringTokenizer(const std::string &str,
+                                 const std::string &delim)
+    : str_(str), delimiter_(delim) {}
+
+bool StringTokenizer::hasMoreTokens() {
+  return str_.find(delimiter_) != std::string::npos || !str_.empty();
+}
+
+std::string StringTokenizer::nextToken() {
+  unsigned long pos = str_.find(delimiter_);
+
+  bool token_found = std::string::npos != pos;
+
+  if (!token_found && str_.empty()) {
+    throw errors::TokenizerException();
+  }
+
+  std::string token = str_.substr(0, pos);
+  str_.erase(0, token_found ? pos + delimiter_.length() : pos);
+
+  return token;
+}
+
+}  // namespace utils
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/string_tokenizer.h b/libtransport/src/hicn/transport/utils/string_tokenizer.h
new file mode 100755 (executable)
index 0000000..36630eb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace utils {
+
+class StringTokenizer {
+ public:
+  StringTokenizer(const std::string &str);
+  StringTokenizer(const std::string &str, const std::string &delim);
+
+  bool hasMoreTokens();
+  std::string nextToken();
+
+ private:
+  std::string str_;
+  std::string delimiter_;
+};
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/test.h b/libtransport/src/hicn/transport/utils/test.h
new file mode 100755 (executable)
index 0000000..e3dd619
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <sstream>
+
+namespace testing {
+
+namespace internal {
+
+enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };
+
+extern void ColoredPrintf(GTestColor color, const char *fmt, ...);
+
+}  // namespace internal
+
+}  // namespace testing
+
+#define PRINTF(...)                                                   \
+  do {                                                                \
+    testing::internal::ColoredPrintf(testing::internal::COLOR_GREEN,  \
+                                     "[          ] ");                \
+    testing::internal::ColoredPrintf(testing::internal::COLOR_YELLOW, \
+                                     __VA_ARGS__);                    \
+  } while (0)
+
+// C++ stream interface
+class TestCout : public std::stringstream {
+ public:
+  ~TestCout() {}
+};
+
+#define TEST_COUT TestCout()
\ No newline at end of file
diff --git a/libtransport/src/hicn/transport/utils/uri.cc b/libtransport/src/hicn/transport/utils/uri.cc
new file mode 100755 (executable)
index 0000000..33eb8b4
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/errors/runtime_exception.h>
+#include <hicn/transport/utils/uri.h>
+
+namespace utils {
+
+Uri::Uri() {}
+
+Uri &Uri::parse(const std::string &uri) {
+  if (uri.length() == 0) {
+    throw errors::RuntimeException("Malformed URI.");
+  }
+
+  iterator_t uri_end = uri.end();
+
+  // get query start
+  iterator_t query_start = std::find(uri.begin(), uri_end, '?');
+
+  // protocol
+  iterator_t protocol_start = uri.begin();
+  iterator_t protocol_end = std::find(protocol_start, uri_end, ':');  //"://");
+
+  if (protocol_end != uri_end) {
+    std::string prot = &*(protocol_end);
+    if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) {
+      protocol_ = std::string(protocol_start, protocol_end);
+      protocol_end += 3;  //      ://
+    } else {
+      protocol_end = uri.begin();  // no protocol
+    }
+  } else {
+    protocol_end = uri.begin();  // no protocol
+  }
+  // host
+  iterator_t host_start = protocol_end;
+  iterator_t path_start =
+      std::find(host_start, uri_end, '/');  // get path_start
+
+  iterator_t host_end = std::find(
+      protocol_end, (path_start != uri_end) ? path_start : query_start,
+      ':');  // check for port
+
+  locator_ = std::string(host_start, host_end);
+
+  // port
+  if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) {
+    host_end++;
+    iterator_t port_end = (path_start != uri_end) ? path_start : query_start;
+    port_ = std::string(host_end, port_end);
+  }
+
+  // path
+  if (path_start != uri_end) {
+    path_ = std::string(path_start, query_start);
+  }
+  // query
+  if (query_start != uri_end) {
+    query_string_ = std::string(query_start, uri.end());
+  }
+
+  return *this;
+}
+
+Uri &Uri::parseProtocolAndLocator(const std::string &locator) {
+  iterator_t total_end = locator.end();
+
+  // protocol
+  iterator_t protocol_start = locator.begin();
+  iterator_t protocol_end =
+      std::find(protocol_start, total_end, ':');  //"://");
+
+  if (protocol_end != total_end) {
+    std::string prot = &*(protocol_end);
+    if ((prot.length() > 3) && (prot.substr(0, 3) == "://")) {
+      protocol_ = std::string(protocol_start, protocol_end);
+      protocol_end += 3;  //      ://
+    } else {
+      throw errors::RuntimeException("Malformed locator. (Missing \"://\")");
+    }
+  } else {
+    throw errors::RuntimeException("Malformed locator. No protocol specified.");
+  }
+
+  // locator
+  iterator_t host_start = protocol_end;
+  iterator_t host_end = std::find(protocol_end, total_end, '/');
+
+  if (host_start == host_end) {
+    throw errors::RuntimeException(
+        "Malformed locator. Locator name is missing");
+  }
+
+  locator_ = std::string(host_start, host_end);
+
+  return *this;
+}
+
+std::string Uri::getLocator() { return locator_; }
+
+std::string Uri::getPath() { return path_; }
+
+std::string Uri::getPort() { return port_; }
+
+std::string Uri::getProtocol() { return protocol_; }
+
+std::string Uri::getQueryString() { return query_string_; }
+
+}  // end namespace utils
diff --git a/libtransport/src/hicn/transport/utils/uri.h b/libtransport/src/hicn/transport/utils/uri.h
new file mode 100755 (executable)
index 0000000..7c28e85
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <algorithm>  // find
+#include <string>
+
+namespace utils {
+
+class Uri {
+  typedef std::string::const_iterator iterator_t;
+
+ public:
+  Uri();
+
+  Uri &parse(const std::string &uri);
+
+  Uri &parseProtocolAndLocator(const std::string &locator);
+
+  std::string getQueryString();
+
+  std::string getPath();
+
+  std::string getProtocol();
+
+  std::string getLocator();
+
+  std::string getPort();
+
+ private:
+  std::string query_string_, path_, protocol_, locator_, port_;
+};  // uri
+
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/verifier.cc b/libtransport/src/hicn/transport/utils/verifier.cc
new file mode 100755 (executable)
index 0000000..9a3de43
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/core/packet.h>
+#include <hicn/transport/errors/malformed_ahpacket_exception.h>
+#include <hicn/transport/portability/portability.h>
+#include <hicn/transport/utils/key_id.h>
+#include <hicn/transport/utils/log.h>
+#include <hicn/transport/utils/verifier.h>
+
+extern "C" {
+TRANSPORT_CLANG_DISABLE_WARNING("-Wextern-c-compat")
+#include <hicn/hicn.h>
+#include <parc/security/parc_CertificateFactory.h>
+#include <parc/security/parc_InMemoryVerifier.h>
+#include <parc/security/parc_Security.h>
+}
+
+#include <sys/stat.h>
+
+namespace utils {
+
+TRANSPORT_ALWAYS_INLINE bool file_exists(const std::string &name) {
+  struct stat buffer;
+  return (stat(name.c_str(), &buffer) == 0);
+}
+
+uint8_t Verifier::zeros[200] = {0};
+
+Verifier::Verifier() {
+  parcSecurity_Init();
+  PARCInMemoryVerifier *in_memory_verifier = parcInMemoryVerifier_Create();
+  this->verifier_ =
+      parcVerifier_Create(in_memory_verifier, PARCInMemoryVerifierAsVerifier);
+  parcInMemoryVerifier_Release(&in_memory_verifier);
+}
+
+Verifier::~Verifier() {
+  parcVerifier_Release(&verifier_);
+  parcSecurity_Fini();
+}
+
+/*
+ * TODO: Unsupported in libparc
+ */
+bool Verifier::hasKey(PARCKeyId *keyId) { return false; }
+
+/*
+ * TODO: signal errors without trap.
+ */
+bool Verifier::addKey(PARCKey *key) {
+  parcVerifier_AddKey(this->verifier_, key);
+  return true;
+}
+
+PARCKeyId * Verifier::addKeyFromCertificate(const std::string &file_name) {
+  PARCCertificateFactory *factory = parcCertificateFactory_Create(PARCCertificateType_X509,
+                                                                  PARCContainerEncoding_PEM);
+  parcAssertNotNull(factory, "Expected non-NULL factory");
+
+  if (!file_exists(file_name)) {
+    TRANSPORT_LOGW("Warning! The certificate %s file does not exist",
+                   file_name.c_str());
+    return nullptr;
+  }
+
+  PARCCertificate *certificate =
+      parcCertificateFactory_CreateCertificateFromFile(
+          factory, (char *)file_name.c_str(), NULL);
+
+  PARCKey *key = parcCertificate_GetPublicKey(certificate);
+  addKey(key);
+
+  PARCKeyId *ret = parcKeyId_Acquire(parcKey_GetKeyId(key));
+
+  //  parcKey_Release(&key);
+  //  parcCertificate_Release(&certificate);
+  //  parcCertificateFactory_Release(&factory);
+
+  return ret;
+}
+
+int Verifier::verify(const Packet &packet) {
+  bool valid = false;
+
+  // header chain points to the IP + TCP hicn header
+  utils::MemBuf *header_chain = packet.header_head_;
+  utils::MemBuf *payload_chain = packet.payload_head_;
+  uint8_t *hicn_packet = header_chain->writableData();
+  Packet::Format format = packet.getFormat();
+
+  if (!(packet.format_ & HFO_AH)) {
+    throw errors::MalformedAHPacketException();
+  }
+
+  // Copy IP+TCP/ICMP header before zeroing them
+  hicn_header_t header_copy;
+  if (format & HFO_INET) {
+    memcpy(&header_copy, hicn_packet, sizeof(hicn_v4_hdr_t));
+  } else if (format & HFO_INET6) {
+    memcpy(&header_copy, hicn_packet, sizeof(hicn_v6_hdr_t));
+  }
+
+  std::size_t header_len = Packet::getHeaderSizeFromFormat(format);
+
+  PARCCryptoSuite suite =
+      static_cast<PARCCryptoSuite>(packet.getValidationAlgorithm());
+  KeyId _key_id = packet.getKeyId();
+  PARCBuffer *buffer =
+      parcBuffer_Wrap(_key_id.first, _key_id.second, 0, _key_id.second);
+  PARCKeyId *key_id = parcKeyId_Create(buffer);
+  parcBuffer_Release(&buffer);
+
+  int ah_payload_len = header_chain->next()->length();
+  uint8_t *signature = header_chain->next()->writableData();
+
+  // Reset fields that should not appear in the signature
+  const_cast<Packet &>(packet).resetForHash();
+
+  PARCCryptoHashType hashtype = parcCryptoSuite_GetCryptoHash(suite);
+  utils::CryptoHasher hasher(
+      parcVerifier_GetCryptoHasher(verifier_, key_id, hashtype));
+
+  hasher.init()
+      .updateBytes(hicn_packet, header_len)
+      .updateBytes(zeros, ah_payload_len);
+
+  for (utils::MemBuf *current = payload_chain; current != header_chain;
+       current = current->next()) {
+    hasher.updateBytes(current->data(), current->length());
+  }
+
+  utils::CryptoHash hash = hasher.finalize();
+  PARCCryptoHash *hash_computed_locally = hash.hash_;
+
+  PARCBuffer *bits =
+      parcBuffer_Wrap(signature, ah_payload_len, 0, ah_payload_len);
+  parcBuffer_Rewind(bits);
+
+  /* IF the signature algo is ECDSA, the signature might be shorter than the
+   * signature field */
+  PARCSigningAlgorithm algo = parcCryptoSuite_GetSigningAlgorithm(suite);
+  while (algo == PARCSigningAlgorithm_ECDSA && parcBuffer_HasRemaining(bits) &&
+         parcBuffer_GetUint8(bits) == 0)
+    ;
+
+  if (algo == PARCSigningAlgorithm_ECDSA) {
+    parcBuffer_SetPosition(bits, parcBuffer_Position(bits) - 1);
+  }
+
+  if (!parcBuffer_HasRemaining(bits)) {
+    parcKeyId_Release(&key_id);
+    parcBuffer_Release(&bits);
+    return valid;
+  }
+
+  PARCSignature *signatureToVerify = parcSignature_Create(
+      parcCryptoSuite_GetSigningAlgorithm(suite), hashtype, bits);
+
+  if (algo == PARCSigningAlgorithm_RSA) {
+    parcBuffer_SetPosition(bits, 0);
+  }
+
+  valid = parcVerifier_VerifyDigestSignature(
+      verifier_, key_id, hash_computed_locally, suite, signatureToVerify);
+
+  /* Restore the resetted fields */
+  if (format & HFO_INET) {
+    memcpy(hicn_packet, &header_copy, sizeof(hicn_v4_hdr_t));
+  } else if (format & HFO_INET6) {
+    memcpy(hicn_packet, &header_copy, sizeof(hicn_v6_hdr_t));
+  }
+
+  parcKeyId_Release(&key_id);
+
+  parcBuffer_Release(&bits);
+  parcSignature_Release(&signatureToVerify);
+
+  return valid;
+}
+}  // namespace utils
diff --git a/libtransport/src/hicn/transport/utils/verifier.h b/libtransport/src/hicn/transport/utils/verifier.h
new file mode 100755 (executable)
index 0000000..6313a72
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#pragma once
+
+#include <hicn/transport/core/packet.h>
+
+extern "C" {
+#include <parc/security/parc_KeyId.h>
+#include <parc/security/parc_Verifier.h>
+}
+
+namespace utils {
+
+using Packet = transport::core::Packet;
+
+/**
+ * A verifier holds a crypto cache that contains all the keys to use for
+ * verify signatures/hmacs.
+ */
+class Verifier {
+ public:
+  Verifier();
+
+  ~Verifier();
+
+  /**
+   * @brief Check if a key is already in this Verifier.
+   *
+   * A PARCVerifier contains a CryptoCache with a set of key to use for
+   * verification purposes.
+   *
+   * @param keyId Identifier of the key to match in the CryptoCache of the
+   * Verifier.
+   * @return true if the key is found, false otherwise.
+   */
+  bool hasKey(PARCKeyId *keyId);
+
+  /**
+   * @brief Add a key to this Verifier
+   *
+   * @param key to add
+   * @return true if the key was added successfully, false otherwise.
+   */
+  bool addKey(PARCKey *key);
+
+  PARCKeyId *addKeyFromCertificate(const std::string &file_name);
+
+  /**
+   * @brief Verify a Signature
+   *
+   * This method is general and must be used for Public-private key signature,
+   * HMAC and CRC.
+   *
+   * @param signature A pointer to the buffer holding the signature
+   * @param sign_len Lenght of the signature (must be consistent with the type
+   * of the key)
+   * @param bufferSigned A pointer to the packet header signed with
+   * signature. Mutable fields and the signature field in the packet must be
+   * set to 0
+   * @param buf_len Lenght of bufferSigned
+   * @param suite CryptoSuite to use to verify the signature
+   * @param key_id Indentifier of the key to use to verify the signature. The
+   * key must be already present in the Verifier.
+   */
+  int verify(const Packet &packet);
+
+ private:
+  PARCVerifier *verifier_;
+  static uint8_t zeros[200];
+};
+
+}  // namespace utils
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..95fdd50
--- /dev/null
@@ -0,0 +1,54 @@
+# Copyright (c) 2017-2019 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.
+
+cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
+set(CMAKE_CXX_STANDARD 14)
+
+project(Utils)
+
+set(CMAKE_MODULE_PATH
+  ${CMAKE_MODULE_PATH}
+  "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules"
+  "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+)
+
+include(BuildMacros)
+include(Packager)
+
+if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+  find_package(Libtransport REQUIRED)
+else()
+  # TODO Set name of targets in CMakeroot file
+  set(LIBTRANSPORT_LIBRARIES ${LIBTRANSPORT})
+endif()
+
+set (COMPILER_DEFINITIONS "-DASIO_STANDALONE")
+
+list(APPEND UTILS_SRC
+  src/hiperf.cc
+  src/ping_client.cc
+  src/ping_server.cc
+)
+
+foreach(util ${UTILS_SRC})
+  get_filename_component(_util_name ${util} NAME)
+  string(REGEX REPLACE ".cc" "" util_name ${_util_name})
+
+  build_executable(${util_name}
+    SOURCES ${util}
+    LINK_LIBRARIES ${LIBTRANSPORT_LIBRARIES}
+    DEPENDS transport
+    COMPONENT utils
+    DEFINITIONS ${COMPILER_DEFINITIONS}
+  )
+endforeach()
\ No newline at end of file
diff --git a/utils/src/hiperf.cc b/utils/src/hiperf.cc
new file mode 100755 (executable)
index 0000000..d8953b3
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_consumer.h>
+#include <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/utils/daemonizator.h>
+#include <hicn/transport/utils/literals.h>
+
+#include <fstream>
+#include <iomanip>
+
+#ifdef __linux__
+#include <mcheck.h>
+#endif
+
+namespace transport {
+
+namespace interface {
+
+#define ERROR_SUCCESS 0
+#define ERROR_SETUP -5
+
+using CryptoSuite = utils::CryptoSuite;
+using Identity = utils::Identity;
+
+struct ClientConfiguration {
+  ClientConfiguration()
+      : name("b001::abcd", 0),
+        verify(false),
+        beta(-1.f),
+        drop_factor(-1.f),
+        window(-1),
+        virtual_download(true),
+        producer_certificate("/tmp/rsa_certificate.pem"),
+        receive_buffer(std::make_shared<utils::SharableVector<uint8_t>>()),
+        download_size(0),
+        report_interval_milliseconds_(1000),
+        rtc_(false) {}
+
+  Name name;
+  bool verify;
+  double beta;
+  double drop_factor;
+  double window;
+  bool virtual_download;
+  std::string producer_certificate;
+  std::shared_ptr<utils::SharableVector<uint8_t>> receive_buffer;
+  std::size_t download_size;
+  std::uint32_t report_interval_milliseconds_;
+  TransportProtocolAlgorithms transport_protocol_;
+  bool rtc_;
+};
+
+struct ServerConfiguration {
+  ServerConfiguration()
+      : name("b001::abcd/64"),
+        virtual_producer(true),
+        manifest(false),
+        live_production(false),
+        sign(false),
+        content_lifetime(600000000_U32),
+        content_object_size(1440),
+        download_size(20 * 1024 * 1024),
+        hash_algorithm(HashAlgorithm::SHA_256),
+        keystore_name("/tmp/rsa_crypto_material.p12"),
+        keystore_password("cisco"),
+        multiphase_produce_(false) {}
+
+  Prefix name;
+  bool virtual_producer;
+  bool manifest;
+  bool live_production;
+  bool sign;
+  std::uint32_t content_lifetime;
+  std::uint16_t content_object_size;
+  std::uint32_t download_size;
+  HashAlgorithm hash_algorithm;
+  std::string keystore_name;
+  std::string keystore_password;
+  bool multiphase_produce_;
+};
+
+class HIperfClient {
+  typedef std::chrono::time_point<std::chrono::steady_clock> Time;
+  typedef std::chrono::microseconds TimeDuration;
+
+ public:
+  HIperfClient(const ClientConfiguration &conf)
+      : configuration_(conf),
+        total_duration_milliseconds_(0),
+        old_bytes_value_(0) {}
+
+  void processPayload(ConsumerSocket &c, std::size_t bytes_transferred,
+                      const std::error_code &ec) {
+    Time t2 = std::chrono::steady_clock::now();
+    TimeDuration dt = std::chrono::duration_cast<TimeDuration>(t2 - t1_);
+    long usec = dt.count();
+
+    std::cout << "Content retrieved. Size: " << bytes_transferred << " [Bytes]"
+              << std::endl;
+
+    std::cerr << "Elapsed Time: " << usec / 1000000.0 << " seconds -- "
+              << (bytes_transferred * 8) * 1.0 / usec * 1.0 << " [Mbps]"
+              << std::endl;
+  }
+
+  bool verifyData(ConsumerSocket &c, const ContentObject &contentObject) {
+    if (contentObject.getPayloadType() == PayloadType::CONTENT_OBJECT) {
+      std::cout << "VERIFY CONTENT" << std::endl;
+    } else if (contentObject.getPayloadType() == PayloadType::MANIFEST) {
+      std::cout << "VERIFY MANIFEST" << std::endl;
+    }
+
+    return true;
+  }
+
+  void processLeavingInterest(ConsumerSocket &c, const Interest &interest) {
+    //    std::cout << "LEAVES " << interest.getName().toUri() << std::endl;
+  }
+
+  void handleTimerExpiration(ConsumerSocket &c, std::size_t byte_count,
+                             std::chrono::milliseconds &exact_duration,
+                             float c_window, uint32_t retransmissions,
+                             uint32_t average_rtt) {
+    const char separator = ' ';
+    const int width = 20;
+
+    std::stringstream interval;
+    interval << total_duration_milliseconds_ / 1000 << "-"
+             << total_duration_milliseconds_ / 1000 +
+                    exact_duration.count() / 1000;
+
+    std::stringstream bytes_transferred;
+    bytes_transferred << std::fixed << std::setprecision(3)
+                      << (byte_count - old_bytes_value_) / 1000000.0
+                      << std::setfill(separator) << "[MBytes]";
+
+    std::stringstream bandwidth;
+    bandwidth << ((byte_count - old_bytes_value_) * 8) /
+                     (exact_duration.count()) / 1000.0
+              << std::setfill(separator) << "[Mbps]";
+
+    std::stringstream window;
+    window << c_window << std::setfill(separator) << "[Interest]";
+
+    std::stringstream avg_rtt;
+    avg_rtt << average_rtt << std::setfill(separator) << "[us]";
+
+    std::cout << std::left << std::setw(width) << "Interval";
+    std::cout << std::left << std::setw(width) << "Transfer";
+    std::cout << std::left << std::setw(width) << "Bandwidth";
+    std::cout << std::left << std::setw(width) << "Retr";
+    std::cout << std::left << std::setw(width) << "Cwnd";
+    std::cout << std::left << std::setw(width) << "AvgRtt" << std::endl;
+
+    std::cout << std::left << std::setw(width) << interval.str();
+    std::cout << std::left << std::setw(width) << bytes_transferred.str();
+    std::cout << std::left << std::setw(width) << bandwidth.str();
+    std::cout << std::left << std::setw(width) << retransmissions;
+    std::cout << std::left << std::setw(width) << window.str();
+    std::cout << std::left << std::setw(width) << avg_rtt.str() << std::endl;
+    std::cout << std::endl;
+
+    total_duration_milliseconds_ += exact_duration.count();
+    old_bytes_value_ = byte_count;
+  }
+
+  int setup() {
+    int ret;
+
+    // Set the transport algorithm
+    TransportProtocolAlgorithms transport_protocol;
+
+    if (configuration_.rtc_) {
+      transport_protocol = RTC;
+    } else if (configuration_.window < 0) {
+      transport_protocol = RAAQM;
+    } else {
+      transport_protocol = CBR;
+    }
+
+    consumer_socket_ = std::make_unique<ConsumerSocket>(transport_protocol);
+
+#if defined(DEBUG) && defined(__linux__)
+    std::shared_ptr<transport::BasePortal> portal;
+    consumer_socket_->getSocketOption(GeneralTransportOptions::PORTAL, portal);
+    signals_ =
+        std::make_unique<asio::signal_set>(portal->getIoService(), SIGUSR1);
+    signals_->async_wait([this](const std::error_code &, const int &) {
+      std::cout << "Signal SIGUSR1!" << std::endl;
+      mtrace();
+    });
+#endif
+
+    if (consumer_socket_->setSocketOption(CURRENT_WINDOW_SIZE,
+                                          configuration_.window) ==
+        SOCKET_OPTION_NOT_SET) {
+      std::cerr << "ERROR -- Impossible to set the size of the window."
+                << std::endl;
+      return ERROR_SETUP;
+    }
+
+    if (transport_protocol == RAAQM && configuration_.beta != -1.f) {
+      if (consumer_socket_->setSocketOption(RaaqmTransportOptions::BETA_VALUE,
+                                            configuration_.beta) ==
+          SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+    }
+
+    if (transport_protocol == RAAQM && configuration_.drop_factor != -1.f) {
+      if (consumer_socket_->setSocketOption(RaaqmTransportOptions::DROP_FACTOR,
+                                            configuration_.drop_factor) ==
+          SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+    }
+
+    if (consumer_socket_->setSocketOption(OtherOptions::VIRTUAL_DOWNLOAD,
+                                          false) == SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    if (configuration_.verify) {
+      if (consumer_socket_->setSocketOption(
+              GeneralTransportOptions::CERTIFICATE,
+              configuration_.producer_certificate) == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+    }
+
+    if (consumer_socket_->setSocketOption(
+            GeneralTransportOptions::VERIFY_SIGNATURE, configuration_.verify) ==
+        SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    ret = consumer_socket_->setSocketOption(
+        ConsumerCallbacksOptions::INTEREST_OUTPUT,
+        (ConsumerInterestCallback)std::bind(
+            &HIperfClient::processLeavingInterest, this, std::placeholders::_1,
+            std::placeholders::_2));
+
+    if (ret == SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    ret = consumer_socket_->setSocketOption(
+        ConsumerCallbacksOptions::CONTENT_RETRIEVED,
+        (ConsumerContentCallback)std::bind(
+            &HIperfClient::processPayload, this, std::placeholders::_1,
+            std::placeholders::_2, std::placeholders::_3));
+
+    if (ret == SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    ret = consumer_socket_->setSocketOption(
+        ConsumerCallbacksOptions::TIMER_EXPIRES,
+        (ConsumerTimerCallback)std::bind(
+            &HIperfClient::handleTimerExpiration, this, std::placeholders::_1,
+            std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
+            std::placeholders::_5, std::placeholders::_6));
+
+    if (ret == SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    if (consumer_socket_->setSocketOption(
+            GeneralTransportOptions::TIMER_INTERVAL,
+            configuration_.report_interval_milliseconds_) ==
+        SOCKET_OPTION_NOT_SET) {
+      return ERROR_SETUP;
+    }
+
+    consumer_socket_->connect();
+
+    return ERROR_SUCCESS;
+  }
+
+  int run() {
+    std::cout << "Starting download of " << configuration_.name << std::endl;
+
+    do {
+      t1_ = std::chrono::steady_clock::now();
+      consumer_socket_->consume(configuration_.name,
+                                *configuration_.receive_buffer);
+    } while (configuration_.virtual_download);
+
+    return ERROR_SUCCESS;
+  }
+
+ private:
+  ClientConfiguration configuration_;
+  std::unique_ptr<ConsumerSocket> consumer_socket_;
+  Time t1_;
+  uint32_t total_duration_milliseconds_;
+  uint64_t old_bytes_value_;
+  // std::unique_ptr<asio::signal_set> signals_;
+};
+
+class HIperfServer {
+  const std::size_t log2_content_object_buffer_size = 8;
+
+ public:
+  HIperfServer(ServerConfiguration &conf)
+      : configuration_(conf),
+        // signals_(io_service_, SIGINT, SIGQUIT),
+        content_objects_((1 << log2_content_object_buffer_size)),
+        content_objects_index_(0),
+        mask_((1 << log2_content_object_buffer_size) - 1) {
+    // signals_.async_wait([this] (const std::error_code&, const int&)
+    // {std::cout << "STOPPING!!" << std::endl; io_service_.stop();});
+
+    std::string buffer(1440, 'X');
+
+    std::cout << "Producing contents under name " << conf.name.getName()
+              << std::endl;
+
+    for (int i = 0; i < (1 << log2_content_object_buffer_size); i++) {
+      content_objects_[i] = std::make_shared<ContentObject>(
+          conf.name.getName(), HF_INET6_TCP, (const uint8_t *)buffer.data(),
+          buffer.size());
+      content_objects_[i]->setLifetime(
+          default_values::content_object_expiry_time);
+    }
+  }
+
+  void processInterest(ProducerSocket &p, const Interest &interest) {
+    content_objects_[content_objects_index_ & mask_]->setName(
+        interest.getName());
+
+    //    if (final_chunk_number_ > 0 && interest.getName().getSuffix() == 0) {
+    //      auto name = interest.getName();
+    //      manifest_ = std::make_shared<ContentObjectManifest>(name);
+    //      // manifest_->setFinalChunkNumber(final_chunk_number_);
+    //      manifest_->encode();
+    //      p.produce(*manifest_);
+    //      return;
+    //    }
+
+    producer_socket_->produce(
+        *content_objects_[content_objects_index_++ & mask_]);
+  }
+
+  void processInterest2(ProducerSocket &p, const Interest &interest) {
+    producer_socket_->setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+                                      (ProducerInterestCallback)VOID_HANDLER);
+    producer_socket_->setSocketOption(
+        GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME, 5000_U32);
+    produceContent(interest.getName().getSuffix());
+    producer_socket_->setSocketOption(
+        ProducerCallbacksOptions::CACHE_MISS,
+        (ProducerInterestCallback)bind(&HIperfServer::processInterest2, this,
+                                       std::placeholders::_1,
+                                       std::placeholders::_2));
+  }
+
+  void produceContent(uint32_t suffix) {
+    core::Name name = configuration_.name.getName();
+
+    std::string content(configuration_.download_size, '?');
+    uint32_t total;
+
+    total = producer_socket_->produce(
+        name, reinterpret_cast<const uint8_t *>(content.data()), content.size(),
+        !configuration_.multiphase_produce_);
+
+    std::cout << "Written " << total << "pieces of data in output buffer"
+              << std::endl;
+  }
+
+  utils::Identity setProducerIdentity(std::string &keystore_name,
+                                      std::string &keystore_password,
+                                      HashAlgorithm &hash_algorithm) {
+    if (access(keystore_name.c_str(), F_OK) != -1) {
+      return utils::Identity(keystore_name, keystore_password, hash_algorithm);
+    } else {
+      return utils::Identity(keystore_name, keystore_password,
+                             CryptoSuite::RSA_SHA256, 1024, 365,
+                             "producer-test");
+    }
+  }
+
+  int setup() {
+    int ret;
+
+    producer_socket_ = std::make_unique<ProducerSocket>();
+
+    if (configuration_.sign) {
+      Identity identity = setProducerIdentity(configuration_.keystore_name,
+                                              configuration_.keystore_password,
+                                              configuration_.hash_algorithm);
+
+      if (producer_socket_->setSocketOption(GeneralTransportOptions::IDENTITY,
+                                            identity) ==
+          SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+    }
+
+    producer_socket_->registerPrefix(configuration_.name);
+
+    if (!configuration_.virtual_producer) {
+      if (producer_socket_->setSocketOption(
+              GeneralTransportOptions::CONTENT_OBJECT_EXPIRY_TIME,
+              configuration_.content_lifetime) == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+
+      if (producer_socket_->setSocketOption(
+              GeneralTransportOptions::MAKE_MANIFEST,
+              configuration_.manifest) == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+
+      if (producer_socket_->setSocketOption(
+              GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 200000U) ==
+          SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+
+      if (!configuration_.live_production) {
+        produceContent(0);
+      } else {
+        ret = producer_socket_->setSocketOption(
+            ProducerCallbacksOptions::CACHE_MISS,
+            (ProducerInterestCallback)bind(&HIperfServer::processInterest2,
+                                           this, std::placeholders::_1,
+                                           std::placeholders::_2));
+
+        if (ret == SOCKET_OPTION_NOT_SET) {
+          return ERROR_SETUP;
+        }
+      }
+    } else {
+      ret = producer_socket_->setSocketOption(
+          GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U);
+
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+
+      ret = producer_socket_->setSocketOption(
+          ProducerCallbacksOptions::CACHE_MISS,
+          (ProducerInterestCallback)bind(&HIperfServer::processInterest, this,
+                                         std::placeholders::_1,
+                                         std::placeholders::_2));
+
+      if (ret == SOCKET_OPTION_NOT_SET) {
+        return ERROR_SETUP;
+      }
+    }
+
+    producer_socket_->connect();
+
+    return ERROR_SUCCESS;
+  }
+
+  int run() {
+    std::cerr << "Starting to serve consumers" << std::endl;
+    producer_socket_->serveForever();
+
+    return ERROR_SUCCESS;
+  }
+
+ private:
+  ServerConfiguration configuration_;
+  std::unique_ptr<ProducerSocket> producer_socket_;
+  // asio::signal_set signals_;
+  std::vector<std::shared_ptr<ContentObject>> content_objects_;
+  std::uint16_t content_objects_index_;
+  std::uint16_t mask_;
+};
+
+void usage() {
+  std::cerr << std::endl;
+  std::cerr << "HIPERF - A tool for performing network throughput "
+               "measurements with hICN"
+            << std::endl;
+  std::cerr << "usage: hiperf [-S|-C] [options] [prefix|name]" << std::endl;
+  std::cerr << "Server or Client:" << std::endl;
+  std::cerr << "-D\t\t\t\t\t"
+            << "Run as a daemon" << std::endl;
+  std::cerr << std::endl;
+  std::cerr << "Server specific:" << std::endl;
+  std::cerr << "-s\t<content_size>\t\t\tSize of the content to publish"
+            << std::endl;
+  std::cerr << "-r\t\t\t\t\t"
+            << "Produce real content of content_size bytes" << std::endl;
+  std::cerr << "-m\t\t\t\t\t"
+            << "Produce transport manifest" << std::endl;
+  std::cerr << "-l\t\t\t\t\t"
+            << "Start producing content upon the reception of the "
+               "first interest"
+            << std::endl;
+  std::cerr << "-k\t<keystore_path>\t\t\t"
+            << "Path of p12 file containing the "
+               "crypto material used for signing the packets"
+            << std::endl;
+  std::cerr << "-y\t<hash_algorithm>\t\t"
+            << "Use the selected hash algorithm for "
+               "calculating manifest digests"
+            << std::endl;
+  std::cerr << "-p\t<password>\t\t\t"
+            << "Password for p12 keystore" << std::endl;
+  std::cerr << std::endl;
+  std::cerr << "Client specific:" << std::endl;
+  std::cerr << "-b\t<beta_parameter>\t\t"
+            << "RAAQM beta parameter" << std::endl;
+  std::cerr << "-d\t<drop_factor_parameter>\t\t"
+            << "RAAQM drop factor "
+               "parameter"
+            << std::endl;
+  std::cerr << "-W\t<window_size>\t\t\t"
+            << "Use a fixed congestion window "
+               "for retrieving the data."
+            << std::endl;
+  std::cerr << "-c\t<certificate_path>\t\t"
+            << "Path of the producer certificate "
+               "to be used for verifying the "
+               "origin of the packets received"
+            << std::endl;
+  std::cout << "-v\t\t\t\t\t"
+            << "Enable verification of received data" << std::endl;
+}
+
+int main(int argc, char *argv[]) {
+  // Common
+  bool daemon = false;
+
+  // -1 server, 0 undefined, 1 client
+  int role = 0;
+  int options = 0;
+
+  char *log_file = nullptr;
+
+  // Consumer
+  ClientConfiguration client_configuration;
+
+  // Producer
+  ServerConfiguration server_configuration;
+
+  int opt;
+  while ((opt = getopt(argc, argv, "DSCf:b:d:W:c:vs:rmlk:y:p:hi:x")) != -1) {
+    switch (opt) {
+      // Common
+      case 'D':
+        daemon = true;
+        break;
+      case 'f':
+        log_file = optarg;
+        break;
+
+      // Server or Client
+      case 'S':
+        role -= 1;
+        break;
+      case 'C':
+        role += 1;
+        break;
+
+      // Client specifc
+      case 'b':
+        client_configuration.beta = std::stod(optarg);
+        options = 1;
+        break;
+      case 'd':
+        client_configuration.drop_factor = std::stod(optarg);
+        options = 1;
+        break;
+      case 'W':
+        client_configuration.window = std::stod(optarg);
+        options = 1;
+        break;
+      case 'c':
+        client_configuration.producer_certificate = std::string(optarg);
+        options = 1;
+        break;
+      case 'v':
+        client_configuration.verify = true;
+        options = 1;
+        break;
+      case 'i':
+        client_configuration.report_interval_milliseconds_ = std::stoul(optarg);
+        options = 1;
+        break;
+      case 'R':
+        client_configuration.rtc_ = true;
+        break;
+
+      // Server specific
+      case 's':
+        server_configuration.download_size = std::stoul(optarg);
+        options = -1;
+        break;
+      case 'r':
+        server_configuration.virtual_producer = false;
+        options = -1;
+        break;
+      case 'm':
+        server_configuration.manifest = true;
+        options = -1;
+        break;
+      case 'l':
+        server_configuration.live_production = true;
+        options = -1;
+        break;
+      case 'k':
+        server_configuration.keystore_name = std::string(optarg);
+        server_configuration.sign = true;
+        options = -1;
+        break;
+      case 'y':
+        if (strncasecmp(optarg, "sha256", 6) == 0) {
+          server_configuration.hash_algorithm = HashAlgorithm::SHA_256;
+        } else if (strncasecmp(optarg, "sha512", 6) == 0) {
+          server_configuration.hash_algorithm = HashAlgorithm::SHA_512;
+        } else if (strncasecmp(optarg, "crc32", 5) == 0) {
+          server_configuration.hash_algorithm = HashAlgorithm::CRC32C;
+        } else {
+          std::cerr << "Ignored unknown hash algorithm. Using SHA 256."
+                    << std::endl;
+        }
+        options = -1;
+        break;
+      case 'p':
+        server_configuration.keystore_password = std::string(optarg);
+        options = -1;
+        break;
+      case 'x':
+        server_configuration.multiphase_produce_ = true;
+        options = -1;
+        break;
+      case 'h':
+      default:
+        usage();
+        return EXIT_FAILURE;
+    }
+  }
+
+  if (options > 0 && role < 0) {
+    std::cerr << "Client options cannot be used when using the "
+                 "software in server mode"
+              << std::endl;
+    usage();
+    return EXIT_FAILURE;
+
+  } else if (options < 0 && role > 0) {
+    std::cerr << "Server options cannot be used when using the "
+                 "software in client mode"
+              << std::endl;
+    usage();
+    return EXIT_FAILURE;
+  } else if (!role) {
+    std::cerr << "Please specify if running hiperf as client "
+                 "or server."
+              << std::endl;
+    usage();
+    return EXIT_FAILURE;
+  }
+
+  if (argv[optind] == 0) {
+    std::cerr << "Please specify the name/prefix to use." << std::endl;
+    usage();
+    return EXIT_FAILURE;
+  } else {
+    if (role > 0) {
+      client_configuration.name = Name(argv[optind]);
+    } else {
+      server_configuration.name = Prefix(argv[optind]);
+    }
+  }
+
+  if (log_file) {
+    int fd = open(log_file, O_WRONLY | O_APPEND | O_CREAT, S_IWUSR | S_IRUSR);
+    dup2(fd, STDOUT_FILENO);
+    dup2(STDOUT_FILENO, STDERR_FILENO);
+    close(fd);
+  }
+
+  if (daemon) {
+    utils::Daemonizator::daemonize(false);
+  }
+
+  if (role > 0) {
+    HIperfClient c(client_configuration);
+    if (c.setup() != ERROR_SETUP) {
+      c.run();
+    }
+  } else if (role < 0) {
+    HIperfServer s(server_configuration);
+    if (s.setup() != ERROR_SETUP) {
+      s.run();
+    }
+  } else {
+    usage();
+    return EXIT_FAILURE;
+  }
+
+  std::cout << "Bye bye" << std::endl;
+
+  return 0;
+}
+
+}  // end namespace interface
+
+}  // end namespace transport
+
+int main(int argc, char *argv[]) {
+  return transport::interface::main(argc, argv);
+}
diff --git a/utils/src/ping_client.cc b/utils/src/ping_client.cc
new file mode 100755 (executable)
index 0000000..178bd8b
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket.h>
+#include <hicn/transport/utils/verifier.h>
+
+#include <asio/steady_timer.hpp>
+#include <chrono>
+#include <map>
+
+#define SYN_STATE 1
+#define ACK_STATE 2
+
+namespace transport {
+
+namespace core {
+
+namespace ping {
+
+typedef std::map<uint64_t, uint64_t> SendTimeMap;
+typedef utils::Verifier Verifier;
+
+class Configuration {
+ public:
+  uint64_t interestLifetime_;
+  uint64_t pingInterval_;
+  uint64_t maxPing_;
+  uint64_t first_suffix_;
+  std::string name_;
+  std::string certificate_;
+  uint16_t srcPort_;
+  uint16_t dstPort_;
+  bool verbose_;
+  bool dump_;
+  bool jump_;
+  bool open_;
+  bool always_syn_;
+  bool always_ack_;
+  bool quiet_;
+  uint32_t jump_freq_;
+  uint32_t jump_size_;
+  uint8_t ttl_;
+
+  Configuration() {
+    interestLifetime_ = 500;  // ms
+    pingInterval_ = 1000000;  // us
+    maxPing_ = 10;            // number of interests
+    first_suffix_ = 0;
+    name_ = "b001::1";  // string
+    srcPort_ = 9695;
+    dstPort_ = 8080;
+    verbose_ = false;
+    dump_ = false;
+    jump_ = false;
+    open_ = false;
+    always_syn_ = false;
+    always_ack_ = false;
+    quiet_ = false;
+    jump_freq_ = 0;
+    jump_size_ = 0;
+    ttl_ = 64;
+  }
+};
+
+class Client : interface::BasePortal::ConsumerCallback {
+ public:
+  Client(Configuration *c) : portal_() {
+    // Let the main thread to catch SIGINT and SIGQUIT
+    // asio::signal_set signals(io_service, SIGINT, SIGQUIT);
+    // signals.async_wait(std::bind(&Client::afterSignal, this));
+
+    portal_.connect();
+    portal_.setConsumerCallback(this);
+    timer_.reset(new asio::steady_timer(portal_.getIoService()));
+    config_ = c;
+    sequence_number_ = config_->first_suffix_;
+    last_jump_ = 0;
+    processed_ = 0;
+    state_ = SYN_STATE;
+    sent_ = 0;
+    received_ = 0;
+    timedout_ = 0;
+    if (!c->certificate_.empty()) {
+      key_id_ = verifier_.addKeyFromCertificate(c->certificate_);
+    }
+  }
+
+  void ping() {
+    std::cout << "start ping" << std::endl;
+    doPing();
+    portal_.runEventsLoop();
+  }
+
+  void onContentObject(Interest::Ptr &&interest,
+                       ContentObject::Ptr &&object) override {
+    uint64_t rtt = 0;
+
+    if (!config_->certificate_.empty()) {
+      auto t0 = std::chrono::steady_clock::now();
+      if (verifier_.verify(*object)) {
+        auto t1 = std::chrono::steady_clock::now();
+        auto dt =
+            std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0);
+        std::cout << "Verification time: " << dt.count() << std::endl;
+        std::cout << "<<<<<< Signature OK!!!" << std::endl;
+      } else {
+        std::cout << "<<<<<< Signature verification failed!" << std::endl;
+      }
+    }
+
+    auto it = send_timestamps_.find(interest->getName().getSuffix());
+    if (it != send_timestamps_.end()) {
+      rtt = std::chrono::duration_cast<std::chrono::microseconds>(
+                std::chrono::steady_clock::now().time_since_epoch())
+                .count() -
+            it->second;
+      send_timestamps_.erase(it);
+    }
+
+    if (config_->verbose_) {
+      std::cout << "<<< recevied object. " << std::endl;
+      std::cout << "<<< interest name: " << interest->getName()
+                << " src port: " << interest->getSrcPort()
+                << " dst port: " << interest->getDstPort()
+                << " flags: " << interest->printFlags() << std::endl;
+      std::cout << "<<< object name: " << object->getName()
+                << " src port: " << object->getSrcPort()
+                << " dst port: " << object->getDstPort()
+                << " flags: " << object->printFlags() << " path label "
+                << object->getPathLabel() << " ("
+                << (object->getPathLabel() >> 24) << ")"
+                << " TTL: " << (int)object->getTTL() << std::endl;
+    } else if (!config_->quiet_) {
+      std::cout << "<<< received object. " << std::endl;
+      std::cout << "<<< round trip: " << rtt << " [us]" << std::endl;
+      std::cout << "<<< interest name: " << interest->getName() << std::endl;
+      std::cout << "<<< object name: " << object->getName() << std::endl;
+      std::cout << "<<< content object size: "
+                << object->payloadSize() + object->headerSize() << " [bytes]"
+                << std::endl;
+    }
+
+    if (config_->dump_) {
+      std::cout << "----- interest dump -----" << std::endl;
+      interest->dump();
+      std::cout << "-------------------------" << std::endl;
+      std::cout << "----- object dump -------" << std::endl;
+      object->dump();
+      std::cout << "-------------------------" << std::endl;
+    }
+
+    if (!config_->quiet_) std::cout << std::endl;
+
+    if (!config_->always_syn_) {
+      if (object->testSyn() && object->testAck() && state_ == SYN_STATE) {
+        state_ = ACK_STATE;
+      }
+    }
+
+    received_++;
+    processed_++;
+    if (processed_ >= config_->maxPing_) {
+      afterSignal();
+    }
+  }
+
+  void onTimeout(Interest::Ptr &&interest) override {
+    if (config_->verbose_) {
+      std::cout << "### timeout for " << interest->getName()
+                << " src port: " << interest->getSrcPort()
+                << " dst port: " << interest->getDstPort()
+                << " flags: " << interest->printFlags() << std::endl;
+    } else if (!config_->quiet_) {
+      std::cout << "### timeout for " << interest->getName() << std::endl;
+    }
+
+    if (config_->dump_) {
+      std::cout << "----- interest dump -----" << std::endl;
+      interest->dump();
+      std::cout << "-------------------------" << std::endl;
+    }
+
+    if (!config_->quiet_) std::cout << std::endl;
+
+    timedout_++;
+    processed_++;
+    if (processed_ >= config_->maxPing_) {
+      afterSignal();
+    }
+  }
+
+  void doPing() {
+    Name interest_name(config_->name_, sequence_number_);
+    hicn_format_t format;
+    if (interest_name.getAddressFamily() == AF_INET) {
+      format = HF_INET_TCP;
+    } else {
+      format = HF_INET6_TCP;
+    }
+
+    Interest::Ptr interest(new Interest(std::move(interest_name), format),
+                           nullptr);
+
+    interest->setLifetime(uint32_t(config_->interestLifetime_));
+
+    interest->resetFlags();
+
+    if (config_->open_ || config_->always_syn_) {
+      if (state_ == SYN_STATE) {
+        interest->setSyn();
+      } else if (state_ == ACK_STATE) {
+        interest->setAck();
+      }
+    } else if (config_->always_ack_) {
+      interest->setAck();
+    }
+
+    interest->setSrcPort(config_->srcPort_);
+    interest->setDstPort(config_->dstPort_);
+    interest->setTTL(config_->ttl_);
+
+    if (config_->verbose_) {
+      std::cout << ">>> send interest " << interest->getName()
+                << " src port: " << interest->getSrcPort()
+                << " dst port: " << interest->getDstPort()
+                << " flags: " << interest->printFlags()
+                << " TTL: " << (int)interest->getTTL() << std::endl;
+    } else if (!config_->quiet_) {
+      std::cout << ">>> send interest " << interest->getName() << std::endl;
+    }
+
+    if (config_->dump_) {
+      std::cout << "----- interest dump -----" << std::endl;
+      interest->dump();
+      std::cout << "-------------------------" << std::endl;
+    }
+
+    if (!config_->quiet_) std::cout << std::endl;
+
+    send_timestamps_[sequence_number_] =
+        std::chrono::duration_cast<std::chrono::microseconds>(
+            std::chrono::steady_clock::now().time_since_epoch())
+            .count();
+
+    portal_.sendInterest(std::move(interest));
+
+    sequence_number_++;
+    sent_++;
+
+    if (sent_ < config_->maxPing_) {
+      this->timer_->expires_from_now(
+          std::chrono::microseconds(config_->pingInterval_));
+      this->timer_->async_wait([this](const std::error_code e) { doPing(); });
+    }
+  }
+
+  void afterSignal() {
+    std::cout << "Stop ping" << std::endl;
+    std::cout << "Sent: " << sent_ << " Received: " << received_
+              << " Timeouts: " << timedout_ << std::endl;
+    portal_.stopEventsLoop();
+  }
+
+  void reset() {
+    timer_.reset(new asio::steady_timer(portal_.getIoService()));
+    sequence_number_ = config_->first_suffix_;
+    last_jump_ = 0;
+    processed_ = 0;
+    state_ = SYN_STATE;
+    sent_ = 0;
+    received_ = 0;
+    timedout_ = 0;
+  }
+
+ private:
+  SendTimeMap send_timestamps_;
+  interface::BasePortal portal_;
+  uint64_t sequence_number_;
+  uint64_t last_jump_;
+  uint64_t processed_;
+  uint32_t state_;
+  uint32_t sent_;
+  uint32_t received_;
+  uint32_t timedout_;
+  std::unique_ptr<asio::steady_timer> timer_;
+  Configuration *config_;
+  Verifier verifier_;
+  PARCKeyId *key_id_;
+};
+
+void help() {
+  std::cout << "usage: hicn-consumer-ping [options]" << std::endl;
+  std::cout << "PING options" << std::endl;
+  std::cout
+      << "-i <val>          ping interval in microseconds (default 1000000ms)"
+      << std::endl;
+  std::cout << "-m <val>          maximum number of pings to send (default 10)"
+            << std::endl;
+  std::cout << "-s <val>          sorce port (default 9695)" << std::endl;
+  std::cout << "-d <val>          destination port (default 8080)" << std::endl;
+  std::cout << "-t <val>          set packet ttl (default 64)" << std::endl;
+  std::cout << "-O                open tcp connection (three way handshake) "
+               "(default false)"
+            << std::endl;
+  std::cout << "-S                send always syn messages (default false)"
+            << std::endl;
+  std::cout << "-A                send always ack messages (default false)"
+            << std::endl;
+  std::cout << "HICN options" << std::endl;
+  std::cout << "-n <val>          hicn name (default b001::1)" << std::endl;
+  std::cout
+      << "-l <val>          interest lifetime in milliseconds (default 500ms)"
+      << std::endl;
+  std::cout << "OUTPUT options" << std::endl;
+  std::cout << "-V                verbose, prints statistics about the "
+               "messagges sent and received (default false)"
+            << std::endl;
+  std::cout << "-D                dump, dumps sent and received packets "
+               "(default false)"
+            << std::endl;
+  std::cout << "-q                quiet, not prints (default false)"
+            << std::endl;
+  std::cout << "-H                prints this message" << std::endl;
+}
+
+int main(int argc, char *argv[]) {
+  Configuration *c = new Configuration();
+  int opt;
+  std::string producer_certificate = "";
+
+  while ((opt = getopt(argc, argv, "j::t:i:m:s:d:n:l:f:c:SAOqVDH")) != -1) {
+    switch (opt) {
+      case 't':
+        c->ttl_ = (uint8_t)std::stoi(optarg);
+        break;
+      case 'i':
+        c->pingInterval_ = std::stoi(optarg);
+        break;
+      case 'm':
+        c->maxPing_ = std::stoi(optarg);
+        break;
+      case 'f':
+        c->first_suffix_ = std::stoul(optarg);
+        break;
+      case 's':
+        c->srcPort_ = std::stoi(optarg);
+        break;
+      case 'd':
+        c->dstPort_ = std::stoi(optarg);
+        break;
+      case 'n':
+        c->name_ = optarg;
+        break;
+      case 'l':
+        c->interestLifetime_ = std::stoi(optarg);
+        break;
+      case 'V':
+        c->verbose_ = true;
+        ;
+        break;
+      case 'D':
+        c->dump_ = true;
+        break;
+      case 'O':
+        c->always_syn_ = false;
+        c->always_ack_ = false;
+        c->open_ = true;
+        break;
+      case 'S':
+        c->always_syn_ = true;
+        c->always_ack_ = false;
+        c->open_ = false;
+        break;
+      case 'A':
+        c->always_syn_ = false;
+        c->always_ack_ = true;
+        c->open_ = false;
+        break;
+      case 'q':
+        c->quiet_ = true;
+        c->verbose_ = false;
+        c->dump_ = false;
+        break;
+      case 'c':
+        c->certificate_ = std::string(optarg);
+        break;
+      case 'H':
+      default:
+        help();
+        exit(EXIT_FAILURE);
+    }
+  }
+
+  Client *ping = new Client(c);
+
+  auto t0 = std::chrono::steady_clock::now();
+  ping->ping();
+  auto t1 = std::chrono::steady_clock::now();
+
+  std::cout
+      << "Elapsed time: "
+      << std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count()
+      << std::endl;
+
+  return 0;
+}
+
+}  // namespace ping
+
+}  // namespace core
+
+}  // namespace transport
+
+int main(int argc, char *argv[]) {
+  return transport::core::ping::main(argc, argv);
+}
diff --git a/utils/src/ping_server.cc b/utils/src/ping_server.cc
new file mode 100755 (executable)
index 0000000..19de34f
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2017-2019 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 <hicn/transport/interfaces/socket_producer.h>
+#include <hicn/transport/utils/daemonizator.h>
+#include <hicn/transport/utils/signer.h>
+#include <hicn/transport/utils/string_tokenizer.h>
+
+namespace transport {
+
+namespace interface {
+
+using HashAlgorithm = core::HashAlgorithm;
+using CryptoSuite = utils::CryptoSuite;
+
+utils::Identity setProducerIdentity(std::string keystore_name,
+                                    std::string keystore_password,
+                                    HashAlgorithm hash_algorithm) {
+  if (access(keystore_name.c_str(), F_OK) != -1) {
+    return utils::Identity(keystore_name, keystore_password, hash_algorithm);
+  } else {
+    return utils::Identity(keystore_name, keystore_password,
+                           CryptoSuite::RSA_SHA256, 1024, 365, "producer-test");
+  }
+}
+
+class CallbackContainer {
+  const std::size_t log2_content_object_buffer_size = 12;
+
+ public:
+  CallbackContainer(const Name &prefix, uint32_t object_size, bool verbose,
+                    bool dump, bool quite, bool flags, bool reset, uint8_t ttl,
+                    utils::Identity *identity, bool sign)
+      : buffer_(object_size, 'X'),
+        content_objects_(1 << log2_content_object_buffer_size),
+        mask_((1 << log2_content_object_buffer_size) - 1),
+        content_objects_index_(0),
+        verbose_(verbose),
+        dump_(dump),
+        quite_(quite),
+        flags_(flags),
+        reset_(reset),
+        ttl_(ttl),
+        identity_(identity),
+        sign_(sign) {
+    core::Packet::Format format;
+
+    if (prefix.getAddressFamily() == AF_INET) {
+      format = core::Packet::Format::HF_INET_TCP;
+      if (sign_) {
+        format = core::Packet::Format::HF_INET_TCP_AH;
+      }
+    } else {
+      format = core::Packet::Format::HF_INET6_TCP;
+      if (sign_) {
+        format = core::Packet::Format::HF_INET6_TCP_AH;
+      }
+    }
+
+    for (int i = 0; i < (1 << log2_content_object_buffer_size); i++) {
+      content_objects_[i] = std::make_shared<ContentObject>(
+          prefix, format, (const uint8_t *)buffer_.data(), buffer_.size());
+      content_objects_[i]->setLifetime(
+          default_values::content_object_expiry_time);
+    }
+  }
+
+  void processInterest(ProducerSocket &p, const Interest &interest) {
+    if (verbose_) {
+      std::cout << "<<< received interest " << interest.getName()
+                << " src port: " << interest.getSrcPort()
+                << " dst port: " << interest.getDstPort()
+                << " flags: " << interest.printFlags()
+                << "TTL: " << (int)interest.getTTL() << std::endl;
+    } else if (!quite_) {
+      std::cout << "<<< received interest " << interest.getName() << std::endl;
+    }
+
+    if (dump_) {
+      std::cout << "----- interest dump -----" << std::endl;
+      interest.dump();
+      std::cout << "-------------------------" << std::endl;
+    }
+
+    if (interest.testRst()) {
+      std::cout << "!!!got a reset, I don't reply" << std::endl;
+    } else {
+      auto &content_object = content_objects_[content_objects_index_++ & mask_];
+
+      content_object->setName(interest.getName());
+      content_object->setLifetime(default_values::content_object_expiry_time);
+      content_object->setLocator(interest.getLocator());
+      content_object->setSrcPort(interest.getDstPort());
+      content_object->setDstPort(interest.getSrcPort());
+      content_object->setTTL(ttl_);
+
+      if (sign_) {
+        content_object->setSignatureSize(identity_->getSignatureLength());
+      } else {
+        content_object->resetFlags();
+      }
+
+      if (flags_) {
+        if (interest.testSyn()) {
+          content_object->setSyn();
+          content_object->setAck();
+        } else if (interest.testAck()) {
+          content_object->setAck();
+        }  // here I may need to handle the FIN flag;
+      } else if (reset_) {
+        content_object->setRst();
+      }
+
+      if (verbose_) {
+        std::cout << ">>> send object " << content_object->getName()
+                  << " src port: " << content_object->getSrcPort()
+                  << " dst port: " << content_object->getDstPort()
+                  << " flags: " << content_object->printFlags()
+                  << " TTL: " << (int)content_object->getTTL() << std::endl;
+      } else if (!quite_) {
+        std::cout << ">>> send object " << content_object->getName()
+                  << std::endl;
+      }
+
+      if (dump_) {
+        std::cout << "----- object dump -----" << std::endl;
+        content_object->dump();
+        std::cout << "-----------------------" << std::endl;
+      }
+
+      if (!quite_) std::cout << std::endl;
+
+      if (sign_) {
+        identity_->getSigner().sign(*content_object);
+      }
+
+      p.produce(*content_object);
+    }
+  }
+
+ private:
+  std::string buffer_;
+  std::vector<std::shared_ptr<ContentObject>> content_objects_;
+  std::uint16_t mask_;
+  std::uint16_t content_objects_index_;
+  bool verbose_;
+  bool dump_;
+  bool quite_;
+  bool flags_;
+  bool reset_;
+  uint8_t ttl_;
+  utils::Identity *identity_;
+  bool sign_;
+};
+
+void help() {
+  std::cout << "usage: hicn-preoducer-ping [options]" << std::endl;
+  std::cout << "PING options" << std::endl;
+  std::cout << "-s <val>  object content size (default 1350B)" << std::endl;
+  std::cout << "-n <val>  hicn name (default b001::/64)" << std::endl;
+  std::cout << "-f        set tcp flags according to the flag received "
+               "(default false)"
+            << std::endl;
+  std::cout << "-r        always reply with a reset flag (default false)"
+            << std::endl;
+  std::cout << "-t        set ttl (default 64)" << std::endl;
+  std::cout << "OUTPUT options" << std::endl;
+  std::cout << "-V        verbose, prints statistics about the messagges sent "
+               "and received (default false)"
+            << std::endl;
+  std::cout << "-D        dump, dumps sent and received packets (default false)"
+            << std::endl;
+  std::cout << "-q        quite, not prints (default false)" << std::endl;
+  std::cout << "-d        daemon mode" << std::endl;
+  std::cout << "-H        prints this message" << std::endl;
+}
+
+int main(int argc, char **argv) {
+  std::string name_prefix = "b001::0/64";
+  std::string delimiter = "/";
+  bool daemon = false;
+  bool verbose = false;
+  bool dump = false;
+  bool quite = false;
+  bool flags = false;
+  bool reset = false;
+  uint32_t object_size = 1350;
+  uint8_t ttl = 64;
+  std::string keystore_path = "./rsa_crypto_material.p12";
+  std::string keystore_password = "cisco";
+  bool sign = false;
+
+  int opt;
+  while ((opt = getopt(argc, argv, "s:n:t:qfrVDdHk:p:")) != -1) {
+    switch (opt) {
+      case 's':
+        object_size = std::stoi(optarg);
+        break;
+      case 'n':
+        name_prefix = optarg;
+        break;
+      case 't':
+        ttl = (uint8_t)std::stoi(optarg);
+        break;
+      case 'V':
+        verbose = true;
+        break;
+      case 'D':
+        dump = true;
+        break;
+      case 'q':
+        verbose = false;
+        dump = false;
+        quite = true;
+        break;
+      case 'd':
+        daemon = true;
+        break;
+      case 'f':
+        flags = true;
+        break;
+      case 'r':
+        reset = true;
+        break;
+      case 'k':
+        keystore_path = optarg;
+        sign = true;
+        break;
+      case 'p':
+        keystore_password = optarg;
+        break;
+      case 'H':
+      default:
+        help();
+        exit(EXIT_FAILURE);
+    }
+  }
+
+  if (daemon) {
+    utils::Daemonizator::daemonize();
+  }
+
+  core::Prefix producer_namespace(name_prefix);
+
+  utils::StringTokenizer tokenizer(name_prefix, delimiter);
+  std::string ip_address = tokenizer.nextToken();
+  Name n(ip_address);
+
+  if (object_size > 1350) object_size = 1350;
+
+  CallbackContainer *stubs;
+  utils::Identity identity = setProducerIdentity(
+      keystore_path, keystore_password, HashAlgorithm::SHA_256);
+
+  if (sign) {
+    stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags,
+                                  reset, ttl, &identity, sign);
+  } else {
+    utils::Identity *identity = nullptr;
+    stubs = new CallbackContainer(n, object_size, verbose, dump, quite, flags,
+                                  reset, ttl, identity, sign);
+  }
+
+  asio::io_service io_service;
+
+  ProducerSocket p(io_service);  // , setProducerIdentity());
+  p.registerPrefix(producer_namespace);
+
+  p.setSocketOption(GeneralTransportOptions::OUTPUT_BUFFER_SIZE, 0U);
+  p.setSocketOption(ProducerCallbacksOptions::CACHE_MISS,
+                    (ProducerInterestCallback)bind(
+                        &CallbackContainer::processInterest, stubs,
+                        std::placeholders::_1, std::placeholders::_2));
+
+  p.connect();
+
+  p.serveForever();
+
+  return 0;
+}
+
+}  // namespace interface
+
+}  // end namespace transport
+
+int main(int argc, char **argv) {
+  return transport::interface::main(argc, argv);
+}