aboutsummaryrefslogtreecommitdiffstats
path: root/ctrl/facemgr
diff options
context:
space:
mode:
authorJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 09:52:33 +0200
committerJordan Augé <jordan.auge+fdio@cisco.com>2019-10-07 15:55:42 +0200
commit6b84ec54083da9911f5ad4816d0eb4f4745afad4 (patch)
treee4296ebb218fff02dc0bbea73ce1c8d12aba7bcc /ctrl/facemgr
parent85a791ac2cdd35d79c00141e748b4c68fbdafb0d (diff)
[HICN-298] Release new hICN app for Android
Change-Id: I43adc62fadf00690b687078d739788dffdc5e566 Signed-off-by: Jordan Augé <jordan.auge+fdio@cisco.com>
Diffstat (limited to 'ctrl/facemgr')
-rw-r--r--ctrl/facemgr/CMakeLists.txt35
-rw-r--r--ctrl/facemgr/README.md10
-rw-r--r--ctrl/facemgr/cmake/Modules/Packaging.cmake12
-rw-r--r--ctrl/facemgr/doc/interface.md358
-rw-r--r--ctrl/facemgr/examples/facemgr.conf217
-rwxr-xr-xctrl/facemgr/examples/run-bonjour.sh162
-rw-r--r--ctrl/facemgr/examples/updowncli/Makefile25
-rw-r--r--ctrl/facemgr/examples/updowncli/updowncli.c57
-rw-r--r--ctrl/facemgr/examples/updownsrv/Makefile25
-rw-r--r--ctrl/facemgr/examples/updownsrv/updownsrv.c231
-rw-r--r--ctrl/facemgr/includes/CMakeLists.txt44
-rw-r--r--ctrl/facemgr/includes/facemgr.h (renamed from ctrl/facemgr/src/netdevice.c)18
-rw-r--r--ctrl/facemgr/includes/hicn/android_utility/android_utility.h48
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr.h (renamed from ctrl/facemgr/src/interface_map.h)15
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr/api.h81
-rw-r--r--ctrl/facemgr/includes/hicn/facemgr/cfg.h193
-rw-r--r--ctrl/facemgr/includes/hicn/util/log.h (renamed from ctrl/facemgr/src/util/log.h)0
-rw-r--r--ctrl/facemgr/src/CMakeLists.txt79
-rw-r--r--ctrl/facemgr/src/api.c1421
-rw-r--r--ctrl/facemgr/src/cfg.c991
-rw-r--r--ctrl/facemgr/src/common.h35
-rw-r--r--ctrl/facemgr/src/event.c39
-rw-r--r--ctrl/facemgr/src/event.h59
-rw-r--r--ctrl/facemgr/src/face.c262
-rw-r--r--ctrl/facemgr/src/face.h177
-rw-r--r--ctrl/facemgr/src/face_cache.h24
-rw-r--r--ctrl/facemgr/src/face_rules.c21
-rw-r--r--ctrl/facemgr/src/facelet.c1008
-rw-r--r--ctrl/facemgr/src/facelet.h198
-rw-r--r--ctrl/facemgr/src/facemgr.c298
-rw-r--r--ctrl/facemgr/src/facemgr.h77
-rw-r--r--ctrl/facemgr/src/interface.c29
-rw-r--r--ctrl/facemgr/src/interface.h21
-rw-r--r--ctrl/facemgr/src/interface_map.c21
-rw-r--r--ctrl/facemgr/src/interface_ops_map.c21
-rw-r--r--ctrl/facemgr/src/interfaces/CMakeLists.txt11
-rw-r--r--ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt27
-rw-r--r--ctrl/facemgr/src/interfaces/android_utility/android_utility.c138
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt32
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/bonjour.c408
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/bonjour.h (renamed from ctrl/facemgr/src/face_rules.h)30
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE24
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/README.md9
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c192
-rw-r--r--ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h879
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt1
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/dummy.c98
-rw-r--r--ctrl/facemgr/src/interfaces/dummy/dummy.h (renamed from ctrl/facemgr/src/interface_ops_map.h)22
-rw-r--r--ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c204
-rw-r--r--ctrl/facemgr/src/interfaces/netlink/netlink.c472
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt1
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/network_framework.c138
-rw-r--r--ctrl/facemgr/src/interfaces/network_framework/network_framework.h (renamed from ctrl/facemgr/src/face_cache.c)11
-rw-r--r--ctrl/facemgr/src/interfaces/updown/CMakeLists.txt31
-rw-r--r--ctrl/facemgr/src/interfaces/updown/updown.c138
-rw-r--r--ctrl/facemgr/src/main.c773
-rw-r--r--ctrl/facemgr/src/netdevice.h52
-rw-r--r--ctrl/facemgr/src/util/ip_address.h328
-rw-r--r--ctrl/facemgr/src/util/log.c60
-rw-r--r--ctrl/facemgr/src/util/map.h113
-rw-r--r--ctrl/facemgr/src/util/policy.c59
-rw-r--r--ctrl/facemgr/src/util/policy.h234
-rw-r--r--ctrl/facemgr/src/util/set.h95
-rw-r--r--ctrl/facemgr/src/util/token.h40
-rw-r--r--ctrl/facemgr/src/util/types.h36
65 files changed, 8614 insertions, 2354 deletions
diff --git a/ctrl/facemgr/CMakeLists.txt b/ctrl/facemgr/CMakeLists.txt
index f688dd2ca..377773c2d 100644
--- a/ctrl/facemgr/CMakeLists.txt
+++ b/ctrl/facemgr/CMakeLists.txt
@@ -20,6 +20,22 @@ endif()
project(facemgr)
+option(WITH_THREAD "Run library as thread" OFF)
+option(WITH_EXAMPLE_DUMMY "Compile dummy example interface" OFF)
+option(WITH_EXAMPLE_UPDOWN "Compile updown example interface" OFF)
+
+if(WITH_THREAD)
+ message("Building with thread support")
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
+ message("Building with 'dummy' example interface")
+endif()
+
+if(WITH_EXAMPLE_UPDOWN)
+ message("Building with 'updown' example interface")
+endif()
+
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "${PROJECT_NAME}: No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release")
@@ -42,22 +58,29 @@ find_package_wrapper(Config REQUIRED)
find_package_wrapper(LibEvent REQUIRED)
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
+ find_package_wrapper(Libhicn REQUIRED)
find_package_wrapper(Libhicnctrl REQUIRED)
- set(FACE_MGR facemgr)
+ set(FACEMGR facemgr)
+ set(LIBFACEMGR facemgr)
else()
- if (ANDROID_API)
- set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_STATIC})
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ set(HICN_LIBRARIES ${LIBHICN_STATIC})
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_STATIC})
list(APPEND DEPENDENCIES
- ${LIBHICN_CTRL_STATIC}
+ ${LIBHICN_STATIC}
+ ${LIBHICNCTRL_STATIC}
)
else ()
- set(LIBHICNCTRL_LIBRARIES ${LIBHICN_CTRL_SHARED})
+ set(HICN_LIBRARIES ${LIBHICN_SHARED})
+ set(LIBHICNCTRL_LIBRARIES ${LIBHICNCTRL_SHARED})
list(APPEND DEPENDENCIES
- ${LIBHICN_CTRL_SHARED}
+ ${LIBHICN_SHARED}
+ ${LIBHICNCTRL_SHARED}
)
endif ()
endif()
+add_subdirectory(includes)
add_subdirectory(src)
include(Packaging)
diff --git a/ctrl/facemgr/README.md b/ctrl/facemgr/README.md
index e1a1beb4f..0cad9bc11 100644
--- a/ctrl/facemgr/README.md
+++ b/ctrl/facemgr/README.md
@@ -1 +1,11 @@
# hICN Face Manager
+
+The bonjour interfaces uses SO_BINDTODEVICE to be able to send bonjour queries
+to the right interfaces. As such facemgr has to be run as root, or with the
+CAP_NET_RAW capability.
+
+```
+sudo getcap build-root/bin/facemgr
+sudo setcap cap_net_raw+ep build-root/bin/facemgr
+sudo getcap build-root/bin/facemgr
+```
diff --git a/ctrl/facemgr/cmake/Modules/Packaging.cmake b/ctrl/facemgr/cmake/Modules/Packaging.cmake
index 97a1b6260..3a7e5a85c 100644
--- a/ctrl/facemgr/cmake/Modules/Packaging.cmake
+++ b/ctrl/facemgr/cmake/Modules/Packaging.cmake
@@ -15,17 +15,17 @@
# Packages section
######################
-set(${FACE_MGR}_DESCRIPTION
- "hICN face manager, lib${LIBHICN_CTRL}"
+set(${FACEMGR}_DESCRIPTION
+ "hICN face manager, lib${LIBHICNCTRL}"
CACHE STRING "Description for deb/rpm package."
)
-set(${FACE_MGR}_DEB_DEPENDENCIES
- "libconfig9, libevent-dev, lib${LIBHICN_CTRL} (>= stable_version)"
+set(${FACEMGR}_DEB_DEPENDENCIES
+ "libconfig9, libevent-dev, lib${LIBHICNCTRL} (>= stable_version)"
CACHE STRING "Dependencies for deb/rpm package."
)
-set(${FACE_MGR}_RPM_DEPENDENCIES
- "libconfig, libevent-devel, lib${LIBHICN_CTRL} >= stable_version"
+set(${FACEMGR}_RPM_DEPENDENCIES
+ "libconfig, libevent-devel, lib${LIBHICNCTRL} >= stable_version"
CACHE STRING "Dependencies for deb/rpm package."
)
diff --git a/ctrl/facemgr/doc/interface.md b/ctrl/facemgr/doc/interface.md
new file mode 100644
index 000000000..11c8da275
--- /dev/null
+++ b/ctrl/facemgr/doc/interface.md
@@ -0,0 +1,358 @@
+# Face manager : Interfaces
+
+## Overview
+
+The architecture of the face manager is built around the concept of interfaces,
+which allows for a modular and extensible deployment.
+
+Interfaces are used to implement in isolation various sources of information
+which help with the construction of faces (such as network interface and service
+discovery), and with handling the heterogeneity of host platforms.
+
+
+### Platform and supported interfaces
+
+Currently, Android, Linux and MacOS are supported through the following
+interfaces:
+
+- hicn-light [Linux, Android, MacOS, iOS]
+ An interface to the hicn-light forwarder, and more specifically to the Face
+ Table and FIB data structures. This component is responsible to effectively
+ create, update and delete faces in the forwarder, based on the information
+ provided by third party interfaces, plus adding default routes for each of
+ the newly created face. The communication with the forwarder is based on the
+ hicn control library (`libhicnctrl`).
+
+- netlink [Linux, Android]
+ The default interface on Linux systems (including Android) to communicate
+ with the kernel and receive information from various sources, including link
+ and address information (both IPv4 and IPv6) about network interfaces.
+
+- android\_utility [Android only]
+ Information available through Netlink is limited with respect to cellular
+ interfaces. This component allows querying the Android layer through SDK
+ functions to get the type of a given network interface (Wired, WiFi or
+ Cellular).
+
+- bonjour [Linux, Android]
+ This component performs remote service discovery based on the bonjour
+ protocol to discover a remote hICN forwarder that might be needed to
+ establish overlay faces.
+
+- network\_framework [MacOS, iOS]
+
+ This component uses the recommended Network framework on Apple devices,
+ which provided all required information to query faces in a unified API:
+ link and address information, interface types, and bonjour service
+ discovery.
+
+
+### Architectural overview
+
+#### Facelets
+
+TODO:
+- Key attributes (netdevice and protocol family)
+- Facelet API
+
+#### Events
+
+TODO
+
+#### Facelet cache & event scheduling
+
+TODO:
+ - Facelet cache
+ - Joins
+ - How synchronization work
+
+### Interface API
+
+TODO
+
+## Developing a new interface
+
+### Dummy template
+
+The face manager source code includes a template that can be used as a skeleton
+to develop new faces. It can be found in `src/interface/dummy/dummy.{h,c}`. Both
+include guard and specific interface functions are prefixed by a (short)
+identifier which acts as a namespace for interface specific code (in our case
+the string 'dummy\_').
+
+Registration and instanciation of the different interfaces is currently done at
+compile time in the file `src/api.c`, and the appropriate hooks to use the dummy
+interface are avaialble in the code between `#if 0/#endif` tags.
+
+#### Interface template header; configuration parameters
+
+All interfaces have a standard interface defined in `src/interface.{h,c}`, and
+as such the header file is only used to specify the configuration parameters of
+the interface, if any.
+
+In the template, these configuration options are empty:
+```
+/*
+ * Configuration data
+ */
+typedef struct {
+ /* ... */
+} dummy_cfg_t;
+```
+
+#### Overview of the interface template
+
+The file starts with useful includes:
+- the global include `<hicn/facemgr.h>` : this provides public facing elements
+ of the face manager, such the standard definition of faces (`face_t` from
+ `libhicnctrl`), helper classes (such as `ip_address_t` from `libhicn`), etc.
+- common.h
+- facelet.h : facelets are the basic unit of communication between the face
+manager and the different interfaces. They are used to construct the faces
+incrementally.
+- interface.h : the parent class of interfaces, such as the current dummy
+interface.
+
+Each interface can hold a pointer to an internal data structure, which is
+declared as follows:
+```
+/*
+ * Internal data
+ */
+typedef struct {
+ /* The configuration data will likely be allocated on the stack (or should
+ * be freed) by the caller, we recommend to make a copy of this data.
+ * This copy can further be altered with default values.
+ */
+ dummy_cfg_t cfg;
+
+ /* ... */
+
+ int fd; /* Sample internal data: file descriptor */
+} dummy_data_t;
+```
+
+We find here a copy of the configuration settings (which allows the called to
+instanciate the structure on the stack), as well as a file descriptor
+(assuming most interfaces will react on events on a file descriptor).
+
+The rest of the file consists in the implementation of the interface, in
+particular the different function required by the registration of a new
+interface to the system. They are grouped as part of the `interface_ops_t` data
+structure declared at the end of the file:
+
+```
+interface\_ops\_t dummy\_ops = {
+ .type = "dummy",
+ .initialize = dummy_initialize,
+ .finalize = dummy_finalize,
+ .callback = dummy_callback,
+ .on_event = dummy_on_event,
+};
+```
+
+The structure itself is declared and documented in `src/interface.h`
+```
+/**
+ * \brief Interface operations
+ */
+typedef struct {
+ /** The type given to the interfaces */
+ char * type;
+ /* Constructor */
+ int (*initialize)(struct interface\_s * interface, void * cfg);
+ /* Destructor */
+ int (*finalize)(struct interface_s * interface);
+ /* Callback upon file descriptor event (iif previously registered) */
+ int (*callback)(struct interface_s * interface);
+ /* Callback upon facelet events coming from the face manager */
+ int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet);
+} interface\_ops\_t;
+```
+
+Such an interface has to be registered first, then one (or multiple) instance(s)
+can be created (see `src/interface.c` for the function prototypes, and
+`src/api.c` for their usage).
+
+- interface registration:
+
+```
+extern interface\_ops\_t dummy\_ops;
+
+/* [...] */
+
+rc = interface\_register(&dummy\_ops);
+if (rc < 0)
+ goto ERR_REGISTER;
+```
+
+- interface instanciation:
+
+```
+#include "interfaces/dummy/dummy.h"
+
+/* [...] */
+
+rc = facemgr_create_interface(facemgr, "dummy0", "dummy", &facemgr->dummy);
+if (rc < 0) {
+ ERROR("Error creating 'Dummy' interface\n");
+ goto ERR_DUMMY_CREATE;
+}
+```
+
+#### Implementation of the interface API
+
+We now quickly go other the different functions, but their usage will be better
+understood through the hands-on example treated in the following section.
+
+In the template, the constructor is the most involved as it need to:
+
+- initialize the internal data structure:
+
+```
+ dummy_data_t * data = malloc(sizeof(dummy_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+```
+
+- process configuration parameters, eventually setting some default values:
+
+```
+ /* Use default values for unspecified configuration parameters */
+ if (cfg) {
+ data->cfg = *(dummy_cfg_t *)cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(data->cfg));
+ }
+```
+
+- open an eventually required file descriptor
+
+For the sake of simplicity, the current API only supports a single file
+descriptor per-interface, and it has to be created in the constructor, and
+set as the return value so as to be registered by the system, and added to the
+event loop for read events. A return value of 0 means the interface does not
+require any file descriptor. As usual, a negative return value indicates an
+error.
+
+```
+ data->fd = 0;
+
+ /* ... */
+
+ /*
+ * We should return a negative value in case of error, and a positive value
+ * otherwise:
+ * - a file descriptor (>0) will be added to the event loop; or
+ * - 0 if we don't use any file descriptor
+ */
+ return data->fd;
+```
+
+While support for multiple file descriptors might be added in the future, an
+alternative short-term implementation might consider the instanciation of
+multiple interface, as is done for Bonjour in the current codebase, in
+`src/api.c`.
+
+Data reception on the file descriptor will get the callback function called, in
+our case `dummy_callback`. Finally, the destructor `dummy_finalize` should close
+an eventual open file descriptor.
+
+In order to retrieve the internal data structure, that should in particular
+store such a file descriptor, all other function but the constructor can
+dereference it from the interface pointer they receive as parameter:
+
+```
+dummy\_data\_t * data = (dummy\_data\_t*)interface->data;
+```
+
+#### Raising and receiving events
+
+An interface will receive events in the form of a facelet through the `*_on_event`
+function. It can then use the facelet API we have describe above to read
+information about the face.
+
+As this information is declared const, the interface can either create a new
+facelet (identified by the same netdevice and protocol family), or eventually
+clone it.
+
+The facelet event can then be defined and raised to the face maanger for further
+processing through the following code:
+```
+ facelet_set_event(facelet, EVENT_TYPE_CREATE);
+ facelet_raise_event(facelet, interface);
+```
+
+Here the event is a facelet creation (`EVENT_TYPE_CREATE`). The full facelet API
+and the list of possible event types is available in `src/facelet.h`
+
+
+#### Integration in the build system
+
+The build system is based on CMake. Each interface should declare its source
+files, private and public header files, as well as link dependencies in the
+local `CMakeLists.txt` file.
+
+TODO: detail the structure of the file
+
+
+### Hands-on example
+
+#### Overview
+
+In order to better illustrate the development of a new interface, we will
+consider the integration of a sample server providing a signal instructing the
+face manager to alternatively use either the WiFi or the LTE interface. The code
+of this server is available in the folder `examples/updownsrv/`, and the
+corresponding client code in `examples/updowncli`.
+
+Communication between client and server is done through unix sockets over an
+abstract namespace (thereby not using the file system, which would cause issues
+on Android). The server listens for client connections, and periodically
+broadcast a binary information to all connected clients, in the form of one byte
+equal to either \0 (which we might interpret as enable LTE, disable WiFi), or \1
+(enable WiFi, disable LTE).
+
+Our objective is to develop a new face manager interface that would listen to
+such event in order to update the administrative status of the current faces.
+This would thus alternatively set the different interfaces admnistratively up
+and down (which takes precedence over the actual status of the interface when
+the forwarder establishes the set of available next hops for a given prefix).
+The actual realization of such queries will be ultimately performed by the
+hicn-light interface.
+
+#### Sample server and client
+
+In the folder containing the source code of hICN, the following commands allow
+to run the sample server:
+
+```
+cd ctrl/facemgr/examples/updownsrv
+make
+./updownsrv
+```
+
+The server should display "Waiting for clients..."
+
+Similar commands allow to run the sample client:
+```
+cd ctrl/facemgr/examples/updowncli
+make
+./updowncli
+```
+
+The client should display "Waiting for server data...", then every couple of
+seconds display either "WiFi" or "LTE".
+
+#### Facemanager interface
+
+An example illustrating how to connect to the dummy service from `updownsrv` is
+provided as the `updown` interface in the facemgr source code.
+
+This interface periodically swaps the status of the LTE interface up and down.
+It is instanciated as part of the facemgr codebase when the code is compiled
+with the ``-DWITH_EXAMPLE_UPDOWN` cmake option.
+
+
+
diff --git a/ctrl/facemgr/examples/facemgr.conf b/ctrl/facemgr/examples/facemgr.conf
index 54c212c2b..4658d13e3 100644
--- a/ctrl/facemgr/examples/facemgr.conf
+++ b/ctrl/facemgr/examples/facemgr.conf
@@ -1,37 +1,194 @@
+#
# hICN facemgr configuration file
+#
-faces:
-{
- # A list of interfaces to ignore
- ignore = ("lo");
-
- # A list of rules used to assign tags to interfaces
- # Each rule follows the syntax { name = "NAME"; tags = ("TAG", ...); }
- # with TAG = WIRED | WIFI | CELLULAR | TRUSTED
- rules = (
- {
- name = "utun1";
- tags = ("WIRED", "TRUSTED");
- }
- );
-
- overlay = {
- ipv4 = {
- local_port = 9695;
- remote_port = 9695;
- remote_addr = "10.60.16.14";
- };
- ipv6 = {
- local_port = 9695;
- remote_port = 9695;
- remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f";
- };
- };
-}
+################################################################################
+# Global settings
+################################################################################
+
+global = {
+
+# Default type for face creation
+#
+# Values: "auto" | "native-udp" | "native-tcp" | "overlay-udp" | "overlay-tcp"
+# Default "auto"
+#
+#face_type = "auto";
+face_type = "overlay-udp"
+
+# Disable service discovery for overlay creation
+#
+# This is only meaningful for overlay_* face types. If service discovery is
+# disabled, only manually entered overlay information will be used, if any.
+# Otherwise, no face will be created.
+#
+# Values : true | false
+# Default: false
+#
+#disable_discovery = true;
+
+# TODO Disable IPv4 face creation
+#
+# Values : true | false
+# Default: false
+#
+#disable_ipv4 = true;
+
+# TODO Disable IPv6 face creation
+#
+# Values : true | false
+# Default: false
+#
+#disable_ipv6 = true;
+
+# TODO overlay
+#
+# By default, no address is specified, and local and remote ports are set to
+# the standard value for hICN (9695).
+#
+
+};
+
+################################################################################
+# Per-interface rules
+################################################################################
+#
+# Rules allow to override the default behaviour of the face manager.
+#
+# The list of rules must be specified as follows (note that the last one has no
+# coma at the end) :
+#
+# rules = (
+# { ... },
+# { ... },
+# { ... }
+# );
+#
+# A rule is composed of match and override attributes, and has the following
+# syntax:
+#
+# {
+# match = {
+# interface_name = STRING;
+# interface_type = STRING;
+# };
+# override = {
+# face_type = STRING;
+# disable_discovery = BOOL;
+# ignore = BOOL;
+# tags = (STRING, STRING, STRING);
+# overlay = {
+# ipv4 = {
+# local_port = PORT;
+# remote_addr = IP_ADDRESS;
+# remote_port = PORT;
+# };
+# ipv6 = {
+# local_port = PORT;
+# remote_addr = IP_ADDRESS;
+# remote_port = PORT;
+# };
+# };
+# };
+# }
+#
+# Match attributes:
+#
+# Match attributes serve to identify rules and as such defining two rules with
+# similar matches is not allowed. However, overlapping match definitions are
+# possible, in which case only the first matching rule is considered.
+#
+# A match is composed of the name of an interface and/or its type (either
+# attribute is optional but at least one has to be specified).
+#
+# * interface_name - a string representing an interface name
+#
+# * interface_type - the type of interface to match
+#
+# Values: "wired" | "wifi" | "cellular"
+#
+# Override attributes:
+#
+# Those attributes are applied when all specified match attributes correspond,
+# and override general settings or default values.
+#
+# * face_type - type used for face creation
+#
+# Values: "auto" | "native_udp" | "native_tcp" | "overlay_udp" | "overlay_tcp"
+#
+# * disable_discovery - disable service discovery for overlay creation
+#
+# Values : true | false
+#
+# * ignore - a boolean indicating whether that interface should be ignored
+#
+# * TODO tags - a (possibly empty) list of tags to be associated to the created face.
+#
+# Values: "wired" | "wifi" | "cellular" | "trusted"
+#
+# * overlay
+#
+# An overlay specification is used to complement any information retrieved
+# through service discovery (or replace it if service discovery is
+# disabled).
+#
+# It is possible to specify values for IPv4, IPv6 or both.
+#
+# Note that it is not currently possible to set different settings for IPv4 and
+# IPv6 but overlay specifications.
+#
+#
+# Here are a few example of rule definitions:
+#
+# rules = (
+# # Ignore localhost interface
+# {
+# match = {
+# interface_name = "lo";
+# };
+# override = {
+# ignore = true;
+# };
+# },
+# # Set tags for unknown tunnnel interface
+# {
+# match = {
+# interface_name = "utun1";
+# };
+# override = {
+# tags = ("WIRED", "TRUSTED");
+# };
+# },
+# # Force cellular connections to use manually specified overlay faces
+# {
+# match = {
+# interface_type = "cellular",
+# };
+# override = {
+# overlay = {
+# ipv4 = {
+# local_port = 9695;
+# remote_addr = "10.60.16.14";
+# remote_port = 9695;
+# };
+# ipv6 = {
+# local_port = 9695;
+# remote_addr = "2001:420:44f1:10:20c:29ff:fef3:8f8f";
+# remote_port = 9695;
+# };
+# };
+# };
+# }
+# );
+#
+#rules = (
+#);
+
+################################################################################
+# Logging
+################################################################################
log:
{
log_level = "DEBUG";
}
-
-
diff --git a/ctrl/facemgr/examples/run-bonjour.sh b/ctrl/facemgr/examples/run-bonjour.sh
new file mode 100755
index 000000000..c6c317b42
--- /dev/null
+++ b/ctrl/facemgr/examples/run-bonjour.sh
@@ -0,0 +1,162 @@
+#!/bin/bash
+
+set -e
+
+PORT=9695
+
+#-------------------------------------------------------------------------------
+
+FN_AVAHI_CFG_SRC=$SCRIPT_PATH/etc_avahi_services_hicn.service
+FN_AVAHI_CFG=/etc/avahi/services/hicn.service
+
+# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression
+! read -r -d '' TPL_AVAHI_CFG <<-EOF
+<?xml version="1.0" standalone='no'?>
+<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
+<service-group>
+ <name>hicn node</name>
+ <service>
+ <type>_hicn._udp</type>
+ <port>$PORT</port>
+ </service>
+</service-group>
+EOF
+
+#-------------------------------------------------------------------------------
+
+# Reliably determine script's full path
+SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
+
+# https://unix.stackexchange.com/questions/325594/script-a-test-for-installed-debian-package-error-handling
+function pkg_is_installed()
+{
+ PKG="$1"
+ LISTF=$(mktemp)
+ dpkg-query -W -f '${Package} ${State}\n' >$LISTF
+ grep "^${PKG} " $LISTF >/dev/null
+ GREP_RC=$?
+ rm $LISTF
+
+ # for even moar strict error handling
+ test $GREP_RC == 0 -o $GREP_RC == 1
+
+ return $GREP_RC
+}
+
+# https://stackoverflow.com/questions/3466166/how-to-check-if-running-in-cygwin-mac-or-linux
+function detect_os()
+{
+ unameOut="$(uname -s)"
+ case "${unameOut}" in
+ Linux*) machine=linux;;
+ Darwin*) machine=mac;;
+ CYGWIN*) machine=cygwin;;
+ MINGW*) machine=mingw;;
+ *) machine=unknown;;
+ esac
+ echo ${machine}
+}
+
+function ensure_pkg_is_installed()
+{
+ PKG="$1"
+ pkg_is_installed $PKG && return
+ sudo apt install $PKG
+}
+
+function ensure_file_installed()
+{
+ SRC=$1
+ DST=$2
+
+ # Test whether destination exists and is up to date
+ [ -s $DST ] && cmp -s $SRC $DST && return
+
+ sudo cp $SRC $DST
+}
+
+function ensure_file_template()
+{
+ DST=$1
+ TPL=$2
+
+ echo "$TPL" | sudo tee $DST >/dev/null
+}
+
+function is_function()
+{
+ [ "$(type -t $1)" == "function" ]
+}
+
+function os_function()
+{
+ FUN=$1
+ shift
+ ARGS=$@
+
+ OS=$(detect_os)
+ if ! is_function ${FUN}_${OS}; then
+ echo "Platform $OS not supported for $FUN [${FUN}_${OS}]"
+ exit -1
+ fi
+ ${FUN}_${OS} $ARGS
+}
+
+#-------------------------------------------------------------------------------
+
+# NOTE: debian only
+function run_bonjour_server_linux()
+{
+ ensure_pkg_is_installed avahi-daemon
+ #ensure_file_installed $FN_AVAHI_CFG_SRC $FN_AVAHI_CFG
+ ensure_file_template $FN_AVAHI_CFG "$TPL_AVAHI_CFG"
+ sudo service avahi-daemon restart
+ echo >&2, "Bonjour is now served through avahi"
+}
+
+function run_bonjour_server_mac()
+{
+ dns-sd -R hicn _hicn._tcp local $PORT
+ # Proxy mode -P
+}
+
+function run_bonjour_client_linux()
+{
+ avahi-browse -ptr _hicn._udp
+}
+
+function run_bonjour_client_mac()
+{
+ dns-sd -B _hicn._udp local
+
+}
+
+# XXX function run_bonjour_proxy_linux() { }
+
+function run_bonjour_proxy_mac()
+{
+ if [[ $# != 2 ]]; then
+ echo "Usage: $0 proxy IP_ADDRESS"
+ exit -1
+ fi
+ IP=$1
+ dns-sd -P hicn _hicn._udp local $PORT hicn.local $IP path=/
+}
+
+#-------------------------------------------------------------------------------
+
+case $1 in
+ client)
+ os_function run_bonjour_client
+ ;;
+ server)
+ os_function run_bonjour_server
+ ;;
+ proxy)
+ os_function run_bonjour_proxy $@
+ ;;
+ *)
+ echo "$0 [client|server]"
+ exit -1
+ ;;
+esac
diff --git a/ctrl/facemgr/examples/updowncli/Makefile b/ctrl/facemgr/examples/updowncli/Makefile
new file mode 100644
index 000000000..5e6111c2a
--- /dev/null
+++ b/ctrl/facemgr/examples/updowncli/Makefile
@@ -0,0 +1,25 @@
+EXEC = $(shell basename $$(pwd))
+CC = gcc
+
+CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing
+#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0)
+#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0)
+
+SRC = $(wildcard *.c)
+OBJ = $(SRC:.c=.o)
+
+all: $(EXEC)
+
+${EXEC}: $(OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf *.o
+
+mrproper: clean
+ @rm -rf $(EXEC)
diff --git a/ctrl/facemgr/examples/updowncli/updowncli.c b/ctrl/facemgr/examples/updowncli/updowncli.c
new file mode 100644
index 000000000..4f5a14165
--- /dev/null
+++ b/ctrl/facemgr/examples/updowncli/updowncli.c
@@ -0,0 +1,57 @@
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+int main() {
+ struct sockaddr_un addr;
+ char buf[100];
+ int fd,rc;
+
+ char * socket_path = UNIX_PATH;
+
+ if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("socket error");
+ exit(-1);
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*socket_path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
+ }
+
+ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("connect error");
+ exit(-1);
+ }
+
+ printf("Waiting for server data...\n");
+ while( (rc=read(fd, buf, sizeof(buf))) > 0) {
+ assert(rc == 1);
+ switch(buf[0]) {
+ case '\0':
+ printf("WiFi\n");
+ break;
+ case '\1':
+ printf("LTE\n");
+ break;
+ default:
+ printf("Unknown\n");
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/ctrl/facemgr/examples/updownsrv/Makefile b/ctrl/facemgr/examples/updownsrv/Makefile
new file mode 100644
index 000000000..5e6111c2a
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/Makefile
@@ -0,0 +1,25 @@
+EXEC = $(shell basename $$(pwd))
+CC = gcc
+
+CFLAGS = -std=gnu11 -O3 -Wall -Wextra -Wpedantic -Wstrict-aliasing
+#CFLAGS += $(shell pkg-config --cflags glib-2.0 gio-2.0)
+#LDFLAGS = $(shell pkg-config --libs glib-2.0 gio-2.0)
+
+SRC = $(wildcard *.c)
+OBJ = $(SRC:.c=.o)
+
+all: $(EXEC)
+
+${EXEC}: $(OBJ)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf *.o
+
+mrproper: clean
+ @rm -rf $(EXEC)
diff --git a/ctrl/facemgr/examples/updownsrv/updownsrv.c b/ctrl/facemgr/examples/updownsrv/updownsrv.c
new file mode 100644
index 000000000..e10247860
--- /dev/null
+++ b/ctrl/facemgr/examples/updownsrv/updownsrv.c
@@ -0,0 +1,231 @@
+/*
+ * Dummy server sending alternating bytes to all clients.
+ *
+ * This is used by the face manager to illustrate the creation of interfaces
+ * using unix domains that sets a face up and down.
+ */
+
+#include <arpa/inet.h> // inet_ntop
+#include <errno.h> // EINTR,. ..
+#include <netinet/in.h> // INET_ADDRSTRLEN, INET6_ADDRSTRLEN
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+#include <sys/un.h> // sockaddr_un
+#include <unistd.h> // fcntl
+#include <fcntl.h> // fcntl
+
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+/**
+ * \brief Default interval (in seconds) between timer events */
+#define DEFAULT_INTERVAL 100000
+
+/**
+ * \brief Maximum allowed number of connected clients
+ */
+#define MAX_CLIENTS 5
+
+/**
+ * \brief Maximum backlog of listening unix socket
+ */
+#define LISTEN_BACKLOG MAX_CLIENTS
+
+
+/**
+ * \brief Creates a unix server socket
+ * \param [in] path - string representing the path on which to listen for
+ * connections
+ * \return int - fd associated to the socket
+ */
+int
+create_unix_server(char * path)
+{
+ struct sockaddr_un addr;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ perror("socket error");
+ return -1;
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+ unlink(path);
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("bind error");
+ return -1;
+ }
+
+ if (listen(fd, LISTEN_BACKLOG) == -1) {
+ perror("listen error");
+ return -1;
+ }
+
+ return fd;
+}
+
+
+/**
+ * \brief Main function
+ */
+int main() {
+ int fd, tfd;
+ int rc;
+
+ /* Alternating state of the server : 0 / 1 */
+ unsigned state = 0;
+
+ /*
+ * This server has to send a signal to all connected clients at periodic
+ * intervals. Since we don't expect a large number of connected clients for
+ * such a simple program, we simply use a statically allocated array.
+ */
+ int clients[MAX_CLIENTS];
+ size_t num_clients = 0;
+
+ fd_set active_fd_set, read_fd_set;
+ FD_ZERO (&active_fd_set);
+
+ /* Create listening unix socket */
+ fd = create_unix_server(UNIX_PATH);
+ if (fd < 0)
+ exit(EXIT_FAILURE);
+ FD_SET (fd, &active_fd_set);
+
+ /* Create timer */
+ tfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (tfd == -1) {
+ perror("timer error");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ perror("fcntl");
+ exit(EXIT_FAILURE);
+ }
+
+ FD_SET (tfd, &active_fd_set);
+
+ struct itimerspec ts = {
+ .it_interval = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ },
+ .it_value = {
+ .tv_sec = DEFAULT_INTERVAL,
+ .tv_nsec = 0,
+ }
+ };
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Waiting for clients...\n");
+
+ for(;;) {
+ /* Block until input arrives on one or more active sockets. */
+ read_fd_set = active_fd_set;
+ rc = select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
+ if (rc < 0) {
+ if (rc == EINTR)
+ break;
+ perror("select");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Service all the sockets with input pending. */
+ for (int i = 0; i < FD_SETSIZE; ++i) {
+ if (!FD_ISSET (i, &read_fd_set))
+ continue;
+ if (i == fd) {
+ /* Connection request on original socket. */
+ int client_fd = accept(fd, NULL, NULL);
+ if (client_fd < 0) {
+ perror("accept");
+ continue;
+ }
+
+ fprintf(stderr, "Server: connect from new client\n");
+ clients[num_clients++] = client_fd;
+ FD_SET(client_fd, &active_fd_set);
+ } else if (i == tfd) {
+ /* Timer event */
+ uint64_t res;
+
+ read(tfd, &res, sizeof(res));
+// while (read(fd, &missed, sizeof(missed)) > 0)
+// ;
+ for (unsigned j = 0; j < num_clients; j++) {
+ write(clients[j], state ? "\1" : "\0", 1);
+ }
+ printf("STATE=%d\n", state);
+ state = 1 - state;
+ } else {
+ char buf[1024];
+ rc = read(i, buf, sizeof(buf));
+ /* Client event : we close the connection on any event... */
+ for (unsigned j = 0; j < num_clients; j++) {
+ if (i == clients[j]) {
+ clients[j] = clients[num_clients--];
+ break;
+ }
+ }
+ close(i);
+ FD_CLR(i, &active_fd_set);
+ }
+ }
+
+ }
+
+ int ret = EXIT_SUCCESS;
+
+ /* Close all active client connections */
+ for (unsigned i = 0; i < num_clients; i++) {
+ rc = close(clients[i]);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ /* Close server */
+ rc = close(fd);
+ if (rc == -1) {
+ perror("close");
+ ret = EXIT_FAILURE;
+ }
+
+ /* Terminate timer */
+ ts.it_value.tv_sec = 0;
+ rc = timerfd_settime(tfd, 0, &ts, NULL);
+ if (rc == -1) {
+ perror("timerfd_settime");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(ret);
+}
diff --git a/ctrl/facemgr/includes/CMakeLists.txt b/ctrl/facemgr/includes/CMakeLists.txt
new file mode 100644
index 000000000..566424c67
--- /dev/null
+++ b/ctrl/facemgr/includes/CMakeLists.txt
@@ -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.
+
+# XXX
+
+set(LIBFACEMGR_INCLUDE_DIRS
+ ${CMAKE_CURRENT_SOURCE_DIR} ""
+ CACHE INTERNAL
+ "" FORCE
+)
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+
+ set(TO_INSTALL_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/android_utility/android_utility.h
+ PARENT_SCOPE
+ )
+
+else ()
+
+ set(TO_INSTALL_HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/facemgr.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/api.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/facemgr/cfg.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/hicn/util/log.h
+ PARENT_SCOPE
+ )
+
+endif ()
+
+
diff --git a/ctrl/facemgr/src/netdevice.c b/ctrl/facemgr/includes/facemgr.h
index 817b0e47b..b322e7b1f 100644
--- a/ctrl/facemgr/src/netdevice.c
+++ b/ctrl/facemgr/includes/facemgr.h
@@ -14,15 +14,15 @@
*/
/**
- * \file netdevice.c
- * \brief Implementation of Netdevice abstraction
+ * \file facemgr.h
+ * \brief Main interface for hICN face manager library
*/
+#ifndef HICN_FACEMGR_H
+#define HICN_FACEMGR_H
-#include "common.h"
-#include "netdevice.h"
+#include <hicn/policy.h>
+#include <hicn/facemgr/api.h>
+#include <hicn/facemgr/cfg.h>
+
+#endif /* HICN_FACEMGR_H */
-const char * netdevice_type_str[] = {
-#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x),
-foreach_netdevice_type
-#undef _
-}
diff --git a/ctrl/facemgr/includes/hicn/android_utility/android_utility.h b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h
new file mode 100644
index 000000000..53adfedf6
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/android_utility/android_utility.h
@@ -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.
+ */
+
+/**
+ * \file android_utility/android_utility.h
+ * \brief Android utility.
+ *
+ * This class relies on a small utility wrapper shipped with the Android
+ * application to access to Java SDK APIs for information not available to
+ * native code.
+ *
+ * For instance, we currently don't have on Linux any mean to get the type
+ * associated to an interface, especially for cellular interfaces. WiFi and
+ * Bluetooth information is for instance available through specific netlink
+ * subsystems, or by means of a support library, but cellular detection mostly
+ * relies on heuristics based on interface names (eg. in network manager).
+ *
+ * Android ship a Radio Interface Layer (RIL) daemon that exposes a control
+ * socket to the Java API to control the radio layer, but there is no working
+ * code exploiting it and no proper documentation.
+ */
+
+#ifndef FACEMGR_INTERFACE_ANDROID_UTILITY_H
+#define FACEMGR_INTERFACE_ANDROID_UTILITY_H
+
+#ifdef __ANDROID__
+
+#include <jni.h>
+
+typedef struct {
+ JavaVM *jvm;
+} android_utility_cfg_t;
+
+#endif /* __ANDROID__ */
+
+#endif /* FACEMGR_INTERFACE_ANDROID_UTILITY_H */
diff --git a/ctrl/facemgr/src/interface_map.h b/ctrl/facemgr/includes/hicn/facemgr.h
index 5930b3001..4165a8fc4 100644
--- a/ctrl/facemgr/src/interface_map.h
+++ b/ctrl/facemgr/includes/hicn/facemgr.h
@@ -13,12 +13,15 @@
* limitations under the License.
*/
-#ifndef INTERFACE_MAP_H
-#define INTERFACE_MAP_H
+/**
+ * \file facemgr.h
+ * \brief Main interface for hICN face manager library
+ */
+#ifndef HICN_FACEMGR_H
+#define HICN_FACEMGR_H
-#include "interface.h"
-#include "util/map.h"
+#include <hicn/policy.h>
+#include <hicn/facemgr/api.h>
-TYPEDEF_MAP_H(interface_map, const char *, interface_t *);
+#endif /* HICN_FACEMGR_H */
-#endif /* INTERFACE_MAP_H */
diff --git a/ctrl/facemgr/includes/hicn/facemgr/api.h b/ctrl/facemgr/includes/hicn/facemgr/api.h
new file mode 100644
index 000000000..c5c29c219
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/facemgr/api.h
@@ -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.
+ */
+
+/**
+ * \file facemgr.h
+ * \brief Face manager library interface
+ */
+#ifndef FACEMGR_H
+#define FACEMGR_H
+
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/ip_address.h>
+#ifdef __ANDROID__
+#include <hicn/android_utility/android_utility.h>
+#endif
+
+/*
+ * \brief Manual overlay settings (alternative to service discovery)
+ */
+
+typedef struct {
+ uint16_t local_port;
+ ip_address_t remote_addr;
+ uint16_t remote_port;
+} facemgr_overlay_setting_t;
+
+#define FACEMGR_OVERLAY_SETTING_EMPTY (facemgr_overlay_setting_t) { \
+ .local_port = 0, \
+ .remote_addr = IP_ADDRESS_EMPTY, \
+ .remote_port = 0, \
+}
+
+typedef struct {
+ facemgr_overlay_setting_t v4;
+ facemgr_overlay_setting_t v6;
+} facemgr_overlay_t;
+
+#define FACEMGR_OVERLAY_EMPTY (facemgr_overlay_t) { \
+ .v4 = FACEMGR_OVERLAY_SETTING_EMPTY, \
+ .v6 = FACEMGR_OVERLAY_SETTING_EMPTY, \
+}
+
+/*
+ * \brief Face manager context
+ */
+typedef struct facemgr_s facemgr_t;
+
+int facemgr_initialize(facemgr_t *);
+int facemgr_finalize(facemgr_t *);
+facemgr_t * facemgr_create();
+facemgr_t * facemgr_create_with_config(facemgr_cfg_t * cfg);
+void facemgr_stop(facemgr_t *);
+void facemgr_free(facemgr_t *);
+
+int facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg);
+int facemgr_reset_config(facemgr_t * facemgr);
+void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop,
+ void * loop_register_fd,
+ void * loop_unregister_event);
+int facemgr_bootstrap(facemgr_t * facemgr);
+#ifdef __ANDROID__
+void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm);
+#endif /* __ANDROID__ */
+
+typedef int (*facemgr_list_faces_cb_t)(face_t * face, void * user_data);
+
+void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data);
+
+#endif /* FACEMGR_H */
diff --git a/ctrl/facemgr/includes/hicn/facemgr/cfg.h b/ctrl/facemgr/includes/hicn/facemgr/cfg.h
new file mode 100644
index 000000000..c121c687f
--- /dev/null
+++ b/ctrl/facemgr/includes/hicn/facemgr/cfg.h
@@ -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.
+ */
+
+/**
+ * \file cfg.h
+ * \brief Face manager configuration
+ */
+#ifndef FACEMGR_CFG_H
+#define FACEMGR_CFG_H
+
+#include <hicn/ctrl/face.h>
+#include <hicn/util/log.h>
+
+/* Face type */
+
+#define foreach_face_type_layer \
+ _(UNDEFINED) \
+ _(3) \
+ _(4) \
+ _(N)
+
+typedef enum {
+#define _(x) FACE_TYPE_LAYER_ ## x,
+ foreach_face_type_layer
+#undef _
+} face_type_layer_t;
+
+#define foreach_face_type_encap \
+ _(UNDEFINED) \
+ _(TCP) \
+ _(UDP) \
+ _(N)
+
+typedef enum {
+#define _(x) FACE_TYPE_ENCAP_ ## x,
+ foreach_face_type_encap
+#undef _
+} face_type_encap_t;
+
+typedef struct {
+ face_type_layer_t layer;
+ face_type_encap_t encap;
+} facemgr_face_type_t;
+
+#define FACEMGR_FACE_TYPE_UNDEFINED (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_UNDEFINED, \
+ .encap = FACE_TYPE_ENCAP_UNDEFINED, \
+}
+
+#define FACEMGR_FACE_TYPE_NATIVE_UDP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_3, \
+ .encap = FACE_TYPE_ENCAP_UDP, \
+}
+
+#define FACEMGR_FACE_TYPE_NATIVE_TCP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_3, \
+ .encap = FACE_TYPE_ENCAP_TCP, \
+}
+
+#define FACEMGR_FACE_TYPE_OVERLAY_UDP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_4, \
+ .encap = FACE_TYPE_ENCAP_UDP, \
+}
+
+#define FACEMGR_FACE_TYPE_OVERLAY_TCP (facemgr_face_type_t) { \
+ .layer = FACE_TYPE_LAYER_4, \
+ .encap = FACE_TYPE_ENCAP_TCP, \
+}
+
+/* Face manager configuration */
+
+#ifdef __ANDROID__
+#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_OVERLAY_UDP
+#else
+#define FACEMGR_FACE_TYPE_DEFAULT FACEMGR_FACE_TYPE_NATIVE_TCP
+#endif /* __ANDROID__ */
+
+#define DEFAULT_FACE_TYPE FACE_TYPE_AUTO
+#define FACEMGR_CFG_DEFAULT_DISCOVERY true
+//#define DEFAULT_IGNORE "lo"
+#define FACEMGR_CFG_DEFAULT_IPV4 true
+#define FACEMGR_CFG_DEFAULT_IPV6 true
+
+
+
+typedef struct facemgr_cfg_s facemgr_cfg_t;
+
+facemgr_cfg_t * facemgr_cfg_create();
+void facemgr_cfg_free(facemgr_cfg_t * cfg);
+int facemgr_cfg_initialize(facemgr_cfg_t * cfg);
+int facemgr_cfg_finalize(facemgr_cfg_t * cfg);
+void facemgr_cfg_dump(facemgr_cfg_t * cfg);
+
+/* Rules */
+
+typedef struct facemgr_cfg_rule_s facemgr_cfg_rule_t;
+
+facemgr_cfg_rule_t * facemgr_cfg_rule_create();
+void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule);
+int facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule);
+int facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule);
+
+int facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule,
+ const char * interface_name, netdevice_type_t interface_type);
+
+int facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * cfg_rule, facemgr_face_type_t * face_type);
+int facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * cfg_rule, bool status);
+int facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * cfg_rule);
+
+int facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port);
+int facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family);
+
+/* General */
+int facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type);
+int facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg);
+int facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status);
+int facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg);
+
+int facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port);
+int facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family);
+
+
+int facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule);
+int facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule);
+int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name,
+ netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule);
+
+/* Log */
+
+/*
+ * Query API
+ *
+ * Takes the overrides into account
+ *
+ * TODO : interface_types are currently not taken into account by this API
+ */
+
+int facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_face_type_t * face_type);
+int facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * discovery);
+int facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ignore);
+int facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv4);
+int facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv6);
+int facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr);
+int facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port);
+int facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr);
+int facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port);
+
+#endif /* FACEMGR_CFG_H */
diff --git a/ctrl/facemgr/src/util/log.h b/ctrl/facemgr/includes/hicn/util/log.h
index f1cafba47..f1cafba47 100644
--- a/ctrl/facemgr/src/util/log.h
+++ b/ctrl/facemgr/includes/hicn/util/log.h
diff --git a/ctrl/facemgr/src/CMakeLists.txt b/ctrl/facemgr/src/CMakeLists.txt
index e7dbda5c1..f99e57e07 100644
--- a/ctrl/facemgr/src/CMakeLists.txt
+++ b/ctrl/facemgr/src/CMakeLists.txt
@@ -20,40 +20,22 @@ set(COMPILER_DEFINITIONS
)
set(HEADER_FILES
-#cache.h
common.h
error.h
- event.h
- face.h
- face_cache.h
- face_rules.h
+ facelet.h
interface.h
- interface_map.h
- interface_ops_map.h
util/hash.h
- util/ip_address.h
- util/log.h
util/map.h
- util/policy.h
util/set.h
- util/token.h
- util/types.h
-
)
set(SOURCE_FILES
-# cache.c
+ api.c
+ cfg.c
error.c
- event.c
- face.c
- face_cache.c
- face_rules.c
+ facelet.c
interface.c
- interface_map.c
- interface_ops_map.c
- facemgr.c
util/log.c
- util/policy.c
)
set(INCLUDE_DIRS
@@ -61,51 +43,82 @@ set(INCLUDE_DIRS
../includes/
${CONFIG_INCLUDE_DIR}
${LIBEVENT_INCLUDE_DIR}
+ ${HICN_INCLUDE_DIRS}
${LIBHICNCTRL_INCLUDE_DIRS}
)
set(LIBRARIES
${CONFIG_LIBRARY}
${LIBEVENT_LIBRARY}
+ ${HICN_LIBRARIES}
${LIBHICNCTRL_LIBRARIES}
)
+
add_subdirectory(interfaces)
-if (ANDROID_API)
- build_library(${FACE_MGR}
+if(WITH_THREAD)
+ set(LIBRARIES
+ ${LIBRARIES}
+ "pthread"
+ "event_pthreads"
+ )
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_THREAD"
+ )
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_EXAMPLE_DUMMY"
+ )
+endif()
+
+if(WITH_EXAMPLE_UPDOWN)
+ set(COMPILER_DEFINITIONS
+ ${COMPILER_DEFINITIONS}
+ "-DWITH_EXAMPLE_UPDOWN"
+ )
+endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Android")
+ build_library(${LIBFACEMGR}
STATIC
SOURCES ${SOURCE_FILES}
INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBRARIES}
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
INSTALL_ROOT_DIR hicn
DEFINITIONS ${COMPILER_DEFINITIONS}
)
else ()
- build_library(${FACE_MGR}
- STATIC NO_DEV
+ build_library(${LIBFACEMGR}
+ SHARED STATIC NO_DEV
SOURCES ${SOURCE_FILES}
INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES}
DEPENDS ${DEPENDENCIES}
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBRARIES}
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
INSTALL_ROOT_DIR hicn
DEFINITIONS ${COMPILER_DEFINITIONS}
)
endif ()
-if(NOT ANDROID_API AND NOT COMPILE_FOR_IOS)
+if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Android" AND NOT COMPILE_FOR_IOS)
list(APPEND DAEMON_SRC
main.c
)
- build_executable(${FACE_MGR}
+ build_executable(${FACEMGR}
SOURCES ${DAEMON_SRC}
- LINK_LIBRARIES ${FACE_MGR}.static ${LIBRARIES}
- DEPENDS ${FACE_MGR}.static
- COMPONENT ${FACE_MGR}
+ LINK_LIBRARIES ${LIBFACEMGR}.static ${LIBRARIES}
+ DEPENDS ${LIBFACEMGR}.static
+ COMPONENT ${FACEMGR}
INCLUDE_DIRS ${INCLUDE_DIRS}
DEFINITIONS ${COMPILER_DEFINITIONS}
)
diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c
new file mode 100644
index 000000000..f630792c4
--- /dev/null
+++ b/ctrl/facemgr/src/api.c
@@ -0,0 +1,1421 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 facemgr.c
+ * \brief Implementation of Face manager library interface
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <hicn/facemgr/api.h>
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/log.h>
+
+#ifdef __APPLE__
+#include "interfaces/network_framework/network_framework.h"
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+#include "interfaces/bonjour/bonjour.h"
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+#include <hicn/android_utility/android_utility.h>
+#endif /* __ANDROID__ */
+
+#include <hicn/ctrl/face.h>
+#include "common.h"
+#include "facelet.h"
+#include "interface.h"
+#include "util/map.h"
+#include "util/set.h"
+
+#define RAND_NAME_LEN 5
+
+#define DEFAULT_PORT 9695
+
+typedef struct {
+ interface_t * interface;
+ void * event;
+} interface_map_data_t;
+
+TYPEDEF_SET_H(facelet_cache, facelet_t *);
+TYPEDEF_SET(facelet_cache, facelet_t *, facelet_cmp, facelet_snprintf);
+
+TYPEDEF_MAP_H(interface_map, const char *, interface_map_data_t *);
+TYPEDEF_MAP(interface_map, const char *, interface_map_data_t *, strcmp, string_snprintf, generic_snprintf);
+
+int int_cmp(int x, int y) { return x - y; }
+
+TYPEDEF_MAP_H(bonjour_map, netdevice_t *, interface_t *);
+TYPEDEF_MAP(bonjour_map, netdevice_t *, interface_t *, netdevice_cmp, generic_snprintf, generic_snprintf);
+
+/* TODO automatically register interfaces */
+
+#ifdef __APPLE__
+extern interface_ops_t network_framework_ops;
+#endif
+#ifdef __linux__
+extern interface_ops_t netlink_ops;
+extern interface_ops_t bonjour_ops;
+#endif
+#ifdef __ANDROID__
+extern interface_ops_t android_utility_ops;
+#endif /* __ANDROID__ */
+#ifdef WITH_EXAMPLE_DUMMY
+extern interface_ops_t dummy_ops;
+#endif
+#ifdef WITH_EXAMPLE_UPDOWN
+extern interface_ops_t updown_ops;
+#endif
+extern interface_ops_t hicn_light_ops;
+
+
+int
+facemgr_overlay_snprintf(char * s, size_t size, const facemgr_overlay_t * overlay)
+{
+ return -1;
+}
+
+struct facemgr_s {
+ /**************************************************/
+ /* Configuration parameters (exposed through API) */
+
+ facemgr_cfg_t * cfg;
+
+#ifdef __ANDROID__
+ /*
+ * Those two pointers are needed to call java functions from the face
+ * manager.
+ */
+ JavaVM *jvm;
+#endif /* __ANDROID__ */
+
+ /* Event loop support */
+ void * loop;
+ void * (*loop_register_fd)(void * loop, int fd, void * cb, void * cb_args);
+ int (*loop_unregister_event)(void * loop, void * event);
+
+ /****************************/
+ /* Internal data structures */
+
+ /* Map of interfaces index by name */
+ interface_map_t interface_map;
+
+ /* Faces under construction */
+ facelet_cache_t facelet_cache;
+
+ /********************************************************/
+ /* Interfaces - Those should be fully replaced by a map */
+
+ interface_t * hl;
+
+#ifdef __ANDROID__
+ interface_t * au; /* android_utility */
+#endif /* __ANDROID__ */
+
+#ifdef __APPLE__
+ interface_t * nf; /* network_framework */
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ interface_t * nl; /* netlink */
+
+ /*
+ * We maintain a map of dynamically created bonjour interfaces, one for each
+ * found netdevice
+ */
+ bonjour_map_t bonjour_map;
+#endif /* __linux__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ interface_t * dummy;
+#endif
+#ifdef WITH_EXAMPLE_UPDOWN
+ interface_t * updown;
+#endif
+};
+
+int
+facemgr_initialize(facemgr_t * facemgr)
+{
+ int rc;
+
+ rc = interface_map_initialize(&facemgr->interface_map);
+ if (rc < 0)
+ goto ERR_INTERFACE_MAP;
+
+ rc = facelet_cache_initialize(&facemgr->facelet_cache);
+ if (rc < 0)
+ goto ERR_FACE_CACHE_PENDING;
+
+#ifdef __linux__
+ rc = bonjour_map_initialize(&facemgr->bonjour_map);
+ if (rc < 0)
+ goto ERR_BJ;
+#endif /* __linux */
+
+ facemgr->cfg = facemgr_cfg_create();
+ if (!facemgr->cfg)
+ goto ERR_CFG;
+
+ return 0;
+
+ERR_CFG:
+#ifdef __linux__
+ bonjour_map_finalize(&facemgr->bonjour_map);
+ERR_BJ:
+#endif /* __linux__ */
+ facelet_cache_finalize(&facemgr->facelet_cache);
+ERR_FACE_CACHE_PENDING:
+ interface_map_finalize(&facemgr->interface_map);
+ERR_INTERFACE_MAP:
+ return -1;
+}
+
+int
+facemgr_finalize(facemgr_t * facemgr)
+{
+ int rc;
+
+ /* TODO Free all interfaces: pass free to map */
+
+ rc = interface_map_finalize(&facemgr->interface_map);
+ if (rc < 0)
+ goto ERR;
+
+ rc = facelet_cache_finalize(&facemgr->facelet_cache);
+ if (rc < 0)
+ goto ERR;
+
+#ifdef __linux__
+ rc = bonjour_map_finalize(&facemgr->bonjour_map);
+ if (rc < 0)
+ goto ERR;
+#endif /* __linux__ */
+
+ return 0;
+
+ERR:
+ return -1;
+}
+
+AUTOGENERATE_CREATE_FREE(facemgr);
+
+int
+facemgr_set_config(facemgr_t * facemgr, facemgr_cfg_t * cfg)
+{
+ if (facemgr->cfg) {
+ facemgr_cfg_free(facemgr->cfg);
+ }
+ facemgr->cfg = cfg;
+ return 0;
+}
+
+int facemgr_reset_config(facemgr_t * facemgr)
+{
+ assert(facemgr->cfg);
+ facemgr_cfg_free(facemgr->cfg);
+ facemgr->cfg = facemgr_cfg_create();
+ if (!facemgr->cfg)
+ return -1;
+ return 0;
+}
+
+facemgr_t *
+facemgr_create_with_config(facemgr_cfg_t * cfg)
+{
+ facemgr_t * facemgr = facemgr_create();
+ if (!facemgr)
+ return NULL;
+ int rc = facemgr_set_config(facemgr, cfg);
+ if (rc < 0) {
+ free(facemgr);
+ return NULL;
+ }
+ return facemgr;
+}
+
+int facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet);
+
+int
+facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface)
+{
+ int fd, rc;
+ void * event = NULL;
+ char rand_name[RAND_NAME_LEN+1];
+ interface_t * interface;
+
+ if (!name) {
+ /*
+ * We can manipulate the name on the stack as it will be strdup'ed by
+ * interface_create
+ */
+ rand_str(rand_name, RAND_NAME_LEN);
+ name = rand_name;
+ }
+
+ INFO("Creating interface %s [%s]...", name, type);
+ interface = interface_create(name, type);
+ if (!interface) {
+ ERROR("Error creating interface %s [%s]", name, type);
+ goto ERR_CREATE;
+ }
+ interface_set_callback(interface, facemgr_on_event, facemgr);
+
+ fd = interface_initialize(interface, cfg);
+ if (fd < 0)
+ goto ERR_INIT;
+ if (fd != 0) {
+ event = facemgr->loop_register_fd(facemgr->loop, fd, interface->ops->callback, interface);
+ if (event == NULL)
+ goto ERR_FD;
+ }
+
+ interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t));
+ if (!interface_map_data)
+ goto ERR_MAP_DATA;
+
+
+ *interface_map_data = (interface_map_data_t) {
+ .interface = interface,
+ .event = event,
+ };
+
+ rc = interface_map_add(&facemgr->interface_map, interface->name, interface_map_data);
+ if (rc < 0)
+ goto ERR_MAP_ADD;
+
+ DEBUG("Interface %s created successfully.", name);
+ if (pinterface)
+ *pinterface = interface;
+ return 0;
+
+ERR_MAP_ADD:
+ free(interface_map_data);
+ERR_MAP_DATA:
+ if (fd > 0)
+ facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event);
+ERR_FD:
+ interface_finalize(interface);
+ERR_INIT:
+ interface_free(interface);
+ERR_CREATE:
+ if (pinterface)
+ *pinterface = NULL;
+ return -1;
+}
+
+int
+facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface)
+{
+ int rc;
+
+ interface_map_data_t * interface_map_data = NULL;
+
+ DEBUG("Removing interface %s\n", interface->name);
+ rc = interface_map_remove(&facemgr->interface_map, interface->name, &interface_map_data);
+ if (rc < 0)
+ return -1;
+
+ if (!interface_map_data)
+ return -1;
+
+ free(interface_map_data);
+
+ rc = facemgr->loop_unregister_event(facemgr->loop, interface_map_data->event);
+ if (rc < 0)
+ return -1;
+
+
+ interface_finalize(interface);
+ interface_free(interface);
+
+ return 0;
+}
+
+#ifdef __linux__
+int facemgr_query_bonjour(facemgr_t * facemgr, netdevice_t * netdevice)
+{
+ interface_t * bj = NULL;
+
+ int rc = bonjour_map_get(&facemgr->bonjour_map, netdevice, &bj);
+ if (rc < 0)
+ return rc;
+
+ if (!bj) {
+ /* Create a new bonjour interface */
+ bonjour_cfg_t bj_cfg = {
+ .netdevice = *netdevice,
+ };
+ rc = facemgr_create_interface(facemgr, NULL, "bonjour", &bj_cfg, &bj);
+ if (rc < 0) {
+ ERROR("Error creating 'Bonjour' interface for '%s'\n", netdevice->name);
+ return -1;
+ }
+ }
+
+ DEBUG("sending event to bonjour interface");
+
+ /* Send an event to the interface (GET ?) */
+ return interface_on_event(bj, NULL);
+}
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+int facemgr_query_android_utility(facemgr_t * facemgr, netdevice_t netdevice)
+{
+ /* Send an event to the interface */
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ int rc = facelet_set_netdevice(facelet, netdevice);
+ if (rc < 0)
+ goto ERR_ND;
+
+ rc = interface_on_event(facemgr->au, facelet);
+ if (rc < 0)
+ goto ERR_EVENT;
+
+ return 0;
+
+ERR_EVENT:
+ERR_ND:
+ facelet_free(facelet);
+ERR_MALLOC:
+ return -1;
+}
+#endif /* __ANDROID__ */
+
+
+/**
+ * \brief Performs a cache lookup to find matching facelets
+ * \param [in] facelet_cache - Facelet cache on which to perform lookup
+ * \param [in] facelet - Facelet to lookup
+ * \param [out] cached_facelet - Pointer used to return a newly allocated
+ * facelet array corresponding to the result of the cache lookup.
+ * \return The number of entries in the array in case of success (positive
+ * value), or -1 in case of error.
+ */
+int
+facelet_cache_lookup(const facelet_cache_t * facelet_cache, facelet_t * facelet,
+ facelet_t ***cached_facelets)
+{
+ /*
+ * If the facelet is uniquely identified by its key, it is used to perform
+ * an efficient lookup directly...
+ */
+ if (facelet_has_key(facelet)) {
+ facelet_t * found = NULL;
+ if (facelet_cache_get(facelet_cache, facelet, &found) < 0) {
+ ERROR("[facelet_cache_lookup] Error during cache lookup");
+ return -1;
+ }
+ if (!found)
+ return 0;
+ *cached_facelets = malloc(sizeof(facelet_t*));
+ *cached_facelets[0] = found;
+ return 1;
+ }
+
+ /* ...otherwise, we iterate over the facelet
+ * cache to find matching elements.
+ */
+ facelet_t ** facelet_array;
+ int n = facelet_cache_get_array(facelet_cache, &facelet_array);
+ if (n < 0) {
+ ERROR("[facelet_cache_lookup] Error during cache match");
+ return -1;
+ }
+ *cached_facelets = malloc(n * sizeof(facelet_t*));
+
+ DEBUG("cache match n = %d", n);
+
+ int num_match = 0;
+ for (unsigned i = 0; i < n; i++) {
+ char buf[128];
+ facelet_snprintf(buf, 128, facelet_array[i]);
+ DEBUG("- facelet_array[%d] %s", i, buf);
+ facelet_snprintf(buf, 128, facelet);
+ DEBUG(" facelet %s", buf);
+
+ DEBUG("match ?");
+ if (!facelet_match(facelet_array[i], facelet)) {
+ DEBUG("no match");
+ continue;
+ }
+ DEBUG("match!");
+ (*cached_facelets)[num_match++] = facelet_array[i];
+ }
+ free(facelet_array);
+ DEBUG("return nummatch=%d", num_match);
+ return num_match;
+}
+
+
+/**
+ * \brief Checks whether the facelet satisfies face creation rules
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet to process
+ * \return 0 in case of success, -2 if we don't have enough information to
+ * decide, -3 if the face does not satisfy rules, and -1 in case of error
+ */
+int
+facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /* As key, netdevice and family should always be present */
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ int family = AF_UNSPEC;
+ if (facelet_has_family(facelet)) {
+ if (facelet_get_family(facelet, &family) < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving family from facelet");
+ return -1;
+ }
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ /* Ignore */
+ bool ignore;
+ if (facemgr_cfg_get_ignore(facemgr->cfg, &netdevice, netdevice_type,
+ &ignore) < 0)
+ return -1;
+ if (ignore) {
+ DEBUG("Ignored interface '%s/%s'...", netdevice.name,
+ netdevice_type_str[netdevice_type]);
+ return -3;
+ }
+
+ /* IPv4 */
+ bool ipv4;
+ if (facemgr_cfg_get_ipv4(facemgr->cfg, &netdevice, netdevice_type,
+ &ipv4) < 0)
+ return -1;
+ if (!ipv4) {
+ DEBUG("Ignored IPv4...");
+ return -3;
+ }
+
+ /* IPv6 */
+ bool ipv6;
+ if (facemgr_cfg_get_ipv6(facemgr->cfg, &netdevice, netdevice_type,
+ &ipv6) < 0)
+ return -1;
+ if (!ipv6) {
+ DEBUG("Ignored IPv6...");
+ return -3;
+ }
+
+ return 0;
+}
+
+#ifdef __ANDROID__
+/**
+ * \brief Complements facelet information through Android Utility interface
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _after_ completion.
+ */
+int
+facemgr_complement_facelet_au(facemgr_t * facemgr, facelet_t * facelet)
+{
+
+ if (facelet_has_netdevice_type(facelet))
+ return -2;
+
+ if (facelet_is_au_done(facelet))
+ return -2;
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ DEBUG("Querying android utility...");
+ facelet_set_au_done(facelet);
+
+ /* /!\ Synchronous code here /!\ */
+ if (facemgr_query_android_utility(facemgr, netdevice) < 0)
+ return -1;
+ return 0;
+}
+#endif /* __ANDROID__ */
+
+#ifdef __linux__
+/**
+ * \brief Complements facelet information through Bonjour interface.
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _before_ completion as bonjour querying is
+ * asynchronous.
+ */
+int
+facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet)
+{
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ bool discovery;
+ if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type,
+ &discovery) < 0)
+ return -2;
+
+ DEBUG("Discovery: %s", discovery ? "ON" : "OFF");
+
+ if (!discovery)
+ return -2;
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facelet_get_face_type(facelet, &face_type) < 0) {
+ ERROR("[facemgr_complement_facelet_bj] Error retrieving face type from facelet");
+ return -1;
+ }
+
+ bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) &&
+ ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet)));
+
+ DEBUG("Discovery needed: %s", discovery ? "ON" : "OFF");
+
+ if (!discovery_needed) {
+ return -2;
+ }
+
+ if (!facelet_has_local_addr(facelet)) {
+ DEBUG("No discovery possible without local address");
+ return -2;
+ }
+
+ if (facelet_is_bj_done(facelet)) {
+ DEBUG("Bonjour already queried");
+ return -2;
+ }
+
+ facelet_set_bj_done(facelet);
+ return facemgr_query_bonjour(facemgr, &netdevice);
+}
+#endif /* __linux__ */
+
+/**
+ * \brief Complements facelet information through Manual settings.
+ * \return 0 if request was successful, -1 in case of error, and -2 if the
+ * interface is not applicable
+ *
+ * This function returnds _before_ completion as bonjour querying is
+ * asynchronous.
+ */
+int
+facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet)
+{
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ int family = AF_UNSPEC;
+ if (facelet_has_family(facelet)) {
+ if (facelet_get_family(facelet, &family) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving family from facelet");
+ return -1;
+ }
+ }
+
+ /* Do not query manual is there is a change to go through bonjour */
+ bool discovery;
+ if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type,
+ &discovery) < 0)
+ return -2;
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facelet_get_face_type(facelet, &face_type) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error retrieving face type from facelet");
+ return -1;
+ }
+
+ bool discovery_needed = (face_type.layer == FACE_TYPE_LAYER_4) &&
+ ((!facelet_has_remote_addr(facelet)) || (!facelet_has_remote_port(facelet)));
+
+ if (!discovery_needed) {
+ DEBUG("manual settings not considered as no discovery is needed");
+ return -2;
+ }
+
+ if (discovery && !facelet_is_bj_done(facelet)) {
+ DEBUG("manual settings not considered as discovery is enabled and Bonjour has not yet been done");
+ return -2;
+ }
+
+ DEBUG("Applying manual settings...");
+ /*
+ * Manual overlay specification (remote addr/port)
+ * We never override a result we have obtained through bonjour
+ */
+ if (!facelet_has_remote_addr(facelet)) {
+ ip_address_t remote_addr;
+ if (facemgr_cfg_get_overlay_remote_addr(facemgr->cfg,
+ &netdevice, netdevice_type, family, &remote_addr) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting remote addr information from cfg");
+ return -1;
+ }
+ if (ip_address_empty(&remote_addr)) {
+ ERROR("[facemgr_complement_facelet_manual] Got empty remote addr information from cfg");
+ } else {
+ DEBUG(" - remote address");
+ facelet_set_remote_addr(facelet, remote_addr);
+ }
+ }
+
+ if (!facelet_has_remote_port(facelet)) {
+ uint16_t remote_port;
+ int rc = facemgr_cfg_get_overlay_remote_port(facemgr->cfg,
+ &netdevice, netdevice_type, family, &remote_port);
+ if (rc < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting remote port information from cfg");
+ return -1;
+ }
+ DEBUG(" - remote port");
+ facelet_set_remote_port(facelet, remote_port);
+ }
+
+ /*
+ * Complementing local addr/port XXX this should be done somewhere
+ * else : manual settings have the lowest priority
+ *
+ * Local IP address is specific as it allows to override the source
+ * address just before creating the face... we would need to check
+ * whether this is an address that belong to us... it might be used
+ * to arbitrate amongst several IP addresses instead...
+ */
+ ip_address_t local_addr;
+ if (facemgr_cfg_get_overlay_local_addr(facemgr->cfg, &netdevice,
+ netdevice_type, family, &local_addr) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting local addr information from cfg");
+ return -1;
+ }
+ if (ip_address_empty(&local_addr)) {
+ ERROR("[facemgr_complement_facelet_manual] Got empty local addr information from cfg");
+ } else {
+ DEBUG(" - local addres");
+ facelet_set_local_addr(facelet, local_addr);
+ }
+
+ /* Sets a default local port, so far nobody sets it */
+ uint16_t local_port;
+ if (facemgr_cfg_get_overlay_local_port(facemgr->cfg,
+ &netdevice, netdevice_type, family, &local_port) < 0) {
+ ERROR("[facemgr_complement_facelet_manual] Error getting local port information from cfg");
+ return -1;
+ }
+ DEBUG(" - local port");
+ facelet_set_local_port(facelet, local_port);
+ return 0;
+}
+
+int
+facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet)
+{
+ int rc;
+
+ if (!facelet_has_key(facelet))
+ return -2;
+
+#ifdef __ANDROID__
+ rc = facemgr_complement_facelet_au(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+#endif /* __ANDROID__ */
+
+ /* We continue only if the current call was not applicable. In the current
+ * setting we have no interface that can be requested in parallel, and no
+ * need to. This might evolve in future releases.
+ */
+
+#ifdef __linux__
+ rc = facemgr_complement_facelet_bj(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+#endif /* __linux__ */
+
+ DEBUG("Complement manual");
+
+ rc = facemgr_complement_facelet_manual(facemgr, facelet);
+ if (rc != -2)
+ return rc;
+
+ INFO("[facemgr_complement_facelet] No more interfaces to query... incomplete face");
+ return 0;
+}
+
+/**
+ * \brief Process facelet CREATE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /*
+ * We create an interface locally, which does not means it should not exist
+ * remotely. Once such codepath is enabled, the two facelets will have been
+ * merged and we need to handle an eventual update on our side.
+ *
+ * In the same way, we need to check for the equivalence of face types etc.
+ */
+ int rc;
+
+ if (facelet_cache_add(&facemgr->facelet_cache, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error adding facelet to cache");
+ return -1;
+ }
+ DEBUG("Facelet added to cache");
+
+ /*
+ * If the facelet does not satisfy filters, we do not lose any information
+ * but do not take any action to complement the face
+ */
+ rc = facemgr_facelet_satisfy_rules(facemgr, facelet);
+ if (rc == -3) {
+ /* Does not satisfy rules */
+ return 0;
+ }
+
+ // FIXME: we should complement a part of the facelet, so that we don't
+ // necessarily keep this information if we get more locally. Or at least we
+ // should remember that.
+ if (rc == -2) {
+ /*
+ * We don't have equivalent for linux right now, heuristic is only used
+ * at the end... might change.
+ */
+#ifdef __ANDROID__
+ /* Priority is given to information that complements a face */
+ if (facemgr_complement_facelet_au(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by rule application");
+ return -1;
+ }
+ return 0;
+#endif /* __ANDROID__ */
+ }
+ if (rc < 0)
+ return -1;
+
+// netdevice_t netdevice = NETDEVICE_EMPTY;
+// if (facelet_get_netdevice(facelet, &netdevice) < 0) {
+// ERROR("[facemgr_process_create] Error retrieving netdevice from facelet");
+// return -1;
+// }
+//
+// netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+//#ifdef __ANDROID__
+// /*
+// * In addition to netdevice, netdevice_type should be present to correctly
+// * apply rules
+// */
+// if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) {
+// ERROR("[facemgr_process_create] Error retrieving netdevice_type from facelet");
+// return -2;
+// }
+//#endif /* __ANDROID__ */
+
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
+ DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s);
+
+ /* Do we have enough information about the facelet ? */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ // we should not stop after complement_manual but create a face if
+ // possible... so we add a second validation
+ }
+
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ /*
+ * Is the forwarder connected, and has the facelet cache already sync'ed the
+ * remote faces ?
+ */
+ // TODO
+
+ /*
+ * Actually create the face on the forwarder
+ *
+ * FIXME Currently hicn-light is hardcoded
+ */
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ return 0;
+}
+
+/**
+ * \brief Process facelet GET event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet)
+{
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ if (facelet_has_netdevice(facelet)) {
+ netdevice_t netdevice;
+ if (facelet_get_netdevice(facelet, &netdevice) < 0)
+ return -1;
+ if (!IS_VALID_NETDEVICE(netdevice))
+ return 0;
+ return facelet_cache_add(&facemgr->facelet_cache, facelet);
+ }
+ return 0;
+}
+
+/**
+ * \brief Process facelet UPDATE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet)
+{
+ /* This is the most complex operation since we have the same problems as in
+ * CREATE + the need to manage changes...
+ *
+ * This might eventually trigger a face deletion...
+ */
+
+ /*
+ * Update in local does not mean the face should not be created remotely as
+ * it might be the first time we have enough information to create it
+ */
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet);
+ DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s);
+
+ /* Sets face type */
+ if (!facelet_has_face_type(facelet)) {
+
+ /* As key, netdevice and family should always be present */
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet");
+ return -1;
+ }
+
+ netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED;
+#ifdef __ANDROID__
+ /*
+ * In addition to netdevice, netdevice_type should be present to correctly
+ * apply rules
+ */
+ rc = facelet_get_netdevice_type(facelet, &netdevice_type);
+ if (rc < 0) {
+ ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet");
+ return -2;
+ }
+#endif /* __ANDROID__ */
+
+ facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+ if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0)
+ return rc;
+ facelet_set_face_type(facelet, face_type);
+ }
+
+ /* Process GET/UDPATE... */
+ switch(facelet_get_status(facelet)) {
+ case FACELET_STATUS_UNDEFINED:
+ ERROR("[facemgr_process_update] Unexpected facelet status");
+ return -1;
+
+ case FACELET_STATUS_DELETED:
+ case FACELET_STATUS_NEW:
+ /*
+ * If the remote action should be a CREATE, then we need to check
+ * whether we have enough information about the face...
+ */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_update] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ }
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ interface_on_event(facemgr->hl, facelet);
+
+ /* This works assuming the call to hicn-light is blocking */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+ case FACELET_STATUS_CLEAN:
+ /* Nothing to do */
+ break;
+
+ case FACELET_STATUS_DIRTY:
+ /*
+ * For now we assume only local changes, and proceed to try and
+ * update the hICN forwarder.
+ *
+ * In case of update, the face exists which means we should already
+ * have enough information
+ */
+ if (!facelet_validate_face(facelet)) {
+ if (facemgr_complement_facelet(facemgr, facelet) < 0) {
+ ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation");
+ return -1;
+ }
+ }
+
+ if (!facelet_validate_face(facelet))
+ return 0;
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+
+ /* This works assuming the call to hicn-light is blocking and we
+ * have proceeded to all udpates */
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ break;
+
+ case FACELET_STATUS_CONFLICT:
+ ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented");
+ return -1;
+ case FACELET_STATUS_N:
+ ERROR("[facemgr_process_update] Facelet in error");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * \brief Process facelet DELETE event
+ * \param [in] facemgr - Pointer to the face manager instance
+ * \param [in] facelet - Pointer to the facelet event to process
+ * \return 0 if everything went correctly, or -1 in case of error.
+ */
+int
+facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet)
+{
+ if (interface_on_event(facemgr->hl, facelet) < 0)
+ return -1;
+
+ facelet_set_status(facelet, FACELET_STATUS_DELETED);
+ //facelet_set_bj_done(facelet, false);
+
+ return 0;
+}
+
+/**
+ * \brief Process incoming events from interfaces
+ *
+ * Implementation notes:
+ * - Any event or timeout due to an interface triggers either a local cache
+ * update, as well a face operations needed to resync the state.
+ */
+int
+facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in)
+{
+ int ret = 0;
+ assert(facelet_in);
+
+ char facelet_s[MAXSZ_FACELET];
+ facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in);
+ DEBUG("----------------------------------");
+ DEBUG("EVENT %s\n", facelet_s);
+
+ facelet_t ** cached_facelets = NULL;
+ int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets);
+ if (n < 0) {
+ ERROR("[facemgr_on_event] Error during cache lookup");
+ goto ERR;
+ }
+ DEBUG("num matches n=%d", n);
+ if (n == 0) {
+ /* This is a new facelet... we expect a CREATE event. */
+ switch(facelet_get_event(facelet_in)) {
+ case FACELET_EVENT_CREATE:
+ if (facemgr_process_create(facemgr, facelet_in) < 0) {
+ ERROR("[facemgr_process_cached_facelet] Error processing CREATE event");
+ goto ERR;
+ }
+ break;
+
+ case FACELET_EVENT_GET:
+ /* Insert new facelet in cached */
+ if (facemgr_process_get(facemgr, facelet_in) < 0) {
+ ERROR("[facemgr_process_cached_facelet] Error processing GET event");
+ goto ERR;
+ }
+ break;
+
+ case FACELET_EVENT_UPDATE:
+ /* Might be because we previously ignored the facelet... */
+ //ERROR("[facemgr_on_event] Unexpected UPDATE... face does not exist");
+ //goto ERR;
+ INFO("Ignored UPDATE for non-existing face");
+ break;
+
+ case FACELET_EVENT_DELETE:
+ ERROR("[facemgr_on_event] Unexpected DELETE... face does not exist");
+ goto ERR;
+
+ case FACELET_EVENT_UNDEFINED:
+ ERROR("[facemgr_on_event] Unexpected UNDEFINED event.");
+ goto ERR;
+
+ default: /* XXX Some events should be deprecated */
+ ERROR("[facemgr_on_event] Deprecated event");
+ goto ERR;
+ }
+ goto DUMP_CACHE;
+ }
+
+ /*
+ * From now on, it should not make any difference whether we have one or
+ * more facelet.
+ */
+ for (unsigned i = 0; i < n; i ++) {
+ /*
+ * We merge each cached facelet with incoming one, and perform state
+ * reconciliation by sending appropriate updates to the forwarder
+ */
+ facelet_t * facelet = cached_facelets[i];
+ DEBUG("... match #%d", i);
+ switch(facelet_get_event(facelet_in)) {
+ case FACELET_EVENT_CREATE:
+ // FIXME, this might occur if the facemgr restarts and we try to
+ // re-create existing faces
+ ERROR("[facemgr_on_event] CREATE event for a face that already exists...");
+ ret = -1;
+ continue;
+
+ case FACELET_EVENT_GET: /* should be an INFORM message */
+ // FIXME, this might occur if the forwarder restarts and we
+ // resync faces...
+ ERROR("[facemgr_on_event] GET event for a face that already exists...");
+ ret = -1;
+ continue;
+
+ case FACELET_EVENT_UPDATE:
+ {
+ DEBUG("FACELET_EVENT_UPDATE");
+ char buf[128];
+ facelet_snprintf(buf, 128, facelet_in);
+ DEBUG("MERGE %s", buf);
+ facelet_snprintf(buf, 128, facelet);
+ DEBUG(" ON %s", buf);
+ }
+ if (facelet_merge(facelet, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error merging facelets");
+ continue;
+ }
+ if (facemgr_process_update(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing UPDATE event");
+ ret = -1;
+ }
+ continue;
+
+ case FACELET_EVENT_DELETE:
+ if (facelet_merge(facelet, facelet_in) < 0) {
+ ERROR("[facemgr_on_event] Error merging facelets");
+ continue;
+ }
+ if (facemgr_process_delete(facemgr, facelet) < 0) {
+ ERROR("[facemgr_on_event] Error processing DELETE event");
+ ret = -1;
+ }
+ continue;
+
+ default: /* XXX Some events should be deprecated */
+ ERROR("[facemgr_on_event] Deprecated event");
+ ret = -1;
+ }
+
+ }
+ free(cached_facelets);
+ goto DUMP_CACHE;
+
+ERR:
+ ret = -1;
+
+DUMP_CACHE:
+ DEBUG(" <CACHE>");
+ facelet_cache_dump(&facemgr->facelet_cache);
+ DEBUG(" </CACHE>");
+ DEBUG("</EVENT ret=%d>", ret);
+ DEBUG("----------------------------------");
+ return ret;
+}
+
+int
+facemgr_bootstrap(facemgr_t * facemgr)
+{
+ int rc;
+
+ DEBUG("Registering interfaces...");
+ rc = interface_register(&hicn_light_ops);
+ if (rc < 0) {
+ ERROR("Could not register interfaces");
+ goto ERR_REGISTER;
+ }
+
+#ifdef __APPLE__
+ rc = interface_register(&network_framework_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ rc = interface_register(&netlink_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+ rc = interface_register(&bonjour_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ rc = interface_register(&android_utility_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif /* __ANDROID__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ rc = interface_register(&dummy_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ rc = interface_register(&updown_ops);
+ if (rc < 0)
+ goto ERR_REGISTER;
+#endif
+
+ rc = facemgr_create_interface(facemgr, "hl", "hicn_light", NULL, &facemgr->hl);
+ if (rc < 0) {
+ ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n");
+ goto ERR_HL_CREATE;
+ }
+
+#ifdef __APPLE__
+ network_framework_cfg_t nf_cfg = {
+ .rules = &facemgr->rules,
+ };
+ rc = facemgr_create_interface(facemgr, "nf", "network_framework", &nf_cfg, &facemgr->nf);
+ if (rc < 0) {
+ ERROR("Error creating 'Apple Network Framework' interface\n");
+ goto ERR_NF_CREATE;
+ }
+#endif /* __APPLE__ */
+
+#ifdef __linux__
+ rc = facemgr_create_interface(facemgr, "nl", "netlink", NULL, &facemgr->nl);
+ if (rc < 0) {
+ ERROR("Error creating 'Netlink' interface\n");
+ goto ERR_NL_CREATE;
+ }
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ android_utility_cfg_t au_cfg = {
+ .jvm = facemgr->jvm,
+ };
+ rc = facemgr_create_interface(facemgr, "au", "android_utility", &au_cfg, &facemgr->au);
+ if (rc < 0) {
+ ERROR("Error creating 'Android Utility' interface\n");
+ goto ERR_AU_CREATE;
+ }
+#endif /* __ANDROID__ */
+
+#ifdef WITH_EXAMPLE_DUMMY
+ rc = facemgr_create_interface(facemgr, "dummy0", "dummy", NULL, &facemgr->dummy);
+ if (rc < 0) {
+ ERROR("Error creating 'dummy' interface\n");
+ goto ERR_DUMMY_CREATE;
+ }
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ rc = facemgr_create_interface(facemgr, "updown0", "updown", NULL, &facemgr->updown);
+ if (rc < 0) {
+ ERROR("Error creating 'updown' interface\n");
+ goto ERR_UPDOWN_CREATE;
+ }
+#endif
+
+ DEBUG("Facemgr successfully initialized...");
+
+ return 0;
+
+ /* FIXME facemgr_delete_interface */
+#ifdef WITH_EXAMPLE_UPDOWN
+ interface_free(facemgr->updown);
+ERR_UPDOWN_CREATE:
+#endif
+#ifdef WITH_EXAMPLE_DUMMY
+ interface_free(facemgr->dummy);
+ERR_DUMMY_CREATE:
+#endif
+#ifdef __ANDROID__
+ interface_free(facemgr->au);
+ERR_AU_CREATE:
+#endif /* __ANDROID__ */
+#ifdef __linux__
+ interface_free(facemgr->nl);
+ERR_NL_CREATE:
+#endif /* __linux__ */
+#ifdef __APPLE__
+ interface_free(facemgr->nf);
+ERR_NF_CREATE:
+#endif /* __APPLE__ */
+ interface_free(facemgr->hl);
+ERR_HL_CREATE:
+ERR_REGISTER:
+ return -1;
+}
+
+void facemgr_stop(facemgr_t * facemgr)
+{
+ // FIXME we should iterate on interface map
+
+#ifdef __APPLE__
+ facemgr_delete_interface(facemgr, facemgr->nf);
+#endif /* __APPLE__ */
+
+
+#ifdef __linux__
+ facemgr_delete_interface(facemgr, facemgr->nl);
+
+ /* Delete all bonjour interfaces */
+ interface_t ** bonjour_array;// = NULL; // NOTE: would allow avoiding tests
+ int n = bonjour_map_get_value_array(&facemgr->bonjour_map, &bonjour_array);
+ if (n > 0) {
+ netdevice_t ** netdevice_array; // = NULL;
+ int m = bonjour_map_get_key_array(&facemgr->bonjour_map, &netdevice_array);
+ if (m > 0) {
+ assert(m == n);
+ for (int i = 0; i < n; i++) { /* Fail silently */
+ DEBUG("Deleting bonjour interface associated to %s (%p)\n",
+ netdevice_array[i]->name, bonjour_array[i]);
+ facemgr_delete_interface(facemgr, bonjour_array[i]);
+ }
+ free(netdevice_array);
+ }
+ free(bonjour_array);
+ }
+#endif /* __linux__ */
+
+#ifdef __ANDROID__
+ facemgr_delete_interface(facemgr, facemgr->au);
+#endif /* __ANDROID__ */
+
+ facemgr_delete_interface(facemgr, facemgr->hl);
+
+#ifdef WITH_EXAMPLE_DUMMY
+ facemgr_delete_interface(facemgr, facemgr->dummy);
+#endif
+
+#ifdef WITH_EXAMPLE_UPDOWN
+ facemgr_delete_interface(facemgr, facemgr->updown);
+#endif
+}
+
+#ifdef __ANDROID__
+void facemgr_set_jvm(facemgr_t * facemgr, JavaVM *jvm)
+{
+ facemgr->jvm = jvm;
+}
+#endif /* __ANDROID__ */
+
+void facemgr_set_event_loop_handler(facemgr_t * facemgr, void * loop, void * loop_register_fd, void * loop_unregister_event)
+{
+ facemgr->loop = loop;
+ facemgr->loop_register_fd = loop_register_fd;
+ facemgr->loop_unregister_event = loop_unregister_event;
+}
+
+void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data)
+{
+ //face_cache_iter(&facemgr->face_cache, cb, user_data);
+ facelet_cache_dump(&facemgr->facelet_cache);
+}
diff --git a/ctrl/facemgr/src/cfg.c b/ctrl/facemgr/src/cfg.c
new file mode 100644
index 000000000..6b04208bb
--- /dev/null
+++ b/ctrl/facemgr/src/cfg.c
@@ -0,0 +1,991 @@
+/**
+ * \file cfg.c
+ * \brief Implementation of Face manager configuration
+ */
+
+#include <assert.h>
+#include <hicn/ctrl.h> // HICN_DEFAULT_PORT
+#include <hicn/facemgr/cfg.h>
+#include <hicn/policy.h>
+#include <hicn/util/ip_address.h>
+#include "util/set.h"
+
+/* Overlay */
+
+typedef struct {
+ bool is_local_port;
+ uint16_t local_port;
+ bool is_local_addr;
+ ip_address_t local_addr;
+ bool is_remote_port;
+ uint16_t remote_port;
+ bool is_remote_addr;
+ ip_address_t remote_addr;
+} facemgr_cfg_overlay_t;
+
+int
+facemgr_cfg_overlay_initialize(facemgr_cfg_overlay_t * overlay)
+{
+ overlay->is_local_port = false;
+ overlay->local_port = 0;
+ overlay->is_local_addr = false;
+ overlay->local_addr = IP_ADDRESS_EMPTY;
+
+ overlay->is_remote_port = false;
+ overlay->remote_port = 0;
+ overlay->is_remote_addr = false;
+ overlay->remote_addr = IP_ADDRESS_EMPTY;
+
+ return 0;
+}
+
+int
+facemgr_cfg_overlay_finalize(facemgr_cfg_overlay_t * overlay)
+{
+ return 0;
+}
+
+facemgr_cfg_overlay_t * facemgr_cfg_overlay_create()
+{
+ facemgr_cfg_overlay_t * overlay = malloc(sizeof(facemgr_cfg_overlay_t));
+ if (!overlay)
+ return NULL;
+
+ int rc = facemgr_cfg_overlay_initialize(overlay);
+ if (rc < 0) {
+ free(overlay);
+ return NULL;
+ }
+
+ return overlay;
+}
+
+void facemgr_cfg_overlay_free(facemgr_cfg_overlay_t * overlay)
+{
+ facemgr_cfg_overlay_finalize(overlay);
+ free(overlay);
+}
+
+typedef struct {
+ facemgr_cfg_overlay_t * v4;
+ facemgr_cfg_overlay_t * v6;
+} facemgr_cfg_overlays_t;
+
+typedef struct {
+ const char * interface_name;
+ netdevice_type_t interface_type;
+} facemgr_cfg_match_t;
+
+
+typedef struct {
+ /* Interface specific */
+ bool is_face_type; // default is auto
+ facemgr_face_type_t face_type;
+
+ /* This should be defaut for the global settings */
+ bool is_ignore;
+ bool ignore;
+ bool is_discovery;
+ bool discovery;
+ bool is_ipv4;
+ bool ipv4;
+ bool is_ipv6;
+ bool ipv6;
+
+ facemgr_cfg_overlays_t overlays; // fallback unless discovery is disabled
+} facemgr_cfg_override_t;
+
+struct facemgr_cfg_rule_s {
+ facemgr_cfg_match_t match;
+ facemgr_cfg_override_t override;
+};
+
+int
+facemgr_cfg_override_initialize(facemgr_cfg_override_t * override)
+{
+ override->is_face_type = false;
+ override->face_type = FACEMGR_FACE_TYPE_UNDEFINED;
+
+ override->is_ignore = false;
+ override->ignore = false;
+
+ override->is_discovery = false;
+ override->discovery = false;
+
+ override->overlays.v4 = NULL;
+ override->overlays.v6 = NULL;
+
+ return 0;
+}
+
+int
+facemgr_cfg_override_finalize(facemgr_cfg_override_t * override)
+{
+ if (override->overlays.v4) {
+ facemgr_cfg_overlay_free(override->overlays.v4);
+ override->overlays.v4 = NULL;
+ }
+ if (override->overlays.v6) {
+ facemgr_cfg_overlay_free(override->overlays.v6);
+ override->overlays.v6 = NULL;
+ }
+
+ return 0;
+}
+
+
+/* Rule */
+facemgr_cfg_rule_t * facemgr_cfg_rule_create()
+{
+ facemgr_cfg_rule_t * rule = malloc(sizeof(facemgr_cfg_rule_t));
+ if (!rule)
+ return NULL;
+
+ int rc = facemgr_cfg_rule_initialize(rule);
+ if (rc < 0)
+ return NULL;
+
+ return rule;
+}
+
+void facemgr_cfg_rule_free(facemgr_cfg_rule_t * rule)
+{
+ facemgr_cfg_rule_finalize(rule);
+ free(rule);
+}
+
+int
+facemgr_cfg_rule_initialize(facemgr_cfg_rule_t * rule)
+{
+ rule->match.interface_name = NULL;
+ rule->match.interface_type = NETDEVICE_TYPE_UNDEFINED;
+
+ int rc = facemgr_cfg_override_initialize(&rule->override);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int
+facemgr_cfg_rule_finalize(facemgr_cfg_rule_t * rule)
+{
+ if (rule->match.interface_name) {
+ free((void*)rule->match.interface_name);
+ rule->match.interface_name = NULL;
+ }
+ return facemgr_cfg_override_finalize(&rule->override);
+}
+
+void
+facemgr_cfg_rule_dump(facemgr_cfg_rule_t * rule)
+{
+ DEBUG(" <rule>");
+ DEBUG(" <match interface_name=%s interface_type=%s>",
+ rule->match.interface_name,
+ netdevice_type_str[rule->match.interface_type]);
+ DEBUG(" <override>");
+ if (rule->override.is_face_type) {
+ DEBUG(" <face_type>%d</face_type>", rule->override.face_type);
+ }
+ if (rule->override.is_ignore) {
+ DEBUG(" <ignore>%d</ignore>", rule->override.ignore);
+ }
+ if (rule->override.is_discovery) {
+ DEBUG(" <discovery>%d</discovery>", rule->override.discovery);
+ }
+ if (rule->override.is_ipv4) {
+ DEBUG(" <ipv4>%d</ipv4>", rule->override.ipv4);
+ }
+ if (rule->override.is_ipv6) {
+ DEBUG(" <ipv6>%d</ipv6>", rule->override.ipv6);
+ }
+ DEBUG(" <overlays>");
+ if (rule->override.overlays.v4) {
+ DEBUG(" <ipv4>");
+ if (rule->override.overlays.v4->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v4->local_addr, AF_INET);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (rule->override.overlays.v4->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ rule->override.overlays.v4->local_port);
+ }
+ if (rule->override.overlays.v4->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v4->remote_addr, AF_INET);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (rule->override.overlays.v4->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ rule->override.overlays.v4->remote_port);
+ }
+ DEBUG(" </ipv4>");
+ }
+ if (rule->override.overlays.v6) {
+ DEBUG(" <ipv6>");
+ if (rule->override.overlays.v6->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v6->local_addr, AF_INET6);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (rule->override.overlays.v6->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ rule->override.overlays.v6->local_port);
+ }
+ if (rule->override.overlays.v6->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &rule->override.overlays.v6->remote_addr, AF_INET6);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (rule->override.overlays.v6->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ rule->override.overlays.v6->remote_port);
+ }
+ DEBUG(" </ipv6>");
+ }
+ DEBUG(" </overlays>");
+ DEBUG(" </override>");
+ DEBUG(" </rule>");
+}
+
+int
+facemgr_cfg_rule_set_match(facemgr_cfg_rule_t * rule, const char * interface_name,
+ netdevice_type_t interface_type)
+{
+ rule->match.interface_name = interface_name ? strdup(interface_name) : NULL;
+ rule->match.interface_type = interface_type;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_face_type(facemgr_cfg_rule_t * rule, facemgr_face_type_t * face_type)
+{
+ rule->override.is_face_type = true;
+ rule->override.face_type = *face_type;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_face_type(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_face_type = false;
+ rule->override.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_discovery(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_discovery = true;
+ rule->override.discovery = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_discovery(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_discovery = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ignore(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ignore = true;
+ rule->override.ignore = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ignore(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ignore = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ipv4(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ipv4 = true;
+ rule->override.ipv4 = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ipv4(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ipv4 = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_ipv6(facemgr_cfg_rule_t * rule, bool status)
+{
+ rule->override.is_ipv6 = true;
+ rule->override.ipv6 = status;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_unset_ipv6(facemgr_cfg_rule_t * rule)
+{
+ rule->override.is_ipv6 = false;
+ return 0;
+}
+
+int
+facemgr_cfg_rule_set_overlay(facemgr_cfg_rule_t * rule, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port) {
+ if ((family != AF_INET) && (family != AF_INET6))
+ return -1;
+
+ facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create();
+ if (local_addr) {
+ overlay->is_local_addr = true;
+ overlay->local_addr = *local_addr;
+ }
+ if (IS_VALID_PORT(local_port)) {
+ overlay->is_local_port = true;
+ overlay->local_port = local_port;
+ }
+ if (remote_addr) {
+ overlay->is_remote_addr = true;
+ overlay->remote_addr = *remote_addr;
+ }
+ if (IS_VALID_PORT(remote_port)) {
+ overlay->is_remote_port = true;
+ overlay->remote_port = remote_port;
+ }
+
+ switch(family) {
+ case AF_INET:
+ rule->override.overlays.v4 = overlay;
+ break;
+
+ case AF_INET6:
+ rule->override.overlays.v6 = overlay;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+facemgr_rule_unset_overlay(facemgr_cfg_rule_t * rule, int family)
+{
+ if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC))
+ return -1;
+
+ if ((family == AF_UNSPEC) || (family == AF_INET)) {
+ if (rule->override.overlays.v4) {
+ facemgr_cfg_overlay_free(rule->override.overlays.v4);
+ rule->override.overlays.v4 = NULL;
+ }
+ }
+ if ((family == AF_UNSPEC) || (family == AF_INET6)) {
+ if (rule->override.overlays.v6) {
+ facemgr_cfg_overlay_free(rule->override.overlays.v6);
+ rule->override.overlays.v6 = NULL;
+ }
+ }
+ return 0;
+}
+
+int
+facemgr_cfg_rule_cmp(const facemgr_cfg_rule_t * r1, const facemgr_cfg_rule_t * r2)
+{
+ /*
+ * We implement a lexicographic order on the tuple (interface_name,
+ * interface_type)
+ */
+
+ /* We need to handle NULL cases out of strcmp */
+ if (!r1->match.interface_name) {
+ if (r2->match.interface_name)
+ return 1;
+ else
+ goto BOTH_NULL;
+ } else {
+ if (!r2->match.interface_name)
+ return -1;
+ }
+
+
+ /* Only if both are non-NULL, we proceed to strcmp */
+ int rc = strcmp(r1->match.interface_name, r2->match.interface_name);
+ if (rc != 0)
+ return rc;
+
+BOTH_NULL:
+ return r1->match.interface_type - r2->match.interface_type;
+}
+
+/* General */
+
+TYPEDEF_SET_H(facemgr_cfg_rule_set, facemgr_cfg_rule_t *);
+TYPEDEF_SET(facemgr_cfg_rule_set, facemgr_cfg_rule_t *, facemgr_cfg_rule_cmp, generic_snprintf);
+
+struct facemgr_cfg_s {
+ facemgr_cfg_override_t global;
+ facemgr_cfg_rule_set_t * rule_set;
+ //log_cfg_t log;
+};
+
+facemgr_cfg_t * facemgr_cfg_create()
+{
+ facemgr_cfg_t * cfg = malloc(sizeof(facemgr_cfg_t));
+ if (!cfg)
+ return NULL;
+
+ int rc = facemgr_cfg_initialize(cfg);
+ if (rc < 0) {
+ free(cfg);
+ return NULL;
+ }
+
+ return cfg;
+}
+
+void facemgr_cfg_free(facemgr_cfg_t * cfg)
+{
+ facemgr_cfg_finalize(cfg);
+ free(cfg);
+}
+
+int
+facemgr_cfg_initialize(facemgr_cfg_t * cfg)
+{
+ int rc = facemgr_cfg_override_initialize(&cfg->global);
+ if (rc < 0)
+ goto ERR_OVERRIDE;
+
+ cfg->rule_set = facemgr_cfg_rule_set_create();
+ if (!cfg->rule_set)
+ goto ERR_RULE_SET;
+
+ return 0;
+
+ERR_RULE_SET:
+ facemgr_cfg_override_finalize(&cfg->global);
+ERR_OVERRIDE:
+ return -1;
+}
+
+int
+facemgr_cfg_finalize(facemgr_cfg_t * cfg)
+{
+ /* TODO Free all rules */
+ facemgr_cfg_rule_set_free(cfg->rule_set);
+ return facemgr_cfg_override_finalize(&cfg->global);
+}
+
+void facemgr_cfg_dump(facemgr_cfg_t * cfg)
+{
+ return; /* NOT IMPLEMENTED */
+}
+
+/* General */
+int
+facemgr_cfg_set_face_type(facemgr_cfg_t * cfg, facemgr_face_type_t * face_type)
+{
+ cfg->global.is_face_type = true;
+ cfg->global.face_type = *face_type;
+ return 0;
+}
+
+int
+facemgr_cfg_unset_face_type(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_face_type = false;
+ cfg->global.face_type = FACEMGR_FACE_TYPE_UNDEFINED; /* optional */
+ return 0;
+}
+
+int
+facemgr_cfg_set_discovery(facemgr_cfg_t * cfg, bool status)
+{
+ cfg->global.is_discovery = true;
+ cfg->global.discovery = status;
+ return 0;
+}
+
+int
+facemgr_cfg_unset_discovery(facemgr_cfg_t * cfg)
+{
+ cfg->global.is_discovery = false;
+ return 0;
+}
+
+int
+facemgr_cfg_set_overlay(facemgr_cfg_t * cfg, int family,
+ ip_address_t * local_addr, uint16_t local_port,
+ ip_address_t * remote_addr, uint16_t remote_port)
+{
+ if ((family != AF_INET) && (family != AF_INET6))
+ return -1;
+
+ facemgr_cfg_overlay_t * overlay = facemgr_cfg_overlay_create();
+ if (local_addr) {
+ overlay->is_local_addr = true;
+ overlay->local_addr = *local_addr;
+ }
+ if (IS_VALID_PORT(local_port)) {
+ overlay->is_local_port = true;
+ overlay->local_port = local_port;
+ }
+ if (remote_addr) {
+ overlay->is_remote_addr = true;
+ overlay->remote_addr = *remote_addr;
+ }
+ if (IS_VALID_PORT(remote_port)) {
+ overlay->is_remote_port = true;
+ overlay->remote_port = remote_port;
+ }
+
+ DEBUG("facemgr_cfg_set_overlay");
+
+ switch(family) {
+ case AF_INET:
+ cfg->global.overlays.v4 = overlay;
+ break;
+
+ case AF_INET6:
+ cfg->global.overlays.v6 = overlay;
+ break;
+
+ default:
+ return -1;
+ }
+
+ DEBUG("<global>");
+ DEBUG(" <overlay>");
+ if (overlay) {
+ DEBUG(" <ipv4>");
+ if (overlay->is_local_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &overlay->local_addr, AF_INET);
+ DEBUG(" <local_addr>%s</local_addr>", buf);
+ }
+ if (overlay->is_local_port) {
+ DEBUG(" <local_port>%d</local_port>",
+ overlay->local_port);
+ }
+ if (overlay->is_remote_addr) {
+ char buf[MAXSZ_IP_ADDRESS];
+ ip_address_snprintf(buf, MAXSZ_IP_ADDRESS,
+ &overlay->remote_addr, AF_INET);
+ DEBUG(" <remote_addr>%s</remote_addr>", buf);
+ }
+ if (overlay->is_remote_port) {
+ DEBUG(" <remote_port>%d</remote_port>",
+ overlay->remote_port);
+ }
+ DEBUG(" </ipv4>");
+ }
+ DEBUG(" </overlay>");
+ DEBUG("</global>");
+
+ return 0;
+}
+
+int
+facemgr_cfg_unset_overlay(facemgr_cfg_t * cfg, int family)
+{
+ if ((family != AF_INET) && (family != AF_INET6) && (family != AF_UNSPEC))
+ return -1;
+
+ if ((family == AF_UNSPEC) || (family == AF_INET)) {
+ if (cfg->global.overlays.v4) {
+ facemgr_cfg_overlay_free(cfg->global.overlays.v4);
+ cfg->global.overlays.v4 = NULL;
+ }
+ }
+ if ((family == AF_UNSPEC) || (family == AF_INET6)) {
+ if (cfg->global.overlays.v6) {
+ facemgr_cfg_overlay_free(cfg->global.overlays.v6);
+ cfg->global.overlays.v6 = NULL;
+ }
+ }
+ return 0;
+}
+
+int
+facemgr_cfg_add_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule)
+{
+ facemgr_cfg_rule_dump(rule);
+ return facemgr_cfg_rule_set_add(cfg->rule_set, rule);
+}
+
+int
+facemgr_cfg_del_rule(facemgr_cfg_t * cfg, facemgr_cfg_rule_t * rule)
+{
+ return facemgr_cfg_rule_set_remove(cfg->rule_set, rule, NULL);
+}
+
+int facemgr_cfg_get_rule(const facemgr_cfg_t * cfg, const char * interface_name,
+ netdevice_type_t interface_type, facemgr_cfg_rule_t ** rule) {
+ facemgr_cfg_rule_t rule_search = {
+ .match = {
+ .interface_name = interface_name,
+ .interface_type = interface_type,
+ },
+ };
+ return facemgr_cfg_rule_set_get(cfg->rule_set, &rule_search, rule);
+}
+
+/* Query API */
+
+/*
+ * Check whether there are override rules for the given netdevice
+ *
+ * TODO:
+ * - until we have proper indexes we loop through the whole structure
+ */
+int
+facemgr_cfg_get_override(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_cfg_override_t ** override)
+{
+ if (!netdevice) {
+ *override = NULL;
+ return 0;
+ }
+
+ facemgr_cfg_rule_t **rule_array;
+ int rc = facemgr_cfg_rule_set_get_array(cfg->rule_set, &rule_array);
+ if (rc < 0) {
+ ERROR("facemgr_cfg_rule_set_get_array failed");
+ return rc;
+ }
+ for (unsigned i = 0; i < rc; i++) {
+ const char * interface_name = rule_array[i]->match.interface_name;
+ /* Check match for interface name */
+ if (interface_name && (strcmp(interface_name, netdevice->name) != 0))
+ continue;
+ /* Check match for interface type */
+ if (rule_array[i]->match.interface_type != NETDEVICE_TYPE_UNDEFINED) {
+#ifdef __ANDROID__
+ if (netdevice_type != rule_array[i]->match.interface_type)
+ continue;
+#else
+ ERROR("Match on interface type is currently not implemented");
+ goto ERR_ARRAY;
+#endif /* __ANDROID__ */
+ }
+ /* Found match... do we have an override for face_type */
+ DEBUG("override found nd=%s, ndt=%s", rule_array[i]->match.interface_name, netdevice_type_str[rule_array[i]->match.interface_type]);
+ *override = &rule_array[i]->override;
+ goto FOUND;
+ }
+
+ DEBUG("override not found");
+ *override = NULL;
+
+FOUND:
+ free(rule_array);
+ return 0;
+
+#ifndef __ANDROID__
+ERR_ARRAY:
+ free(rule_array);
+ return -1;
+#endif /* __ANDROID__ */
+}
+
+int
+facemgr_cfg_get_face_type(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ facemgr_face_type_t * face_type)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0) {
+ ERROR("get override failed");
+ return rc;
+ }
+
+ if ((override) && (override->is_face_type)) {
+ *face_type = override->face_type;
+ return 0;
+ }
+
+ *face_type = cfg->global.is_face_type
+ ? cfg->global.face_type
+ : FACEMGR_FACE_TYPE_DEFAULT;
+
+ return 0;
+}
+
+int
+facemgr_cfg_get_discovery(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * discovery)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_discovery)) {
+ *discovery = override->discovery;
+ return 0;
+ }
+
+ *discovery = cfg->global.is_discovery
+ ? cfg->global.discovery
+ : FACEMGR_CFG_DEFAULT_DISCOVERY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ipv4(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv4)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ipv4)) {
+ *ipv4 = override->ipv4;
+ return 0;
+ }
+
+ *ipv4 = cfg->global.is_ipv4
+ ? cfg->global.ipv4
+ : FACEMGR_CFG_DEFAULT_IPV4;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ipv6(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ipv6)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ipv6)) {
+ *ipv6 = override->ipv6;
+ return 0;
+ }
+
+ *ipv6 = cfg->global.is_ipv6
+ ? cfg->global.ipv6
+ : FACEMGR_CFG_DEFAULT_IPV6;
+ return 0;
+}
+
+int
+facemgr_cfg_get_ignore(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ bool * ignore)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ if ((override) && (override->is_ignore)) {
+ *ignore = override->ignore;
+ return 0;
+ }
+
+ assert (!cfg->global.is_ignore);
+
+ *ignore = (netdevice && (netdevice->name[0] != '\0') && strcmp(netdevice->name, "lo") == 0);
+
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_local_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_addr)) {
+ *addr = override->overlays.v4->local_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_addr)) {
+ *addr = cfg->global.overlays.v4->local_addr;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_addr)) {
+ *addr = override->overlays.v6->local_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_addr)) {
+ *addr = cfg->global.overlays.v6->local_addr;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *addr = IP_ADDRESS_EMPTY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_local_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_local_port)) {
+ *port = override->overlays.v4->local_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_local_port)) {
+ *port = cfg->global.overlays.v4->local_port;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_local_port)) {
+ *port = override->overlays.v6->local_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_local_port)) {
+ *port = cfg->global.overlays.v6->local_port;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *port = HICN_DEFAULT_PORT;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_remote_addr(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, ip_address_t * addr)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_addr)) {
+ DEBUG("remote addr v4 from override");
+ *addr = override->overlays.v4->remote_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_addr)) {
+ DEBUG("remote addr v4 from global");
+ *addr = cfg->global.overlays.v4->remote_addr;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_addr)) {
+ DEBUG("remote addr v6 from override");
+ *addr = override->overlays.v6->remote_addr;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_addr)) {
+ DEBUG("remote addr v6 from global");
+ *addr = cfg->global.overlays.v6->remote_addr;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ DEBUG("remote addr empty");
+ *addr = IP_ADDRESS_EMPTY;
+ return 0;
+}
+
+int
+facemgr_cfg_get_overlay_remote_port(const facemgr_cfg_t * cfg,
+ const netdevice_t * netdevice, netdevice_type_t netdevice_type,
+ int family, u16 * port)
+{
+ facemgr_cfg_override_t * override;
+ int rc = facemgr_cfg_get_override(cfg, netdevice, netdevice_type,
+ &override);
+ if (rc < 0)
+ return rc;
+
+ switch (family) {
+ case AF_INET:
+ if ((override) && (override->overlays.v4) && (override->overlays.v4->is_remote_port)) {
+ *port = override->overlays.v4->remote_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v4) && (cfg->global.overlays.v4->is_remote_port)) {
+ *port = cfg->global.overlays.v4->remote_port;
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if ((override) && (override->overlays.v6) && (override->overlays.v6->is_remote_port)) {
+ *port = override->overlays.v6->remote_port;
+ return 0;
+ }
+ if ((cfg->global.overlays.v6) && (cfg->global.overlays.v6->is_remote_port)) {
+ *port = cfg->global.overlays.v6->remote_port;
+ return 0;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ default:
+ return -1;
+ }
+
+ *port = HICN_DEFAULT_PORT;
+ return 0;
+}
diff --git a/ctrl/facemgr/src/common.h b/ctrl/facemgr/src/common.h
index a73964b6d..9d6e8ca87 100644
--- a/ctrl/facemgr/src/common.h
+++ b/ctrl/facemgr/src/common.h
@@ -22,18 +22,12 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
-#include "util/types.h"
-#include "util/ip_address.h"
-#include "util/token.h" // XXX debug
+#include <hicn/util/ip_address.h>
//#define DEBUG
-/* Return value conventions */
-#define FACEMGR_SUCCESS 0
-#define FACEMGR_FAILURE -1
-#define FACEMGR_IS_ERROR(rc) (rc < 0)
-
/* Useful types and macros for comparisons */
typedef int(*cmp_t)(const void * x, const void * y);
@@ -43,18 +37,35 @@ typedef int(*cmp_t)(const void * x, const void * y);
#define INDENT(n, fmt) "%*s" fmt, n, ""
#define printfi(n, fmt, ...) printf(INDENT(n*4, fmt), ##__VA_ARGS__)
+#define _unused(x) ((void)(x))
+
+/* Random strings */
+
+static inline
+void rand_str(char *dest, size_t length) {
+ char charset[] = "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ while (length-- > 0) {
+ size_t index = (double) rand() / RAND_MAX * (sizeof charset - 1);
+ *dest++ = charset[index];
+ }
+ *dest = '\0';
+}
+
/* Boilerplate code */
#define NO_INITIALIZE(NAME) \
int \
NAME ## _initialize(NAME ## _t * obj) { \
- return FACEMGR_SUCCESS; \
+ return 0; \
}
#define NO_FINALIZE(NAME) \
int \
NAME ## _finalize(NAME ## _t * obj) { \
- return FACEMGR_SUCCESS; \
+ return 0; \
}
#define AUTOGENERATE_CREATE_FREE(NAME) \
@@ -66,7 +77,7 @@ NAME ## _create() \
if (!obj) \
goto ERR_MALLOC; \
\
- if (FACEMGR_IS_ERROR(NAME ## _initialize(obj))) \
+ if (NAME ## _initialize(obj) < 0) \
goto ERR_INIT; \
\
return obj; \
@@ -80,7 +91,7 @@ ERR_MALLOC: \
void \
NAME ## _free(NAME ## _t * obj) \
{ \
- if (FACEMGR_IS_ERROR(NAME ## _finalize(obj))) \
+ if (NAME ## _finalize(obj) < 0) \
(void)0; /* XXX */ \
free(obj); \
} \
diff --git a/ctrl/facemgr/src/event.c b/ctrl/facemgr/src/event.c
deleted file mode 100644
index 446c51c22..000000000
--- a/ctrl/facemgr/src/event.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 event.h
- * \brief Implementatino of face events
- */
-
-#include "common.h"
-#include "event.h"
-#include "interface.h"
-#include "util/token.h"
-
-const char * event_type_str[] = {
-#define _(x) [EVENT_TYPE_ ## x] = STRINGIZE(x),
-foreach_event_type
-#undef _
-};
-
-int
-event_raise(event_type_t type, const face_t * face, const interface_t * interface)
-{
- event_t event = { .type = type, .face = face };
- if (interface->callback)
- interface->callback(interface->callback_data, &event);
- return FACEMGR_SUCCESS;
-}
diff --git a/ctrl/facemgr/src/event.h b/ctrl/facemgr/src/event.h
deleted file mode 100644
index 53295d009..000000000
--- a/ctrl/facemgr/src/event.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 event.h
- * \brief Face event
- */
-#ifndef FACEMGR_EVENT_H
-#define FACEMGR_EVENT_H
-
-#include "face.h"
-#include "interface.h"
-
-#define foreach_event_type \
- _(UNDEFINED) \
- _(CREATE) \
- _(UPDATE) \
- _(DELETE) \
- _(SET_PARAMS) \
- _(SET_UP) \
- _(SET_DOWN) \
- _(SET_TAGS) \
- _(CLEAR_TAGS) \
- _(ADD_TAG) \
- _(REMOVE_TAG) \
- _(N)
-
-#define MAXSZ_EVENT_TYPE_ 10
-#define MAXSZ_EVENT_TYPE MAXSZ_EVENT_TYPE_ + 1
-
-typedef enum {
-#define _(x) EVENT_TYPE_ ## x,
-foreach_event_type
-#undef _
-} event_type_t;
-
-extern const char * event_type_str[];
-
-typedef struct event_s {
- event_type_t type;
- const face_t * face; /* + bitfield for face fields ? */
-} event_t;
-
-int
-event_raise(event_type_t type, const face_t * face, const interface_t * interface);
-
-#endif /* FACEMGR_EVENT_H */
diff --git a/ctrl/facemgr/src/face.c b/ctrl/facemgr/src/face.c
deleted file mode 100644
index 270a6fa9f..000000000
--- a/ctrl/facemgr/src/face.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 face.c
- * \brief Implementation of face abstraction
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "face.h"
-#include "util/hash.h"
-#include "util/token.h"
-
-#ifndef bzero
-#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
-#endif
-
-#define member_size(type, member) sizeof(((type *)0)->member)
-
-
-/* Netdevice */
-
-const char * netdevice_type_str[] = {
-#define _(x) [NETDEVICE_TYPE_ ## x] = STRINGIZE(x),
-foreach_netdevice_type
-#undef _
-};
-
-
-/* Face state */
-
-const char * face_state_str[] = {
-#define _(x) [FACE_STATE_ ## x] = STRINGIZE(x),
-foreach_face_state
-#undef _
-};
-
-
-/* Face type */
-
-const char * face_type_str[] = {
-#define _(x) [FACE_TYPE_ ## x] = STRINGIZE(x),
-foreach_face_type
-#undef _
-};
-
-
-/* Face */
-
-int
-face_initialize(face_t * face)
-{
- bzero(face, sizeof(face_t)); /* 0'ed for hash */
- return 1;
-}
-
-int
-face_initialize_udp(face_t * face, const ip_address_t * local_addr,
- u16 local_port, const ip_address_t * remote_addr, u16 remote_port,
- int family)
-{
- if (!local_addr)
- return -1;
-
- *face = (face_t) {
- .type = FACE_TYPE_UDP,
- .params.tunnel = {
- .family = family,
- .local_addr = *local_addr,
- .local_port = local_port,
- .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY,
- .remote_port = remote_port,
- },
- };
- return 1;
-}
-
-int
-face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr,
- const struct sockaddr * remote_addr)
-{
- if (!local_addr)
- return -1;
-
- if (remote_addr && (local_addr->sa_family != remote_addr->sa_family))
- return -1;
-
- switch (local_addr->sa_family) {
- case AF_INET:
- {
- struct sockaddr_in *lsai = (struct sockaddr_in *)local_addr;
- struct sockaddr_in *rsai = (struct sockaddr_in *)remote_addr;
- *face = (face_t) {
- .type = FACE_TYPE_UDP,
- .params.tunnel = {
- .family = AF_INET,
- .local_addr.v4.as_inaddr = lsai->sin_addr,
- .local_port = lsai ? ntohs(lsai->sin_port) : 0,
- .remote_addr = IP_ADDRESS_EMPTY,
- .remote_port = rsai ? ntohs(rsai->sin_port) : 0,
- },
- };
- if (rsai)
- face->params.tunnel.remote_addr.v4.as_inaddr = rsai->sin_addr;
- }
- break;
- case AF_INET6:
- {
- struct sockaddr_in6 *lsai = (struct sockaddr_in6 *)local_addr;
- struct sockaddr_in6 *rsai = (struct sockaddr_in6 *)remote_addr;
- *face = (face_t) {
- .type = FACE_TYPE_UDP,
- .params.tunnel = {
- .family = AF_INET6,
- .local_addr.v6.as_in6addr = lsai->sin6_addr,
- .local_port = lsai ? ntohs(lsai->sin6_port) : 0,
- .remote_addr = IP_ADDRESS_EMPTY,
- .remote_port = rsai ? ntohs(rsai->sin6_port) : 0,
- },
- };
- if (rsai)
- face->params.tunnel.remote_addr.v6.as_in6addr = rsai->sin6_addr;
- }
- break;
- default:
- return -1;
- }
- return 1;
-}
-
-face_t * face_create()
-{
- face_t * face = calloc(1, sizeof(face_t)); /* 0'ed for hash */
- return face;
-}
-
-face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port,
- const ip_address_t * remote_addr, u16 remote_port, int family)
-{
- face_t * face = face_create();
- if (face_initialize_udp(face, local_addr, local_port, remote_addr, remote_port, family) < 0)
- goto ERR_INIT;
- return face;
-
-ERR_INIT:
- free(face);
- return NULL;
-}
-
-face_t * face_create_udp_sa(const struct sockaddr * local_addr,
- const struct sockaddr * remote_addr)
-{
- face_t * face = face_create();
- if (face_initialize_udp_sa(face, local_addr, remote_addr) < 0)
- goto ERR_INIT;
- return face;
-
-ERR_INIT:
- free(face);
- return NULL;
-}
-
-void face_free(face_t * face)
-{
- free(face);
-}
-
-#define face_param_cmp(f1, f2, face_param_type) \
- memcmp(&f1->type, &f2->type, \
- member_size(face_params_t, face_param_type));
-
-/**
- * \brief Compare two faces
- * \param [in] f1 - First face
- * \param [in] f2 - Second face
- * \return whether faces are equal, ie both their types are parameters are
- * equal.
- *
- * NOTE: this function implements a partial order.
- */
-int
-face_cmp(const face_t * f1, const face_t * f2)
-{
- if (f1->type != f2->type)
- return false;
-
- switch(f1->type) {
- case FACE_TYPE_HICN:
- return face_param_cmp(f1, f2, hicn);
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- return face_param_cmp(f1, f2, tunnel);
- default:
- return false;
- }
-}
-
-hash_t
-face_hash(const face_t * face)
-{
- /* Assuming the unused part of the struct is set to zero */
- return hash_struct(face);
-}
-
-/* /!\ Please update constants in header file upon changes */
-size_t
-face_snprintf(char * s, size_t size, const face_t * face)
-{
- switch(face->type) {
- case FACE_TYPE_HICN:
- return 0; // XXX Not implemented
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- {
- char local[MAXSZ_IP_ADDRESS];
- char remote[MAXSZ_IP_ADDRESS];
- char tags[MAXSZ_POLICY_TAGS];
-
- ip_address_snprintf(local, MAXSZ_IP_ADDRESS,
- &face->params.tunnel.local_addr,
- face->params.tunnel.family);
- ip_address_snprintf(remote, MAXSZ_IP_ADDRESS,
- &face->params.tunnel.remote_addr,
- face->params.tunnel.family);
- policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags);
-
- return snprintf(s, size, "%s [%s:%d -> %s:%d] [%s]",
- face_type_str[face->type],
- local,
- face->params.tunnel.local_port,
- remote,
- face->params.tunnel.remote_port,
- tags);
- }
- break;
- default:
- return 0;
- }
-
-}
-
-int
-face_set_tags(face_t * face, policy_tags_t tags)
-{
- face->tags = tags;
- return 1;
-}
diff --git a/ctrl/facemgr/src/face.h b/ctrl/facemgr/src/face.h
deleted file mode 100644
index 8b553f685..000000000
--- a/ctrl/facemgr/src/face.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 face.h
- * \brief Face abstraction
- */
-#ifndef HICN_FACE_H
-#define HICN_FACE_H
-
-#ifndef SPACES
-#define SPACES(x) x
-#endif
-#ifndef SPACE
-#define SPACE 1
-#endif
-#ifndef NULLTERM
-#define NULLTERM 1
-#endif
-
-#include "util/ip_address.h"
-#include "util/policy.h"
-#include "util/types.h"
-
-
-/* Netdevice type */
-
-#include <net/if.h> // IFNAMSIZ
-
-#define foreach_netdevice_type \
- _(UNDEFINED) \
- _(WIRED) \
- _(WIFI) \
- _(CELLULAR) \
- _(VPN) \
- _(N)
-
-#define MAXSZ_NETDEVICE_TYPE_ 9
-#define MAXSZ_NETDEVICE_TYPE MAXSZ_NETDEVICE_TYPE_ + NULLTERM
-
-typedef enum {
-#define _(x) NETDEVICE_TYPE_ ## x,
-foreach_netdevice_type
-#undef _
-} netdevice_type_t;
-
-extern const char * netdevice_type_str[];
-
-
-/* Netdevice */
-
-typedef struct {
- u32 index;
- char name[IFNAMSIZ];
-} netdevice_t;
-
-#define NETDEVICE_UNDEFINED_INDEX 0
-
-/* Face state */
-
-#define foreach_face_state \
- _(UNDEFINED) \
- _(PENDING_UP) \
- _(UP) \
- _(PENDING_DOWN) \
- _(DOWN) \
- _(ERROR) \
- _(N)
-
-#define MAXSZ_FACE_STATE_ 12
-#define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1
-
-typedef enum {
-#define _(x) FACE_STATE_ ## x,
-foreach_face_state
-#undef _
-} face_state_t;
-
-extern const char * face_state_str[];
-
-
-/* Face type */
-
-#define foreach_face_type \
- _(UNDEFINED) \
- _(HICN) \
- _(HICN_LISTENER) \
- _(TCP) \
- _(TCP_LISTENER) \
- _(UDP) \
- _(UDP_LISTENER) \
- _(N)
-
-#define MAXSZ_FACE_TYPE_ 13
-#define MAXSZ_FACE_TYPE MAXSZ_FACE_TYPE_ + 1
-
-typedef enum {
-#define _(x) FACE_TYPE_ ## x,
-foreach_face_type
-#undef _
-} face_type_t;
-
-extern const char * face_type_str[];
-
-#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS_ + 2 * MAXSZ_PORT_ + 9 + MAXSZ_POLICY_TAGS_
-#define MAXSZ_FACE MAXSZ_FACE_ + 1
-
-/* Face */
-
-typedef union {
- int family; /* To access family independently of face type */
- struct {
- int family;
- netdevice_t netdevice;
- ip_address_t local_addr;
- ip_address_t remote_addr;
- } hicn;
- struct {
- int family;
- ip_address_t local_addr;
- u16 local_port;
- ip_address_t remote_addr;
- u16 remote_port;
- } tunnel;
-} face_params_t;
-
-typedef struct {
- face_type_t type;
- face_params_t params;
- face_state_t admin_state;
- face_state_t state;
-#ifdef WITH_POLICY
- policy_tags_t tags; /**< \see policy_tag_t */
-#endif /* WITH_POLICY */
-} face_t;
-
-int face_initialize(face_t * face);
-int face_initialize_udp(face_t * face, const ip_address_t * local_addr,
- u16 local_port, const ip_address_t * remote_addr, u16 remote_port,
- int family);
-int face_initialize_udp_sa(face_t * face,
- const struct sockaddr * local_addr, const struct sockaddr * remote_addr);
-
-face_t * face_create();
-face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port,
- const ip_address_t * remote_addr, u16 remote_port, int family);
-face_t * face_create_udp_sa(const struct sockaddr * local_addr,
- const struct sockaddr * remote_addr);
-
-int face_finalize(face_t * face);
-
-void face_free(face_t * face);
-
-typedef int (*face_cmp_t)(const face_t * f1, const face_t * f2);
-
-int face_cmp(const face_t * f1, const face_t * f2);
-hash_t face_hash(const face_t * face);
-
-size_t
-face_snprintf(char * s, size_t size, const face_t * face);
-
-int face_set_tags(face_t * face, policy_tags_t tags);
-
-#endif /* HICN_FACE_H */
-
diff --git a/ctrl/facemgr/src/face_cache.h b/ctrl/facemgr/src/face_cache.h
deleted file mode 100644
index caefb7e22..000000000
--- a/ctrl/facemgr/src/face_cache.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_CACHE_H
-#define FACE_CACHE_H
-
-#include "face.h"
-#include "util/set.h"
-
-TYPEDEF_SET_H(face_cache, face_t *);
-
-#endif /* FACE_CACHE_H */
diff --git a/ctrl/facemgr/src/face_rules.c b/ctrl/facemgr/src/face_rules.c
deleted file mode 100644
index ddefc15f9..000000000
--- a/ctrl/facemgr/src/face_rules.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_rules.h"
-
-#include <string.h>
-#include "util/policy.h"
-
-TYPEDEF_MAP(face_rules, const char *, policy_tags_t, strcmp, string_snprintf, policy_tags_snprintf);
diff --git a/ctrl/facemgr/src/facelet.c b/ctrl/facemgr/src/facelet.c
new file mode 100644
index 000000000..8a3074d2a
--- /dev/null
+++ b/ctrl/facemgr/src/facelet.c
@@ -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.
+ */
+
+/**
+ * \file facelet.c
+ * \brief Implementation of facelet
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <hicn/ctrl/face.h>
+#include <hicn/facemgr/cfg.h>
+#include <hicn/util/log.h>
+
+#include "facelet.h"
+
+const char * face_type_layer_str[] = {
+#define _(x) [FACE_TYPE_LAYER_ ## x] = STRINGIZE(x),
+ foreach_face_type_layer
+#undef _
+};
+
+const char * face_type_encap_str[] = {
+#define _(x) [FACE_TYPE_ENCAP_ ## x] = STRINGIZE(x),
+ foreach_face_type_encap
+#undef _
+};
+
+#define FACEMGR_FACE_TYPE_STR(x) \
+ face_type_layer_str[x.layer], face_type_encap_str[x.encap]
+
+
+const char * facelet_status_str[] = {
+#define _(x) [FACELET_STATUS_ ## x] = STRINGIZE(x),
+ foreach_facelet_status
+#undef _
+};
+
+/* Facelet attribute status */
+
+
+const char * facelet_attr_status_str[] = {
+#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(x),
+ foreach_facelet_attr_status
+#undef _
+};
+
+const char * facelet_attr_status_str_short[] = {
+#define _(x, str) [FACELET_ATTR_STATUS_ ## x] = STRINGIZE(str),
+ foreach_facelet_attr_status
+#undef _
+};
+
+
+/* Facelet */
+
+struct facelet_s {
+#define _(TYPE, NAME) TYPE NAME;
+ foreach_facelet_attr
+#undef _
+#define _(TYPE, NAME) facelet_attr_status_t NAME ## _status;
+ foreach_facelet_attr
+#undef _
+
+ facelet_status_t status;
+ facelet_event_t event;
+
+ /* Joins */
+ bool bj_done;
+ bool au_done;
+ int num_pending;
+};
+
+const char * facelet_event_str[] = {
+#define _(x) [FACELET_EVENT_ ## x] = STRINGIZE(x),
+foreach_facelet_event
+#undef _
+};
+
+facelet_t *
+facelet_create()
+{
+ facelet_t * facelet = calloc(1, sizeof(facelet_t));
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->family_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->state_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->face_type_status = FACELET_ATTR_STATUS_UNSET;
+
+ facelet->status = FACELET_STATUS_NEW;
+
+ facelet->bj_done = false;
+ facelet->au_done = false;
+ facelet->num_pending = 0;
+
+ facelet->event = FACELET_EVENT_UNDEFINED;
+
+ return facelet;
+
+ERR_MALLOC:
+ return NULL;
+}
+
+facelet_t *
+facelet_create_from_netdevice(netdevice_t * netdevice)
+{
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_FACELET;
+
+ int rc = facelet_set_netdevice(facelet, *netdevice);
+ if (rc < 0)
+ goto ERR_NETDEV;
+
+ return facelet;
+
+ERR_NETDEV:
+ facelet_free(facelet);
+ERR_FACELET:
+ return NULL;
+}
+
+/**
+ * \brief Validate whether the facelet has all required fields to construct a
+ * face of the given type
+ * \param [in) facelet - Pointer to the facelet to verify
+ * \return 0 in case of success, -1 otherwise
+ */
+int
+facelet_validate_face(const facelet_t * facelet)
+{
+ if (!facelet_has_face_type(facelet))
+ return false;
+ switch(facelet->face_type.layer) {
+ case FACE_TYPE_LAYER_4:
+ if (!facelet_has_remote_port(facelet))
+ return false;
+ if (!facelet_has_remote_addr(facelet))
+ return false;
+ case FACE_TYPE_LAYER_3:
+ if (!facelet_has_local_addr(facelet))
+ return false;
+ if (!facelet_has_netdevice(facelet))
+ return false;
+ return true;
+
+ default:
+ return false; /* Error */
+ }
+ // FIXME Not implemented
+ return 0;
+}
+
+
+netdevice_type_t
+netdevice_type_from_face_tags(const face_t * face)
+{
+ policy_tags_t tags = face->tags;
+ if (policy_tags_has(tags, POLICY_TAG_WIRED))
+ return NETDEVICE_TYPE_WIRED;
+ else if (policy_tags_has(tags, POLICY_TAG_WIFI))
+ return NETDEVICE_TYPE_WIFI;
+ else if (policy_tags_has(tags, POLICY_TAG_CELLULAR))
+ return NETDEVICE_TYPE_CELLULAR;
+ return NETDEVICE_TYPE_UNDEFINED;
+}
+
+facelet_t *
+facelet_create_from_face(face_t * face)
+{
+ facelet_t * facelet = malloc(sizeof(facelet_t));
+ if (!facelet)
+ goto ERR_MALLOC;
+
+ /* Go through the face attributes to update the local representation */
+
+ /* Attribute : netdevice */
+ /* NOTE index is not set */
+ if (IS_VALID_NETDEVICE(face->netdevice)) {
+ facelet->netdevice = face->netdevice;
+ facelet->netdevice_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->netdevice_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : netdevice_type */
+ facelet->netdevice_type = netdevice_type_from_face_tags(face);
+ if (facelet->netdevice_type != NETDEVICE_TYPE_UNDEFINED) {
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->netdevice = NETDEVICE_EMPTY;
+ facelet->netdevice_type_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : family */
+ if (IS_VALID_FAMILY(face->family)) {
+ facelet->family = face->family;
+ facelet->family_status = FACELET_ATTR_STATUS_CLEAN;
+
+ /* Attribute : local_addr */
+ if (ip_address_cmp(&face->local_addr, &IP_ADDRESS_EMPTY, face->family) != 0) {
+ facelet->local_addr = face->local_addr;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : local_port */
+ if (IS_VALID_PORT(face->local_port)) {
+ facelet->local_port = face->local_port;
+ facelet->local_port_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : remote_addr */
+ if (ip_address_cmp(&face->remote_addr, &IP_ADDRESS_EMPTY, face->family) != 0) {
+ facelet->remote_addr = face->remote_addr;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : remote_port */
+ if (IS_VALID_PORT(face->remote_port)) {
+ facelet->remote_port = face->remote_port;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ } else {
+ facelet->family_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->local_port_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_addr_status = FACELET_ATTR_STATUS_UNSET;
+ facelet->remote_port_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : admin_state */
+ if ((face->admin_state == FACE_STATE_UP) ||
+ (face->admin_state == FACE_STATE_DOWN)) {
+ facelet->admin_state = face->admin_state;
+ facelet->admin_state_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->admin_state_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : state */
+ if ((face->state == FACE_STATE_UP) ||
+ (face->state == FACE_STATE_DOWN)) {
+ facelet->state = face->state;
+ facelet->state_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->state_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Attribute : face_type */
+ if ((face->type != FACE_TYPE_UNDEFINED) && (face->type != FACE_TYPE_N)) {
+ switch(face->type) {
+ case FACE_TYPE_UDP:
+ facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ break;
+ case FACE_TYPE_TCP:
+ facelet->face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ break;
+ case FACE_TYPE_HICN:
+ facelet->face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ break;
+ default:
+ ERROR("[facelet_create_from_face] Face type not (yet) implemented");
+ goto ERR_FACE;
+ }
+ facelet->face_type_status = FACELET_ATTR_STATUS_CLEAN;
+ } else {
+ facelet->face_type_status = FACELET_ATTR_STATUS_UNSET;
+ }
+
+ /* Status */
+ facelet->status = FACELET_STATUS_CLEAN;
+
+ /* TODO Consistency check between face type and found attributes */
+ if (facelet_validate_face(facelet) < 0)
+ goto ERR_FACE;
+
+ facelet->bj_done = false;
+ facelet->au_done = false;
+ facelet->num_pending = 0;
+
+ facelet->event = FACELET_EVENT_UNDEFINED;
+
+ return facelet;
+
+ERR_FACE:
+ free(facelet);
+ERR_MALLOC:
+ return NULL;
+}
+
+
+void
+facelet_free(facelet_t * facelet)
+{
+ free(facelet);
+}
+
+facelet_t *
+facelet_dup(const facelet_t * current_facelet)
+{
+ facelet_t * facelet = facelet_create();
+ if (!facelet)
+ goto ERR_CREATE;
+
+#define _(TYPE, NAME) facelet-> NAME = current_facelet-> NAME;
+ foreach_facelet_attr
+#undef _
+#define _(TYPE, NAME) facelet-> NAME ## _status = current_facelet-> NAME ## _status;
+ foreach_facelet_attr
+#undef _
+
+ facelet->status = current_facelet->status;
+ facelet->event = current_facelet->event;
+
+ facelet->bj_done = current_facelet->bj_done;
+ facelet->au_done = current_facelet->au_done;
+ facelet->num_pending = current_facelet->num_pending;
+
+ return facelet;
+
+ERR_CREATE:
+ return NULL;
+}
+
+int
+facelet_cmp(const facelet_t * f1, const facelet_t * f2)
+{
+ /*
+ * Under the assumption we only create a face per physical interface, a
+ * facelet is uniquely identified by its netdevice attribute, and address
+ * family if any.
+ *
+ * This function is mostly used for lookups into the cache, and the face
+ * thus needs to have a netdevice associated, and optionally, an address
+ * family.
+ *
+ * For other situations, the `facelet_match` function is more appropriate.
+ */
+
+ if ((f1->netdevice_status != FACELET_ATTR_STATUS_UNSET) &&
+ (f2->netdevice_status != FACELET_ATTR_STATUS_UNSET)) {
+ int rc = netdevice_cmp(&f1->netdevice, &f2->netdevice);
+ if (rc != 0)
+ return rc;
+
+ } else {
+ /* Both unset : we might have the face without netdevice due to hicn
+ * light not returning it currently, but we cannot skip it in the match
+ * otherwise we cannot distinguish with other faces except matching on
+ * other fields which might unfortunately not be determined yet...
+ */
+ return (f1->netdevice_status == FACELET_ATTR_STATUS_UNSET) ? -1 : 1;
+ }
+
+ assert(f1->family_status != FACELET_ATTR_STATUS_UNSET);
+ assert(f2->family_status != FACELET_ATTR_STATUS_UNSET);
+
+ if ((f1->family == AF_UNSPEC) || (f2->family == AF_UNSPEC))
+ return 0;
+ int diff = f1->family - f2->family;
+ return (diff > 0) ? 1 :
+ (diff < 0) ? -1 : 0;
+}
+
+/*
+ * If the match has a field set, then the facelet only matches iif it has the
+ * same field set, and both values are equal
+ */
+#define MATCH_ATTRIBUTE(TYPE, NAME) \
+do { \
+ if (facelet_match->NAME ## _status == FACELET_ATTR_STATUS_CLEAN) { \
+ if (facelet_has_ ## NAME(facelet_match)) { \
+ TYPE NAME; \
+ TYPE NAME ## _match; \
+ if (!facelet_has_ ## NAME(facelet)) \
+ return false; \
+ if (facelet_get_ ## NAME (facelet, & NAME) < 0) \
+ return false; \
+ if (facelet_get_ ## NAME (facelet_match, & NAME ## _match) < 0) \
+ return false; \
+ if (memcmp(& NAME, & NAME ## _match, sizeof(NAME)) != 0) \
+ return false; \
+ } \
+ } \
+} while(0)
+
+/* facelet_match is the incoming one */
+bool
+facelet_match(const facelet_t * facelet, const facelet_t * facelet_match)
+{
+#define _(TYPE, NAME) MATCH_ATTRIBUTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ return true;
+}
+
+bool facelet_has_key(const facelet_t * facelet) {
+ return (facelet_has_netdevice(facelet) && facelet_has_family(facelet));
+}
+
+/*
+ * Implementation note:
+ * - facelet_set_* is equivalent to merge with a CLEAN remote attribute
+ */
+#define FACELET_ACCESSORS(TYPE, NAME) \
+bool \
+facelet_has_ ## NAME(const facelet_t * facelet) \
+{ \
+ assert(facelet); \
+ assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_UNDEFINED); \
+ assert(facelet->NAME ## _status != FACELET_ATTR_STATUS_N); \
+ return ((facelet-> NAME ## _status != FACELET_ATTR_STATUS_UNSET)); \
+} \
+ \
+facelet_attr_status_t \
+facelet_get_ ## NAME ## _status(const facelet_t * facelet) \
+{ \
+ return (facelet->NAME ## _status); \
+} \
+ \
+int \
+facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME) \
+{ \
+ assert(facelet); \
+ if (!facelet_has_ ## NAME(facelet)) \
+ return -1; \
+ *NAME = facelet-> NAME; \
+ return 0; \
+} \
+ \
+int \
+facelet_set_local_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ assert(facelet); \
+ switch(facelet->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNSET: \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ facelet-> NAME = NAME; \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_DIRTY; \
+ if (facelet->status == FACELET_STATUS_CLEAN) \
+ facelet->status = FACELET_STATUS_DIRTY; \
+ break; \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ break; \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ ERROR("Unexpected attribute status value"); \
+ return -1; \
+ } \
+ return 0; \
+} \
+ \
+int \
+facelet_set_remote_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ assert(facelet); \
+ switch(facelet->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNSET: \
+ facelet-> NAME = NAME; \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ facelet->NAME = NAME; \
+ break; \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ ERROR("Discarded remote value for status reasons"); \
+ break; \
+ case FACELET_ATTR_STATUS_PENDING: \
+ ERROR("Received remote value on pending attribute"); \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CONFLICT; \
+ if (facelet->status != FACELET_STATUS_CONFLICT) \
+ facelet->status = FACELET_STATUS_CONFLICT; \
+ break; \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ ERROR("Unexpected attribute status value"); \
+ return -1; \
+ } \
+ return 0; \
+} \
+ \
+int \
+facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME) \
+{ \
+ return facelet_set_local_ ## NAME(facelet, NAME); \
+} \
+ \
+
+#define _(TYPE, NAME) FACELET_ACCESSORS(TYPE, NAME)
+foreach_facelet_attr
+#undef _
+
+/*
+ * This function is called for every facelet attribute. It is responsible for
+ * comparing both the current and new value, and set the attribute and facelet
+ * status appropriately.
+ */
+
+// FIXME CLEAN for key fields, dirty for fields to update.
+
+#define MERGE_ATTRIBUTE(TYPE, NAME) \
+do { \
+ switch(facelet_to_merge->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ ERROR("Unexpected facelet attribute status"); \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNSET: \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \
+ break; \
+ } \
+} while (0)
+
+int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge)
+{
+ assert(facelet && facelet_to_merge);
+#define _(TYPE, NAME) MERGE_ATTRIBUTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ facelet->event = facelet_to_merge->event;
+ return 0;
+}
+
+#define MERGE_ATTRIBUTE_REMOTE(TYPE, NAME) \
+do { \
+ switch(facelet_to_merge->NAME ## _status) { \
+ case FACELET_ATTR_STATUS_UNDEFINED: \
+ case FACELET_ATTR_STATUS_N: \
+ case FACELET_ATTR_STATUS_DIRTY: \
+ case FACELET_ATTR_STATUS_PENDING: \
+ case FACELET_ATTR_STATUS_CONFLICT: \
+ ERROR("Unexpected facelet attribute status"); \
+ return -1; \
+ case FACELET_ATTR_STATUS_UNSET: \
+ break; \
+ case FACELET_ATTR_STATUS_CLEAN: \
+ facelet_set_ ## NAME(facelet, facelet_to_merge-> NAME); \
+ break; \
+ \
+ } \
+} while (0)
+
+int facelet_merge_remote(facelet_t * facelet, const facelet_t * facelet_to_merge)
+{
+ assert(facelet && facelet_to_merge);
+#define _(TYPE, NAME) MERGE_ATTRIBUTE_REMOTE(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ facelet->event = facelet_to_merge->event;
+ return 0;
+}
+
+int
+facelet_get_face(const facelet_t * facelet, face_t ** pface)
+{
+ assert(pface);
+
+ /* Facelet has all the required information to create a face */
+ if (facelet_validate_face(facelet) < 0)
+ return 0;
+
+ face_t * face = face_create();
+ if (!face)
+ goto ERR_CREATE;
+
+ assert(facelet_has_netdevice(facelet));
+ face->netdevice = facelet->netdevice;
+
+ /* Face type */
+ switch(facelet->face_type.layer) {
+ case FACE_TYPE_LAYER_4:
+ switch(facelet->face_type.encap) {
+ case FACE_TYPE_ENCAP_UDP:
+ face->type = FACE_TYPE_UDP;
+ break;
+ case FACE_TYPE_ENCAP_TCP:
+ face->type = FACE_TYPE_TCP;
+ break;
+ case FACE_TYPE_ENCAP_UNDEFINED:
+ case FACE_TYPE_ENCAP_N:
+ ERROR("[facelet_get_face] Unsupported face encapsulation");
+ goto ERR;
+ }
+
+ if (facelet_get_family(facelet, &face->family) < 0)
+ goto ERR;
+ if (facelet_get_local_addr(facelet, &face->local_addr) < 0)
+ goto ERR;
+ if (facelet_get_local_port(facelet, &face->local_port) < 0)
+ goto ERR;
+ if (facelet_get_remote_addr(facelet, &face->remote_addr) < 0)
+ goto ERR;
+ if (facelet_get_remote_port(facelet, &face->remote_port) < 0)
+ goto ERR;
+ break;
+
+ case FACE_TYPE_LAYER_3:
+ ERROR("{facelet_get_face] hICN face not (yet) implemented");
+ goto ERR;
+
+ case FACE_TYPE_LAYER_UNDEFINED:
+ case FACE_TYPE_LAYER_N:
+ ERROR("[facelet_get_face] Unsupported face type");
+ goto ERR;
+ }
+
+ if (facelet_has_admin_state(facelet)) {
+ if (facelet_get_admin_state(facelet, &face->admin_state) < 0)
+ goto ERR;
+ } else {
+ face->admin_state = FACE_STATE_UP;
+ }
+
+ if (facelet_has_state(facelet)) {
+ if (facelet_get_state(facelet, &face->state) < 0)
+ goto ERR;
+ } else {
+ face->state = FACE_STATE_UP;
+ }
+
+ /* Tags */
+
+ /* - based on netdevice type */
+ policy_tags_t tags = POLICY_TAGS_EMPTY;
+ if (facelet_has_netdevice_type(facelet)) {
+ netdevice_type_t netdevice_type;
+ if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) {
+ ERROR("error getting netdevice_type");
+ goto ERR;
+ }
+
+
+ switch(netdevice_type) {
+ case NETDEVICE_TYPE_UNDEFINED:
+ case NETDEVICE_TYPE_LOOPBACK:
+ break;
+ case NETDEVICE_TYPE_WIRED:
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ break;
+ case NETDEVICE_TYPE_WIFI:
+ policy_tags_add(&tags, POLICY_TAG_WIFI);
+ break;
+ case NETDEVICE_TYPE_CELLULAR:
+ policy_tags_add(&tags, POLICY_TAG_CELLULAR);
+ break;
+ default:
+ goto ERR;
+ }
+ }
+#ifdef __linux__
+#ifndef __ANDROID__
+ else {
+ /*
+ * Heuristics to determine face type based on name, until a better
+ * solution is found
+ */
+ if (strncmp(facelet->netdevice.name, "eth", 3) == 0) {
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ goto DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "en", 2) == 0) {
+ policy_tags_add(&tags, POLICY_TAG_WIRED);
+ goto DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "wl", 2) == 0) {
+ /* wlan* wlp* wlx* */
+ policy_tags_add(&tags, POLICY_TAG_WIFI);
+ goto DONE;
+ }
+
+DONE:
+ ;
+ }
+#endif /* ! __ANDROID__ */
+#endif /* __linux__ */
+ face->tags = tags;
+
+ *pface = face;
+
+ return 0;
+
+ERR:
+ free(face);
+ERR_CREATE:
+ *pface = NULL;
+ return -1;
+}
+
+facelet_status_t
+facelet_get_status(const facelet_t * facelet)
+{
+ return facelet->status;
+}
+
+#define SET_ATTR_STATUS_CLEAN(TYPE, NAME) \
+do { \
+ if (facelet->NAME ## _status == FACELET_ATTR_STATUS_DIRTY) \
+ facelet->NAME ## _status = FACELET_ATTR_STATUS_CLEAN; \
+} while (0)
+
+void
+facelet_set_status(facelet_t * facelet, facelet_status_t status)
+{
+ if (status == FACELET_STATUS_CLEAN) {
+#define _(TYPE, NAME) SET_ATTR_STATUS_CLEAN(TYPE, NAME);
+ foreach_facelet_attr
+#undef _
+ }
+ facelet->status = status;
+}
+
+int
+facelet_add_pending(facelet_t * facelet)
+{
+ assert(facelet);
+ facelet->num_pending++;
+ return 0;
+}
+
+int
+facelet_remove_pending(facelet_t * facelet)
+{
+ assert(facelet);
+ if (facelet->num_pending == 0)
+ return -1;
+ facelet->num_pending--;
+ return 0;
+}
+
+bool
+facelet_has_pending(const facelet_t * facelet)
+{
+ assert(facelet);
+ DEBUG("num pending=%d\n", facelet->num_pending);
+ return (facelet->num_pending > 0);
+}
+
+void
+facelet_set_bj_done(facelet_t * facelet)
+{
+ facelet->bj_done = true;
+}
+
+bool
+facelet_is_bj_done(const facelet_t * facelet)
+{
+ return facelet->bj_done;
+}
+
+void
+facelet_set_au_done(facelet_t * facelet)
+{
+ facelet->au_done = true;
+}
+
+bool
+facelet_is_au_done(const facelet_t * facelet)
+{
+ return facelet->au_done;
+}
+
+facelet_event_t
+facelet_get_event(const facelet_t * facelet)
+{
+ return facelet->event;
+}
+
+void
+facelet_set_event(facelet_t * facelet, facelet_event_t event)
+{
+ facelet->event = event;
+}
+
+int
+facelet_raise_event(facelet_t * facelet, const interface_t * interface)
+{
+ if (interface->callback)
+ interface->callback(interface->callback_data, facelet);
+ return 0;
+}
+
+int
+facelet_snprintf(char * s, size_t size, facelet_t * facelet)
+{
+ char * cur = s;
+ int rc;
+
+ assert(facelet);
+
+ /* Header + key attributes (netdevice + family) */
+ rc = snprintf(cur, s + size - cur, "<Facelet %s (%s) [%d]",
+ // FIXME, better than the event would be the action to be performed next
+ facelet_event_str[facelet->event],
+ (facelet->family == AF_INET) ? "AF_INET" :
+ (facelet->family == AF_INET6) ? "AF_INET6" :
+ (facelet->family == AF_UNSPEC) ? "AF_UNSPEC" :
+ "unknown",
+ facelet->num_pending);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ /* Netdevice */
+ if (facelet_has_netdevice(facelet)) {
+ rc = snprintf(cur, s + size - cur, " netdevice=%s",
+ facelet->netdevice.name[0] ? facelet->netdevice.name : "*");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = snprintf(cur, s + size - cur, "/%d", facelet->netdevice.index);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ } else {
+ rc = snprintf(cur, s + size - cur, " netdevice=*/*");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Netdevice type */
+ if (facelet_has_netdevice_type(facelet)) {
+ rc = snprintf(cur, s + size - cur, " type=%s",
+ netdevice_type_str[facelet->netdevice_type]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+#ifdef __linux__
+#ifndef __ANDROID__
+ else {
+ /*
+ * Heuristics to determine face type based on name, until a better
+ * solution is found
+ */
+ if ((strncmp(facelet->netdevice.name, "eth", 3) == 0) ||
+ (strncmp(facelet->netdevice.name, "en", 2) == 0)) {
+ rc = snprintf(cur, s + size - cur, " [type=WIRED]");
+ goto HEURISTIC_DONE;
+ }
+ if (strncmp(facelet->netdevice.name, "wl", 2) == 0) {
+ /* wlan* wlp* wlx* */
+ rc = snprintf(cur, s + size - cur, " [type=WIFI]");
+ goto HEURISTIC_DONE;
+ }
+ goto HEURISTIC_END;
+
+HEURISTIC_DONE:
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+HEURISTIC_END:
+ ;
+ }
+#endif /* ! __ANDROID__ */
+#endif /* __linux__ */
+
+ /* Local ip address */
+ if (facelet_has_local_addr(facelet)) {
+ rc = snprintf(cur, s + size - cur, " local_addr=");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = ip_address_snprintf(cur, s + size - cur, &facelet->local_addr,
+ facelet->family);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Local port */
+ if (facelet_has_local_port(facelet)) {
+ rc = snprintf(cur, s + size - cur, " local_port=%d",
+ facelet->local_port);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Remote ip address */
+ if (facelet_has_remote_addr(facelet)) {
+ rc = snprintf(cur, s + size - cur, " remote_addr=");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ rc = ip_address_snprintf(cur, s + size - cur, &facelet->remote_addr,
+ facelet->family);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Remote port */
+ if (facelet_has_remote_port(facelet)) {
+ rc = snprintf(cur, s + size - cur, " remote_port=%d",
+ facelet->remote_port);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* Admin state */
+ if (facelet_has_admin_state(facelet)) {
+ rc = snprintf(cur, s + size - cur, " admin_state=%s",
+ face_state_str[facelet->admin_state]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ /* State */
+ if (facelet_has_state(facelet)) {
+ rc = snprintf(cur, s + size - cur, " state=%s",
+ face_state_str[facelet->state]);
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ if (facelet_has_face_type(facelet)) {
+ rc = snprintf(cur, s + size - cur, " face_type=IP%s/%s",
+ FACEMGR_FACE_TYPE_STR(facelet->face_type));
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+ }
+
+ rc = snprintf(cur, s + size - cur, ">");
+ if (rc < 0)
+ return rc;
+ cur += rc;
+ if (size != 0 && cur >= s + size)
+ return cur - s;
+
+ return cur - s;
+}
diff --git a/ctrl/facemgr/src/facelet.h b/ctrl/facemgr/src/facelet.h
new file mode 100644
index 000000000..fecee8641
--- /dev/null
+++ b/ctrl/facemgr/src/facelet.h
@@ -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.
+ */
+
+/**
+ * \file facelet.h
+ * \brief Facelet
+ *
+ * A facelet consists in partial information and annotations collected towards
+ * the contruction of the final face that will be sent to the forwarder.
+ *
+ * It might also consist in a pattern allowing the deletion of a group of face
+ * for instance.
+ */
+#ifndef FACEMGR_FACELET_H
+#define FACEMGR_FACELET_H
+
+#include <stdbool.h>
+
+#include <hicn/ctrl/face.h>
+#include <hicn/facemgr.h>
+
+#include "interface.h"
+
+/* NOTE: Any test should be sufficient */
+#define IS_VALID_NETDEVICE(netdevice) ((netdevice.index != 0) && (netdevice.name[0] != '\0'))
+
+typedef struct facelet_s facelet_t;
+
+/* Facelet status */
+#define foreach_facelet_status \
+ _(UNDEFINED) \
+ _(NEW) \
+ _(CLEAN) \
+ _(DIRTY) \
+ _(CONFLICT) \
+ _(DELETED) \
+ _(N)
+
+typedef enum {
+#define _(x) FACELET_STATUS_ ## x,
+ foreach_facelet_status
+#undef _
+} facelet_status_t;
+
+extern const char * facelet_status_str[];
+
+/* Facelet attribute status */
+
+/*
+ * We expect an attribute in the cache to be able to take any value but
+ * UNDEFINED and N, which facelet events should either be UNSET or CLEAN
+ */
+#define foreach_facelet_attr_status \
+ _(UNDEFINED, '?') \
+ _(UNSET, 'X') \
+ _(CLEAN, ' ') \
+ _(DIRTY, '*') \
+ _(PENDING, 'P') \
+ _(CONFLICT, '!') \
+ _(N, '-')
+
+typedef enum {
+#define _(x, y) FACELET_ATTR_STATUS_ ## x,
+ foreach_facelet_attr_status
+#undef _
+} facelet_attr_status_t;
+
+extern const char * facelet_attr_status_str[];
+extern const char * facelet_attr_status_str_short[];
+
+/* Facelet attribute */
+
+#define foreach_facelet_attr \
+ _(netdevice_type_t, netdevice_type) \
+ _(netdevice_t, netdevice) \
+ _(int, family) \
+ _(ip_address_t, local_addr) \
+ _(u16, local_port) \
+ _(ip_address_t, remote_addr) \
+ _(u16, remote_port) \
+ _(face_state_t, admin_state) \
+ _(face_state_t, state) \
+ _(facemgr_face_type_t, face_type)
+
+#define foreach_facelet_event \
+ _(UNDEFINED) \
+ _(GET) \
+ _(CREATE) \
+ _(UPDATE) \
+ _(DELETE) \
+ _(SET_PARAMS) \
+ _(SET_UP) \
+ _(SET_DOWN) \
+ _(SET_TAGS) \
+ _(CLEAR_TAGS) \
+ _(ADD_TAG) \
+ _(REMOVE_TAG) \
+ _(N)
+
+#define MAXSZ_EVENT__ 10
+#define MAXSZ_EVENT_ MAXSZ_EVENT_ + 1
+
+/**
+ * \brief Enumeration of the possible types of event
+ */
+typedef enum {
+#define _(x) FACELET_EVENT_ ## x,
+foreach_facelet_event
+#undef _
+} facelet_event_t;
+
+extern const char * facelet_event_str[];
+
+/**
+ * \brief Create a facelet.
+ */
+facelet_t * facelet_create();
+
+facelet_t * facelet_create_from_netdevice(netdevice_t * netdevice);
+
+int facelet_validate_face(const facelet_t * facelet);
+
+facelet_t * facelet_create_from_face(face_t * face);
+
+void facelet_free(facelet_t * facelet);
+
+facelet_t * facelet_dup(const facelet_t * current_facelet);
+
+int facelet_cmp(const facelet_t * f1, const facelet_t * f2);
+
+/* NOTE: only clean attributes are matched */
+bool facelet_match(const facelet_t * facelet, const facelet_t * facelet_match);
+
+/**
+ * \brief Returns whether the specified facelet has all key attributes defined.
+ *
+ * Key attributes are netdevice and family. If both are present, this allows to
+ * uniquely identify a facelet, otherwise it is a 'wildcard' facelet
+ * specification and might match several facelets.
+ */
+bool facelet_has_key(const facelet_t * facelet);
+
+
+#define FACELET_ACCESSORS_H(TYPE, NAME) \
+bool facelet_has_ ## NAME(const facelet_t * facelet); \
+facelet_attr_status_t facelet_get_ ## NAME ## _status(const facelet_t * facelet);\
+int facelet_get_ ## NAME(const facelet_t * facelet, TYPE * NAME); \
+int facelet_set_ ## NAME(facelet_t * facelet, TYPE NAME);
+
+#define _(TYPE, NAME) FACELET_ACCESSORS_H(TYPE, NAME)
+foreach_facelet_attr
+#undef _
+
+int facelet_get_face(const facelet_t * facelet, face_t ** pface);
+
+int facelet_merge(facelet_t * facelet, const facelet_t * facelet_to_merge);
+
+facelet_status_t facelet_get_status(const facelet_t * facelet);
+void facelet_set_status(facelet_t * facelet, facelet_status_t status);
+
+int facelet_add_pending(facelet_t * facelet);
+int facelet_remove_pending(facelet_t * facelet);
+bool facelet_has_pending(const facelet_t * facelet);
+
+void facelet_set_bj_done(facelet_t * facelet);
+bool facelet_is_bj_done(const facelet_t * facelet);
+void facelet_set_au_done(facelet_t * facelet);
+bool facelet_is_au_done(const facelet_t * facelet);
+
+facelet_event_t facelet_get_event(const facelet_t * facelet);
+void facelet_set_event(facelet_t * facelet, facelet_event_t event);
+
+/**
+ * \brief Create and raises an event to the face manager
+ * \param [in] event_type - Type of the event to create
+ * \param [in] facelet - Facelet to communicate with the event
+ * \param [in] interface - Interface that raised the event (or NULL if it was
+ * created but the face manager itself, or is a joined event)
+ */
+int facelet_raise_event(facelet_t * facelet, const interface_t * interface);
+
+int facelet_snprintf(char * buf, size_t size, facelet_t * facelet);
+
+#define MAXSZ_FACELET 1024
+
+#endif /* FACEMGR_FACELET_H */
diff --git a/ctrl/facemgr/src/facemgr.c b/ctrl/facemgr/src/facemgr.c
deleted file mode 100644
index 41e30de56..000000000
--- a/ctrl/facemgr/src/facemgr.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 facemgr.c
- * \brief Implementation of Face manager library interface
- */
-
-#include <stdio.h>
-
-#include "common.h"
-#include "event.h"
-#include "facemgr.h"
-#include "interface.h"
-#include "util/log.h"
-
-#ifdef __APPLE__
-extern interface_ops_t network_framework_ops;
-#endif
-#ifdef __linux__
-extern interface_ops_t netlink_ops;
-#endif
-#if 0
-extern interface_ops_t dummy_ops;
-#endif
-extern interface_ops_t hicn_light_ops;
-
-int
-facemgr_initialize(facemgr_t * facemgr)
-{
- int rc;
-
- rc = interface_map_initialize(&facemgr->interface_map);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_INTERFACE_MAP;
-
- rc = face_cache_initialize(&facemgr->face_cache);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_FACE_SET;
-
- rc = face_rules_initialize(&facemgr->rules);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_FACE_SET;
-
- return FACEMGR_SUCCESS;
-
-ERR_FACE_SET:
- interface_map_finalize(&facemgr->interface_map);
-
-ERR_INTERFACE_MAP:
- return FACEMGR_FAILURE;
-}
-
-int
-facemgr_finalize(facemgr_t * facemgr)
-{
- int rc;
-
- /* XXX Free all interfaces: pass free to map */
- rc = interface_map_finalize(&facemgr->interface_map);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- rc = face_cache_finalize(&facemgr->face_cache);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- rc = face_rules_finalize(&facemgr->rules);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
- return FACEMGR_SUCCESS;
-
-ERR:
- return FACEMGR_FAILURE;
-}
-
-AUTOGENERATE_CREATE_FREE(facemgr);
-
-int
-facemgr_on_event(facemgr_t * facemgr, event_t * event)
-{
- int rc;
- char face_s[MAXSZ_FACE];
- face_t * cached_face;
-
- if (!event->face) {
- printf("Event with empty face\n");
- return -1;
- }
-
- face_t face = *event->face;
-
- /* Complement unbound UDP faces */
- switch(face.type) {
- case FACE_TYPE_TCP:
- case FACE_TYPE_UDP:
- switch (face.params.tunnel.family) {
- case AF_INET:
- if ((ip_address_empty(&face.params.tunnel.remote_addr)) &&
- (!ip_address_empty(&facemgr->overlay_v4_remote_addr)))
- face.params.tunnel.remote_addr = facemgr->overlay_v4_remote_addr;
- if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v4_local_port != 0))
- face.params.tunnel.local_port = facemgr->overlay_v4_local_port;
- if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v4_remote_port != 0))
- face.params.tunnel.remote_port = facemgr->overlay_v4_remote_port;
- break;
- case AF_INET6:
- if ((ip_address_empty(&face.params.tunnel.remote_addr)) &&
- (!ip_address_empty(&facemgr->overlay_v6_remote_addr)))
- face.params.tunnel.remote_addr = facemgr->overlay_v6_remote_addr;
- if ((face.params.tunnel.local_port == 0) && (facemgr->overlay_v6_local_port != 0))
- face.params.tunnel.local_port = facemgr->overlay_v6_local_port;
- if ((face.params.tunnel.remote_port == 0) && (facemgr->overlay_v6_remote_port != 0))
- face.params.tunnel.remote_port = facemgr->overlay_v6_remote_port;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- face_snprintf(face_s, MAXSZ_FACE, &face);
-
- /* TODO Here, we need to filter events based on our cache, and update the cache
- * based on our actions if they are successful */
-
- switch(event->type) {
- case EVENT_TYPE_CREATE:
- rc = face_cache_get(&facemgr->face_cache, &face, &cached_face);
- if (!FACEMGR_IS_ERROR(rc)) {
- DEBUG("Face found in cache");
- goto IGNORE_EVENT;
- }
- rc = face_cache_add(&facemgr->face_cache, &face);
- if (FACEMGR_IS_ERROR(rc))
- WARN("Failed to add face to cache");
- break;
- case EVENT_TYPE_DELETE:
- rc = face_cache_remove(&facemgr->face_cache, &face, &cached_face);
- if (FACEMGR_IS_ERROR(rc))
- WARN("Face not found in cache");
- break;
- case EVENT_TYPE_SET_UP:
- case EVENT_TYPE_SET_DOWN:
- /* TODO We need a return code to update the cache */
- break;
- default:
- printf("Not implemented!\n");
- break;
- }
-
- /* Process event */
- printf("[ FACE %s ] %s\n", event_type_str[event->type], face_s);
- /* Hardcoded hicn-light */
- rc = interface_on_event(facemgr->hl, event);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR;
-
-IGNORE_EVENT:
- return FACEMGR_SUCCESS;
-
-ERR:
- return FACEMGR_FAILURE;
-}
-
-#ifdef __linux__
-void interface_callback(evutil_socket_t fd, short what, void * arg) {
- interface_t * interface = (interface_t *)arg;
- interface->ops->callback(interface);
-}
-#endif /* __linux__ */
-
-int
-facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, interface_t ** interface)
-{
- int fd, rc;
-
- INFO("Creating interface %s [%s]...\n", name, type);
- *interface = interface_create(name, type);
- if (!*interface) {
- ERROR("Error creating interface %s [%s]\n", name, type);
- return -1;
- }
- interface_set_callback(*interface, facemgr_on_event, facemgr);
-
- fd = interface_initialize(*interface, &facemgr->rules);
- if (fd < 0)
- return -2;
- if (fd != 0) {
-#ifdef __linux__
- evutil_make_socket_nonblocking(fd);
- struct event * event = event_new(facemgr->loop, fd, EV_READ | EV_PERSIST, interface_callback, *interface);
- if (!event) {
- return -3;
- }
-
- if (event_add(event, NULL) < 0) {
- return -4;
- }
-#else
- ERROR("Not implemented\n");
- return FACEMGR_FAILURE;
-#endif /* __linux__ */
- }
-
- rc = interface_map_add(&facemgr->interface_map, (*interface)->name, *interface);
- if (FACEMGR_IS_ERROR(rc))
- return -5;
-
- DEBUG("Interface created successfully.\n");
- return FACEMGR_SUCCESS;
-}
-
-int
-facemgr_bootstrap(facemgr_t * facemgr)
-{
- int rc;
-
- DEBUG("Registering interfaces...");
- rc = interface_register(&hicn_light_ops);
- if (FACEMGR_IS_ERROR(rc)) {
- ERROR("Could not register interfaces");
- goto ERR_REGISTER;
- }
-
-#ifdef __APPLE__
- rc = interface_register(&network_framework_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- rc = interface_register(&netlink_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif /* __linux__ */
-
-#if 0
- rc = interface_register(&dummy_ops);
- if (FACEMGR_IS_ERROR(rc))
- goto ERR_REGISTER;
-#endif
-
- rc = facemgr_create_interface(facemgr, "hl", "hicn_light", &facemgr->hl);
- if (rc < 0) {
- ERROR("Error creating 'hICN forwarder (hicn-light)' interface\n");
- goto ERR_HL_CREATE;
- }
-
-#ifdef __APPLE__
- rc = facemgr_create_interface(facemgr, "nf", "network_framework", &facemgr->nf);
- if (rc < 0) {
- ERROR("Error creating 'Apple Network Framework' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- rc = facemgr_create_interface(facemgr, "nl", "netlink", &facemgr->nl);
- if (rc < 0) {
- ERROR("Error creating 'Netlink' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif /* __linux__ */
-
-#if 0
- rc = facemgr_create_interface(facemgr, "dummy", "dummy", &facemgr->dummy);
- if (rc < 0) {
- ERROR("Error creating 'Dummy' interface\n");
- goto ERR_NF_CREATE;
- }
-#endif
-
- DEBUG("Facemgr successfully initialized...");
-
- return FACEMGR_SUCCESS;
-
-ERR_NF_CREATE:
- interface_free(facemgr->hl);
-ERR_HL_CREATE:
- //interface_map_remove(&facemgr->interface_map, data->nf->name);
-ERR_REGISTER:
- return FACEMGR_FAILURE;
-}
diff --git a/ctrl/facemgr/src/facemgr.h b/ctrl/facemgr/src/facemgr.h
deleted file mode 100644
index 6505a1bd8..000000000
--- a/ctrl/facemgr/src/facemgr.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 facemgr.h
- * \brief Face manager library interface
- */
-#ifndef FACEMGR_H
-#define FACEMGR_H
-
-#include <string.h>
-#include "common.h"
-#include "face.h"
-#include "face_cache.h"
-#include "face_rules.h"
-#include "interface.h"
-#include "interface_map.h"
-#include "util/ip_address.h"
-#include "util/map.h"
-#include "util/policy.h"
-#ifndef __APPLE__
-#include <event2/event.h>
-#endif /* __APPLE__ */
-
-/*
- * \brief Face manager context
- */
-typedef struct {
-#ifndef APPLE
- /* Event loop */
- struct event_base * loop;
-#endif /* APPLE */
-
- interface_map_t interface_map;
- interface_t * hl;
-
-#ifdef __APPLE__
- interface_t * nf;
-#endif /* __APPLE__ */
-
-#ifdef __linux__
- interface_t * nl;
-#endif /* __linux__ */
-
-#if 0
- interface_t * dummy;
-#endif
-
- /* Overlay management */
- uint16_t overlay_v4_local_port;
- ip_address_t overlay_v4_remote_addr;
- uint16_t overlay_v4_remote_port;
- uint16_t overlay_v6_local_port;
- ip_address_t overlay_v6_remote_addr;
- uint16_t overlay_v6_remote_port;
-
- face_rules_t rules;
- face_cache_t face_cache;
-} facemgr_t;
-
-AUTOGENERATE_DEFS(facemgr);
-
-int facemgr_bootstrap(facemgr_t * facemgr);
-
-#endif /* FACEMGR_H */
diff --git a/ctrl/facemgr/src/interface.c b/ctrl/facemgr/src/interface.c
index af9f666a7..3e6bc0854 100644
--- a/ctrl/facemgr/src/interface.c
+++ b/ctrl/facemgr/src/interface.c
@@ -20,12 +20,13 @@
#include <stdlib.h>
#include <string.h>
-#include "event.h"
-#include "face_rules.h"
+#include "facelet.h"
#include "interface.h"
-#include "interface_ops_map.h"
#include "util/map.h"
+TYPEDEF_MAP_H(interface_ops_map, const char *, const interface_ops_t *);
+TYPEDEF_MAP(interface_ops_map, const char *, const interface_ops_t *, strcmp, string_snprintf, generic_snprintf);
+
static interface_ops_map_t * interface_ops_map = NULL;
int
@@ -34,19 +35,19 @@ interface_register(const interface_ops_t * ops)
if (!interface_ops_map) {
interface_ops_map = interface_ops_map_create();
if (!interface_ops_map)
- return FACEMGR_FAILURE;
+ return -1;
}
interface_ops_map_add(interface_ops_map, ops->type, ops);
- return FACEMGR_SUCCESS;
+ return 0;
}
interface_t *
interface_create(const char * name, const char * type)
{
- interface_ops_t * ops;
+ const interface_ops_t * ops = NULL;
int rc = interface_ops_map_get(interface_ops_map, type, &ops);
- if (FACEMGR_IS_ERROR(rc)) {
+ if (rc < 0) {
printf("Interface type not found %s\n", type);
return NULL;
}
@@ -80,25 +81,25 @@ _interface_set_callback(interface_t * interface, callback_t callback, void * cal
}
int
-interface_initialize(interface_t * interface, struct face_rules_s * rules)
+interface_initialize(interface_t * interface, void * cfg)
{
if (!interface->ops->initialize)
- return FACEMGR_FAILURE;
- return interface->ops->initialize(interface, rules, &interface->data);
+ return -1;
+ return interface->ops->initialize(interface, cfg);
}
int
interface_finalize(interface_t * interface)
{
if (!interface->ops->finalize)
- return FACEMGR_FAILURE;
+ return -1;
return interface->ops->finalize(interface);
}
int
-interface_on_event(interface_t * interface, const event_t * event)
+interface_on_event(interface_t * interface, const facelet_t * facelet)
{
if (!interface->ops->on_event)
- return FACEMGR_FAILURE;
- return interface->ops->on_event(interface, event);
+ return -1;
+ return interface->ops->on_event(interface, facelet);
}
diff --git a/ctrl/facemgr/src/interface.h b/ctrl/facemgr/src/interface.h
index f38313182..331312bde 100644
--- a/ctrl/facemgr/src/interface.h
+++ b/ctrl/facemgr/src/interface.h
@@ -30,27 +30,30 @@
#include <stdbool.h>
-struct event_s;
-typedef int (*callback_t)(struct event_s * event, void * callback_data);
+struct facelet_s;
+typedef int (*callback_t)(struct facelet_s * facelet, void * callback_data);
struct interface_s;
-struct face_rules_s;
/**
* \brief Interface operations
*/
typedef struct {
+ /** The type given to the interfaces */
char * type;
- bool is_singleton;
- int (*initialize)(struct interface_s * interface, struct face_rules_s * rules, void ** pdata);
+ /* Constructor */
+ int (*initialize)(struct interface_s * interface, void * cfg);
+ /* Destructor */
int (*finalize)(struct interface_s * interface);
+ /* Callback upon file descriptor event (iif previously registered) */
int (*callback)(struct interface_s * interface);
- int (*on_event)(struct interface_s * interface, const struct event_s * event);
+ /* Callback upon face events coming from the face manager */
+ int (*on_event)(struct interface_s * interface, const struct facelet_s * facelet);
} interface_ops_t;
typedef struct interface_s {
char * name;
- interface_ops_t * ops;
+ const interface_ops_t * ops;
callback_t callback;
void * callback_data;
void * data;
@@ -90,9 +93,9 @@ void _interface_set_callback(interface_t * interface, callback_t callback, void
#define interface_set_callback(interface, callback, callback_data) \
_interface_set_callback(interface, (callback_t)callback, (void*)callback_data)
-int interface_initialize(interface_t * interface, struct face_rules_s * rules);
+int interface_initialize(interface_t * interface, void * cfg);
int interface_finalize(interface_t * interface);
-int interface_on_event(interface_t * interface, const struct event_s * event);
+int interface_on_event(interface_t * interface, const struct facelet_s * facelet);
#endif /* FACEMGR_INTERFACE_H */
diff --git a/ctrl/facemgr/src/interface_map.c b/ctrl/facemgr/src/interface_map.c
deleted file mode 100644
index 9f7c20cab..000000000
--- a/ctrl/facemgr/src/interface_map.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "interface_map.h"
-
-#include <string.h>
-#include "interface.h"
-
-TYPEDEF_MAP(interface_map, const char *, interface_t *, strcmp, string_snprintf, generic_snprintf);
diff --git a/ctrl/facemgr/src/interface_ops_map.c b/ctrl/facemgr/src/interface_ops_map.c
deleted file mode 100644
index 373f5d22f..000000000
--- a/ctrl/facemgr/src/interface_ops_map.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "interface_ops_map.h"
-
-#include <string.h>
-#include "util/map.h"
-
-TYPEDEF_MAP(interface_ops_map, const char *, interface_ops_t *, strcmp, string_snprintf, generic_snprintf);
diff --git a/ctrl/facemgr/src/interfaces/CMakeLists.txt b/ctrl/facemgr/src/interfaces/CMakeLists.txt
index e5a26177a..8d079612a 100644
--- a/ctrl/facemgr/src/interfaces/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/CMakeLists.txt
@@ -24,12 +24,21 @@ endif()
if(LINUX)
add_subdirectory(netlink)
+add_subdirectory(bonjour)
endif()
-if(false)
+if(ANDROID)
+add_subdirectory(android_utility)
+endif()
+
+if(WITH_EXAMPLE_DUMMY)
add_subdirectory(dummy)
endif()
+if(WITH_EXAMPLE_UPDOWN)
+add_subdirectory(updown)
+endif()
+
set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt
new file mode 100644
index 000000000..0ebe87745
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/android_utility/CMakeLists.txt
@@ -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.
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/android_utility.c
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+list(APPEND LIBRARIES
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/android_utility/android_utility.c b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c
new file mode 100644
index 000000000..bb612507f
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/android_utility/android_utility.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 interfaces/android_utility/android_utility.c
+ * \brief Implementation of Android utility.
+ */
+
+#include <assert.h>
+
+#include <hicn/facemgr.h>
+#include <hicn/ctrl/face.h>
+#include <hicn/util/log.h>
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+#include <hicn/android_utility/android_utility.h>
+
+#define FACEMGR_ANDROID_UTILITY_CLASS "com/cisco/hicn/forwarder/supportlibrary/AndroidUtility"
+
+#define AU_INTERFACE_TYPE_UNDEFINED 0
+#define AU_INTERFACE_TYPE_WIRED 1
+#define AU_INTERFACE_TYPE_WIFI 2
+#define AU_INTERFACE_TYPE_CELLULAR 3
+#define AU_INTERFACE_TYPE_LOOPBACK 4 /* not supported yet */
+
+#define ERR_STR_JAVA "Java VM parameters are required in the interface configuration."
+
+typedef struct {
+ android_utility_cfg_t cfg;
+} au_data_t;
+
+int au_initialize(interface_t * interface, void * cfg)
+{
+ au_data_t * data = malloc(sizeof(au_data_t));
+ if (!data)
+ return -1;
+ interface->data = data;
+
+ if (!cfg)
+ goto ERR_CFG;
+
+ data->cfg = * (android_utility_cfg_t *) cfg;
+
+ if (!data->cfg.jvm)
+ goto ERR_CFG;
+
+ return 0;
+
+ERR_CFG:
+ fprintf(stderr, ERR_STR_JAVA);
+ return -1;
+}
+
+int au_finalize(interface_t * interface)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+int au_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ /*
+ * This function is responsible to annotate every face we receive with the
+ * correct interface type, based on the value returned by the Android
+ * utility shipped with the Android forwarder.
+ */
+ DEBUG("Android utility received request");
+ au_data_t * data = (au_data_t*)interface->data;
+
+ netdevice_t netdevice = NETDEVICE_EMPTY;
+ int rc = facelet_get_netdevice(facelet, &netdevice);
+ if (rc < 0)
+ return -1;
+ DEBUG("[au_on_event] netdevice=%s", netdevice.name);
+
+ JNIEnv *env;
+ JavaVM *jvm = data->cfg.jvm;
+ (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+ jclass cls = (*env)->FindClass(env, FACEMGR_ANDROID_UTILITY_CLASS);
+ jmethodID getNetworkType = (*env)->GetStaticMethodID(env, cls,
+ "getNetworkType", "(Ljava/lang/String;)I");
+ jint interface_type = (*env)->CallStaticIntMethod(env, cls, getNetworkType,
+ (*env)->NewStringUTF(env, netdevice.name));
+
+ DEBUG("Processing results for interface %s", netdevice.name);
+
+ netdevice_type_t netdevice_type = AU_INTERFACE_TYPE_UNDEFINED;
+ switch(interface_type) {
+ case AU_INTERFACE_TYPE_UNDEFINED:
+ break;
+ case AU_INTERFACE_TYPE_WIRED:
+ netdevice_type = NETDEVICE_TYPE_WIRED;
+ break;
+ case AU_INTERFACE_TYPE_WIFI:
+ netdevice_type = NETDEVICE_TYPE_WIFI;
+ break;
+ case AU_INTERFACE_TYPE_CELLULAR:
+ netdevice_type = NETDEVICE_TYPE_CELLULAR;
+ break;
+ case AU_INTERFACE_TYPE_LOOPBACK:
+ netdevice_type = NETDEVICE_TYPE_LOOPBACK;
+ break;
+ default:
+ return -1;
+ }
+
+ facelet_t * facelet_new = facelet_create();
+ facelet_set_netdevice(facelet_new, netdevice);
+ facelet_set_status(facelet_new, FACELET_STATUS_CLEAN);
+ facelet_set_netdevice_type(facelet_new, netdevice_type);
+
+ DEBUG("sending AU udpate");
+ facelet_set_event(facelet_new, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet_new, interface);
+
+ return 0;
+}
+
+const interface_ops_t android_utility_ops = {
+ .type = "android_utility",
+ .initialize = au_initialize,
+ .finalize = au_finalize,
+ .callback = NULL,
+ .on_event = au_on_event,
+};
diff --git a/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt
new file mode 100644
index 000000000..8a0ddc888
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/CMakeLists.txt
@@ -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.
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/mdns/mdns.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/bonjour.c
+)
+
+list(APPEND LIBRARIES
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/bonjour/bonjour.c b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c
new file mode 100644
index 000000000..d7b27b995
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 interfaces/bonjour/bonjour.c
+ * \brief Implementation of Bonjour interface
+ *
+ * TODO:
+ * - concurrent queries
+ * - interface binding
+ */
+
+#include <hicn/facemgr.h>
+#include <hicn/util/log.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+#include "../../util/map.h"
+#include "mdns/mdns.h"
+
+#include "bonjour.h"
+
+#define DEFAULT_BUFFER_SIZE 2048
+#define SERVICE_STRING_SIZE 256
+
+#define DEFAULT_SERVICE_NAME "hicn"
+#define DEFAULT_SERVICE_PROTOCOL "udp"
+#define DEFAULT_SERVICE_DOMAIN "local"
+
+typedef struct {
+ bonjour_cfg_t cfg;
+ int sock;
+ size_t buffer_size;
+ void* buffer;
+
+ /* The face being resolved, non-NULL values indicate interface is busy... */
+ face_t * face;
+} bj_data_t;
+
+int bj_initialize(interface_t * interface, void * cfg)
+{
+ bj_data_t * data = malloc(sizeof(bj_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ if (cfg) {
+#ifndef __linux__
+ if (cfg->netdevice)
+ WARN("Binding to interface is (currently) only supported on Linux");
+#endif /* ! __linux__ */
+ data->cfg = * (bonjour_cfg_t *) cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(bonjour_cfg_t));
+ }
+
+ if (!data->cfg.service_name)
+ data->cfg.service_name = DEFAULT_SERVICE_NAME;
+
+ if (!data->cfg.service_protocol)
+ data->cfg.service_protocol = DEFAULT_SERVICE_PROTOCOL;
+
+ if (!data->cfg.service_domain)
+ data->cfg.service_domain = DEFAULT_SERVICE_DOMAIN;
+
+ data->sock = mdns_socket_open_ipv4();
+ if (data->sock < 0) {
+ printf("Failed to open socket: %s\n", strerror(errno));
+ goto ERR_SOCK;
+ }
+
+ /* Netdevice configuration */
+#ifdef __linux__
+#ifndef __ANDROID__
+ if (IS_VALID_NETDEVICE(data->cfg.netdevice)) {
+ int rc = setsockopt(data->sock, SOL_SOCKET, SO_BINDTODEVICE,
+ &data->cfg.netdevice.name, strlen(data->cfg.netdevice.name) + 1);
+ if (rc == -1) {
+ ERROR("setsockopt");
+ goto ERR_SOCK_OPT;
+ }
+ }
+#endif
+#endif /* __linux__ */
+
+ data->buffer_size = DEFAULT_BUFFER_SIZE;
+ data->buffer = malloc(data->buffer_size);
+ if (!data->buffer)
+ goto ERR_BUFFER;
+
+#ifdef _WIN32
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ WSAStartup(versionWanted, &wsaData);
+#endif
+
+ return data->sock;
+
+ERR_BUFFER:
+#ifndef __ANDROID__
+ERR_SOCK_OPT:
+#endif
+ mdns_socket_close(data->sock);
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ERR_SOCK:
+ free(data);
+ERR_MALLOC:
+ return -1;
+}
+
+/*
+ * We reuse the callback to be triggered upon external events
+ * TODO: move to a cleaner interface architecture later...
+ */
+int bj_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+
+ /*
+ printf("Sending DNS-SD discovery\n");
+ if (mdns_discovery_send(sock)) {
+ printf("Failed to send DNS-DS discovery: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ printf("Reading DNS-SD replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_discovery_recv(sock, buffer, capacity, callback,
+ user_data);
+ sleep(1);
+ }
+ */
+
+ DEBUG("Sending mDNS query");
+ char service_string[SERVICE_STRING_SIZE];
+
+ int rc = snprintf(service_string, SERVICE_STRING_SIZE, "_%s._%s.%s.",
+ data->cfg.service_name, data->cfg.service_protocol,
+ data->cfg.service_domain);
+ if (rc < 0)
+ ; // error
+ else if (rc >= SERVICE_STRING_SIZE)
+ ; //truncated
+
+ if (mdns_query_send(data->sock, MDNS_RECORDTYPE_PTR,
+ service_string,
+ strlen(service_string),
+ data->buffer, data->buffer_size)) {
+ printf("Failed to send mDNS query: %s\n", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static char addrbuffer[64];
+static char namebuffer[256];
+static mdns_record_txt_t txtbuffer[128];
+
+static mdns_string_t
+ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin_port != 0)
+ len = snprintf(buffer, capacity, "%s:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin6_port != 0)
+ len = snprintf(buffer, capacity, "[%s]:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) {
+ if (addr->sa_family == AF_INET6)
+ return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr);
+ return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr);
+}
+
+int
+ip_address_set_sockaddr(ip_address_t * ip_address, struct sockaddr * sa)
+{
+ switch(sa->sa_family) {
+ case AF_INET:
+ ip_address->v4.as_inaddr = ((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_INET6:
+ ip_address->v6.as_in6addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+callback(const struct sockaddr* from, mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl, const void* data, size_t size, size_t
+ offset, size_t length, void* user_data)
+{
+ interface_t * interface = (interface_t*)user_data;
+ bj_data_t * bj_data = (bj_data_t *)interface->data;
+
+ struct sockaddr_storage addr;
+
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from);
+ const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
+ ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
+
+ switch(type) {
+ case MDNS_RECORDTYPE_A:
+ {
+ ip_address_t ip_address;
+ mdns_record_parse_a(data, size, offset, length, (struct sockaddr_in*)&addr);
+ ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr);
+
+ mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), (struct sockaddr_in *)&addr);
+ DEBUG("%.*s : %s A %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET);
+ facelet_set_remote_addr(facelet, ip_address);
+ //facelet_set_remote_port(facelet, ((struct sockaddr_in*)&addr)->sin_port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet, interface);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_AAAA:
+ {
+ ip_address_t ip_address;
+ mdns_record_parse_aaaa(data, size, offset, length, (struct sockaddr_in6*)&addr);
+ ip_address_set_sockaddr(&ip_address, (struct sockaddr *)&addr);
+
+ mdns_string_t addrstr = ipv6_address_to_string(namebuffer,
+ sizeof(namebuffer), (struct sockaddr_in6*)&addr);
+ DEBUG("%.*s : %s AAAA %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET6);
+ facelet_set_remote_addr(facelet, ip_address);
+ //facelet_set_remote_port(facelet, ((struct sockaddr_in6*)&addr)->sin6_port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet, interface);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_SRV: /* same port for both v4 and v6 */
+ {
+ mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+
+ DEBUG("%.*s : %s SRV %.*s priority %d weight %d port %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
+
+ /* We raise both v4 and v6
+ *
+ * Unless we choose whether we query A and/or AAAA, this might leave
+ * us with an unused pending facelet, eg. we might not have an IPv6
+ * but we raise an IPv6 bonjour event...
+ */
+
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET);
+ facelet_set_remote_port(facelet, srv.port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet, interface);
+
+ facelet = facelet_create();
+ facelet_set_netdevice(facelet, bj_data->cfg.netdevice);
+ facelet_set_family(facelet, AF_INET6);
+ facelet_set_remote_port(facelet, srv.port);
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet, interface);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_PTR:
+ {
+ mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ DEBUG("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length);
+ break;
+ }
+
+ case MDNS_RECORDTYPE_TXT:
+ {
+ size_t parsed = mdns_record_parse_txt(data, size, offset, length,
+ txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
+ for (size_t itxt = 0; itxt < parsed; ++itxt) {
+ if (txtbuffer[itxt].value.length) {
+ DEBUG("%.*s : %s TXT %.*s = %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].value));
+ }
+ else {
+ DEBUG("%.*s : %s TXT %.*s",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key));
+ }
+ }
+ break;
+ }
+
+ default:
+ /* Silently ignore the received record */
+ DEBUG("%.*s : %s type %u rclass 0x%x ttl %u length %d",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ type, rclass, ttl, (int)length);
+ return 0;
+ }
+ return 0;
+
+}
+
+/*
+ * The fact we use a single fd does not allow us to get user_data associated to
+ * the query.
+ */
+int bj_callback(interface_t * interface)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+ DEBUG("Got an mDNS reply");
+ /* size_t records = */ mdns_query_recv(data->sock, data->buffer, data->buffer_size, callback, interface, 1);
+
+ return 0;
+}
+
+int bj_finalize(interface_t * interface)
+{
+ bj_data_t * data = (bj_data_t*)interface->data;
+
+ free(data->buffer);
+ mdns_socket_close(data->sock);
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return 0;
+
+}
+
+const interface_ops_t bonjour_ops = {
+ .type = "bonjour",
+ .initialize = bj_initialize,
+ .on_event = bj_on_event,
+ .callback = bj_callback,
+ .finalize = bj_finalize,
+ // .on_event = NULL,
+};
diff --git a/ctrl/facemgr/src/face_rules.h b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h
index 28f5391a0..fe053079d 100644
--- a/ctrl/facemgr/src/face_rules.h
+++ b/ctrl/facemgr/src/interfaces/bonjour/bonjour.h
@@ -13,19 +13,23 @@
* limitations under the License.
*/
-#ifndef FACE_RULES_H
-#define FACE_RULES_H
-
-#include "util/map.h"
-#include "util/policy.h"
-
-/*
- * Face creation rules
+/**
+ * \file interfaces/bonjour/bonjour.h
+ * \brief Bonjour interface
*
- * For now, face creations rules are very simple and consist in a map between
- * the physical interface name, and the associated list of tags that will
- * preempt those assigned by the system.
+ * NOTES:
+ * - shall we support multiple service names, or instanciate multiple instances
+ * of the interface ?
+ * - interface list ?
+ * - ideally we should register here events that will trigger bonjour
+ * queries...
*/
-TYPEDEF_MAP_H(face_rules, const char *, policy_tags_t);
-#endif /* FACE_RULES_H */
+#include <hicn/ctrl/face.h> /* netdevice_t */
+
+typedef struct {
+ netdevice_t netdevice;
+ char * service_name;
+ char * service_protocol;
+ char * service_domain;
+} bonjour_cfg_t;
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE
new file mode 100644
index 000000000..cf1ab25da
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md
new file mode 100644
index 000000000..1bee49c08
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/README.md
@@ -0,0 +1,9 @@
+# Public domain mDNS/DNS-SD library in C
+
+This library provides a cross-platform mDNS and DNS-DS library in C. The latest source code is always available at
+
+https://github.com/mjansson/mdns
+
+This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+
+Created by Mattias Jansson ([@maniccoder](https://twitter.com/maniccoder))
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c
new file mode 100644
index 000000000..a8e97e8e0
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.c
@@ -0,0 +1,192 @@
+
+#ifdef _WIN32
+# define _CRT_SECURE_NO_WARNINGS 1
+#endif
+
+#include "mdns.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef _WIN32
+# define sleep(x) Sleep(x * 1000)
+#else
+# include <netdb.h>
+#endif
+
+static char addrbuffer[64];
+static char namebuffer[256];
+static mdns_record_txt_t txtbuffer[128];
+
+static mdns_string_t
+ipv4_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin_port != 0)
+ len = snprintf(buffer, capacity, "%s:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ipv6_address_to_string(char* buffer, size_t capacity, const struct sockaddr_in6* addr) {
+ char host[NI_MAXHOST] = {0};
+ char service[NI_MAXSERV] = {0};
+ int ret = getnameinfo((const struct sockaddr*)addr, sizeof(struct sockaddr_in6),
+ host, NI_MAXHOST, service, NI_MAXSERV,
+ NI_NUMERICSERV | NI_NUMERICHOST);
+ int len = 0;
+ if (ret == 0) {
+ if (addr->sin6_port != 0)
+ len = snprintf(buffer, capacity, "[%s]:%s", host, service);
+ else
+ len = snprintf(buffer, capacity, "%s", host);
+ }
+ if (len >= (int)capacity)
+ len = (int)capacity - 1;
+ mdns_string_t str = {buffer, len};
+ return str;
+}
+
+static mdns_string_t
+ip_address_to_string(char* buffer, size_t capacity, const struct sockaddr* addr) {
+ if (addr->sa_family == AF_INET6)
+ return ipv6_address_to_string(buffer, capacity, (const struct sockaddr_in6*)addr);
+ return ipv4_address_to_string(buffer, capacity, (const struct sockaddr_in*)addr);
+}
+
+static int
+callback(const struct sockaddr* from,
+ mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl,
+ const void* data, size_t size, size_t offset, size_t length,
+ void* user_data) {
+ mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer, sizeof(addrbuffer), from);
+ const char* entrytype = (entry == MDNS_ENTRYTYPE_ANSWER) ? "answer" :
+ ((entry == MDNS_ENTRYTYPE_AUTHORITY) ? "authority" : "additional");
+ if (type == MDNS_RECORDTYPE_PTR) {
+ mdns_string_t namestr = mdns_record_parse_ptr(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ INFO("%.*s : %s PTR %.*s type %u rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(namestr), type, rclass, ttl, (int)length);
+ }
+ else if (type == MDNS_RECORDTYPE_SRV) {
+ mdns_record_srv_t srv = mdns_record_parse_srv(data, size, offset, length,
+ namebuffer, sizeof(namebuffer));
+ INFO("%.*s : %s SRV %.*s priority %d weight %d port %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(srv.name), srv.priority, srv.weight, srv.port);
+ }
+ else if (type == MDNS_RECORDTYPE_A) {
+ struct sockaddr_in addr;
+ mdns_record_parse_a(data, size, offset, length, &addr);
+ mdns_string_t addrstr = ipv4_address_to_string(namebuffer, sizeof(namebuffer), &addr);
+ INFO("%.*s : %s A %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+ }
+ else if (type == MDNS_RECORDTYPE_AAAA) {
+ struct sockaddr_in6 addr;
+ mdns_record_parse_aaaa(data, size, offset, length, &addr);
+ mdns_string_t addrstr = ipv6_address_to_string(namebuffer, sizeof(namebuffer), &addr);
+ INFO("%.*s : %s AAAA %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(addrstr));
+ }
+ else if (type == MDNS_RECORDTYPE_TXT) {
+ size_t parsed = mdns_record_parse_txt(data, size, offset, length,
+ txtbuffer, sizeof(txtbuffer) / sizeof(mdns_record_txt_t));
+ for (size_t itxt = 0; itxt < parsed; ++itxt) {
+ if (txtbuffer[itxt].value.length) {
+ INFO("%.*s : %s TXT %.*s = %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key),
+ MDNS_STRING_FORMAT(txtbuffer[itxt].value));
+ }
+ else {
+ INFO("%.*s : %s TXT %.*s\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ MDNS_STRING_FORMAT(txtbuffer[itxt].key));
+ }
+ }
+ }
+ else {
+ INFO("%.*s : %s type %u rclass 0x%x ttl %u length %d\n",
+ MDNS_STRING_FORMAT(fromaddrstr), entrytype,
+ type, rclass, ttl, (int)length);
+ }
+ return 0;
+}
+
+int
+main() {
+ size_t capacity = 2048;
+ void* buffer = 0;
+ void* user_data = 0;
+ size_t records;
+
+#ifdef _WIN32
+ WORD versionWanted = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ WSAStartup(versionWanted, &wsaData);
+#endif
+
+ int sock = mdns_socket_open_ipv4();
+ if (sock < 0) {
+ INFO("Failed to open socket: %s\n", strerror(errno));
+ return -1;
+ }
+ INFO("Opened IPv4 socket for mDNS/DNS-SD\n");
+ buffer = malloc(capacity);
+/*
+ INFO("Sending DNS-SD discovery\n");
+ if (mdns_discovery_send(sock)) {
+ INFO("Failed to send DNS-DS discovery: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ INFO("Reading DNS-SD replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_discovery_recv(sock, buffer, capacity, callback,
+ user_data);
+ sleep(1);
+ }
+ */
+
+ INFO("Sending mDNS query\n");
+ if (mdns_query_send(sock, MDNS_RECORDTYPE_PTR,
+ MDNS_STRING_CONST("_hicn._udp.local."),
+ buffer, capacity)) {
+ INFO("Failed to send mDNS query: %s\n", strerror(errno));
+ goto quit;
+ }
+
+ INFO("Reading mDNS replies\n");
+ for (int i = 0; i < 10; ++i) {
+ records = mdns_query_recv(sock, buffer, capacity, callback, user_data, 1);
+ sleep(1);
+ }
+
+quit:
+ free(buffer);
+
+ mdns_socket_close(sock);
+ INFO("Closed socket\n");
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ return 0;
+}
diff --git a/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h
new file mode 100644
index 000000000..ff04b5d72
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/bonjour/mdns/mdns.h
@@ -0,0 +1,879 @@
+/* mdns.h - mDNS/DNS-SD library - Public Domain - 2017 Mattias Jansson
+ *
+ * This library provides a cross-platform mDNS and DNS-SD library in C.
+ * The implementation is based on RFC 6762 and RFC 6763.
+ *
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/mdns
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#ifdef _WIN32
+#include <Winsock2.h>
+#include <Ws2tcpip.h>
+#define strncasecmp _strnicmp
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+
+#define MDNS_INVALID_POS ((size_t)-1)
+
+#define MDNS_STRING_CONST(s) (s), (sizeof((s))-1)
+#define MDNS_STRING_FORMAT(s) (int)((s).length), s.str
+
+enum mdns_record_type {
+ MDNS_RECORDTYPE_IGNORE = 0,
+ //Address
+ MDNS_RECORDTYPE_A = 1,
+ //Domain Name pointer
+ MDNS_RECORDTYPE_PTR = 12,
+ //Arbitrary text string
+ MDNS_RECORDTYPE_TXT = 16,
+ //IP6 Address [Thomson]
+ MDNS_RECORDTYPE_AAAA = 28,
+ //Server Selection [RFC2782]
+ MDNS_RECORDTYPE_SRV = 33
+};
+
+enum mdns_entry_type {
+ MDNS_ENTRYTYPE_ANSWER = 1,
+ MDNS_ENTRYTYPE_AUTHORITY = 2,
+ MDNS_ENTRYTYPE_ADDITIONAL = 3
+};
+
+enum mdns_class {
+ MDNS_CLASS_IN = 1
+};
+
+typedef enum mdns_record_type mdns_record_type_t;
+typedef enum mdns_entry_type mdns_entry_type_t;
+typedef enum mdns_class mdns_class_t;
+
+typedef int (* mdns_record_callback_fn)(const struct sockaddr* from,
+ mdns_entry_type_t entry, uint16_t type,
+ uint16_t rclass, uint32_t ttl,
+ const void* data, size_t size, size_t offset, size_t length,
+ void* user_data);
+
+typedef struct mdns_string_t mdns_string_t;
+typedef struct mdns_string_pair_t mdns_string_pair_t;
+typedef struct mdns_record_srv_t mdns_record_srv_t;
+typedef struct mdns_record_txt_t mdns_record_txt_t;
+
+struct mdns_string_t {
+ const char* str;
+ size_t length;
+};
+
+struct mdns_string_pair_t {
+ size_t offset;
+ size_t length;
+ int ref;
+};
+
+struct mdns_record_srv_t {
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ mdns_string_t name;
+};
+
+struct mdns_record_txt_t {
+ mdns_string_t key;
+ mdns_string_t value;
+};
+
+static int
+mdns_socket_open_ipv4(void);
+
+static int
+mdns_socket_setup_ipv4(int sock);
+
+#if 0
+static int
+mdns_socket_open_ipv6(void);
+
+
+
+static int
+mdns_socket_setup_ipv6(int sock);
+#endif
+
+static void
+mdns_socket_close(int sock);
+
+#if 0
+static int
+mdns_discovery_send(int sock);
+
+
+static size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data);
+#endif
+
+static int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length,
+ void* buffer, size_t capacity);
+
+static size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data,
+ uint8_t one_shot);
+
+static mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset,
+ char* str, size_t capacity);
+
+static int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset);
+
+#if 0
+static int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs,
+ const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs);
+#endif
+
+static void*
+mdns_string_make(void* data, size_t capacity, const char* name, size_t length);
+
+static mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+static mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity);
+
+static struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr);
+
+static struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr);
+
+static size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity);
+
+// Implementations
+
+static int
+mdns_socket_open_ipv4(void) {
+ int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv4(sock)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+static int
+mdns_socket_setup_ipv4(int sock) {
+ struct sockaddr_in saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = INADDR_ANY;
+#ifdef __APPLE__
+ saddr.sin_len = sizeof(saddr);
+#endif
+
+ if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, &param);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ unsigned char ttl = 1;
+ unsigned char loopback = 1;
+ struct ip_mreq req;
+
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof(ttl));
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ req.imr_interface.s_addr = INADDR_ANY;
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&req, sizeof(req)))
+ return -1;
+
+ return 0;
+}
+
+#if 0
+static int
+mdns_socket_open_ipv6(void) {
+ int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return -1;
+ if (mdns_socket_setup_ipv6(sock)) {
+ mdns_socket_close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+
+static int
+mdns_socket_setup_ipv6(int sock) {
+ struct sockaddr_in6 saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin6_family = AF_INET6;
+ saddr.sin6_addr = in6addr_any;
+#ifdef __APPLE__
+ saddr.sin6_len = sizeof(saddr);
+#endif
+
+ if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)))
+ return -1;
+
+#ifdef _WIN32
+ unsigned long param = 1;
+ ioctlsocket(sock, FIONBIO, &param);
+#else
+ const int flags = fcntl(sock, F_GETFL, 0);
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+#endif
+
+ int hops = 1;
+ unsigned int loopback = 1;
+ struct ipv6_mreq req;
+
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*)&hops, sizeof(hops));
+ setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const char*)&loopback, sizeof(loopback));
+
+ memset(&req, 0, sizeof(req));
+ req.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
+ req.ipv6mr_multiaddr.s6_addr[1] = 0x02;
+ req.ipv6mr_multiaddr.s6_addr[15] = 0xFB;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&req, sizeof(req)))
+ return -1;
+
+ return 0;
+}
+#endif
+
+static void
+mdns_socket_close(int sock) {
+#ifdef _WIN32
+ closesocket(sock);
+#else
+ close(sock);
+#endif
+}
+
+static int
+mdns_is_string_ref(uint8_t val) {
+ return (0xC0 == (val & 0xC0));
+}
+
+static mdns_string_pair_t
+mdns_get_next_substring(const void* rawdata, size_t size, size_t offset) {
+ const uint8_t* buffer = rawdata;
+ mdns_string_pair_t pair = {MDNS_INVALID_POS, 0, 0};
+ if (!buffer[offset]) {
+ pair.offset = offset;
+ return pair;
+ }
+ if (mdns_is_string_ref(buffer[offset])) {
+ if (size < offset + 2)
+ return pair;
+
+ offset = (((size_t)(0x3f & buffer[offset]) << 8) | (size_t)buffer[offset + 1]);
+ if (offset >= size)
+ return pair;
+
+ pair.ref = 1;
+ }
+
+ size_t length = (size_t)buffer[offset++];
+ if (size < offset + length)
+ return pair;
+
+ pair.offset = offset;
+ pair.length = length;
+
+ return pair;
+}
+
+static int
+mdns_string_skip(const void* buffer, size_t size, size_t* offset) {
+ size_t cur = *offset;
+ mdns_string_pair_t substr;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if (substr.offset == MDNS_INVALID_POS)
+ return 0;
+ if (substr.ref) {
+ *offset = cur + 2;
+ return 1;
+ }
+ cur = substr.offset + substr.length;
+ }
+ while (substr.length);
+
+ *offset = cur + 1;
+ return 1;
+}
+
+#if 0
+static int
+mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs,
+ const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs) {
+ size_t lhs_cur = *ofs_lhs;
+ size_t rhs_cur = *ofs_rhs;
+ size_t lhs_end = MDNS_INVALID_POS;
+ size_t rhs_end = MDNS_INVALID_POS;
+ mdns_string_pair_t lhs_substr;
+ mdns_string_pair_t rhs_substr;
+ do {
+ lhs_substr = mdns_get_next_substring(buffer_lhs, size_lhs, lhs_cur);
+ rhs_substr = mdns_get_next_substring(buffer_rhs, size_rhs, rhs_cur);
+ if ((lhs_substr.offset == MDNS_INVALID_POS) || (rhs_substr.offset == MDNS_INVALID_POS))
+ return 0;
+ if (lhs_substr.length != rhs_substr.length)
+ return 0;
+ if (strncasecmp((const char*)buffer_rhs + rhs_substr.offset,
+ (const char*)buffer_lhs + lhs_substr.offset, rhs_substr.length))
+ return 0;
+ if (lhs_substr.ref && (lhs_end == MDNS_INVALID_POS))
+ lhs_end = lhs_cur + 2;
+ if (rhs_substr.ref && (rhs_end == MDNS_INVALID_POS))
+ rhs_end = rhs_cur + 2;
+ lhs_cur = lhs_substr.offset + lhs_substr.length;
+ rhs_cur = rhs_substr.offset + rhs_substr.length;
+ }
+ while (lhs_substr.length);
+
+ if (lhs_end == MDNS_INVALID_POS)
+ lhs_end = lhs_cur + 1;
+ *ofs_lhs = lhs_end;
+
+ if (rhs_end == MDNS_INVALID_POS)
+ rhs_end = rhs_cur + 1;
+ *ofs_rhs = rhs_end;
+
+ return 1;
+}
+#endif
+
+static mdns_string_t
+mdns_string_extract(const void* buffer, size_t size, size_t* offset,
+ char* str, size_t capacity) {
+ size_t cur = *offset;
+ size_t end = MDNS_INVALID_POS;
+ mdns_string_pair_t substr;
+ mdns_string_t result = {str, 0};
+ char* dst = str;
+ size_t remain = capacity;
+ do {
+ substr = mdns_get_next_substring(buffer, size, cur);
+ if (substr.offset == MDNS_INVALID_POS)
+ return result;
+ if (substr.ref && (end == MDNS_INVALID_POS))
+ end = cur + 2;
+ if (substr.length) {
+ size_t to_copy = (substr.length < remain) ? substr.length : remain;
+ memcpy(dst, (const char*)buffer + substr.offset, to_copy);
+ dst += to_copy;
+ remain -= to_copy;
+ if (remain) {
+ *dst++ = '.';
+ --remain;
+ }
+ }
+ cur = substr.offset + substr.length;
+ }
+ while (substr.length);
+
+ if (end == MDNS_INVALID_POS)
+ end = cur + 1;
+ *offset = end;
+
+ result.length = capacity - remain;
+ return result;
+}
+
+static size_t
+mdns_string_find(const char* str, size_t length, char c, size_t offset) {
+ const void* found;
+ if (offset >= length)
+ return MDNS_INVALID_POS;
+ found = memchr(str + offset, c, length - offset);
+ if (found)
+ return (size_t)((const char*)found - str);
+ return MDNS_INVALID_POS;
+}
+
+static void*
+mdns_string_make(void* data, size_t capacity, const char* name, size_t length) {
+ size_t pos = 0;
+ size_t last_pos = 0;
+ size_t remain = capacity;
+ unsigned char* dest = data;
+ while ((last_pos < length) && ((pos = mdns_string_find(name, length, '.', last_pos)) != MDNS_INVALID_POS)) {
+ size_t sublength = pos - last_pos;
+ if (sublength < remain) {
+ *dest = (unsigned char)sublength;
+ memcpy(dest + 1, name + last_pos, sublength);
+ dest += sublength + 1;
+ remain -= sublength + 1;
+ }
+ else {
+ return 0;
+ }
+ last_pos = pos + 1;
+ }
+ if (last_pos < length) {
+ size_t sublength = length - last_pos;
+ if (sublength < capacity) {
+ *dest = (unsigned char)sublength;
+ memcpy(dest + 1, name + last_pos, sublength);
+ dest += sublength + 1;
+ remain -= sublength + 1;
+ }
+ else {
+ return 0;
+ }
+ }
+ if (!remain)
+ return 0;
+ *dest++ = 0;
+ return dest;
+}
+
+static size_t
+mdns_records_parse(const struct sockaddr* from, const void* buffer, size_t size, size_t* offset,
+ mdns_entry_type_t type, size_t records, mdns_record_callback_fn callback,
+ void* user_data) {
+ size_t parsed = 0;
+ int do_callback = 1;
+ for (size_t i = 0; i < records; ++i) {
+ mdns_string_skip(buffer, size, offset);
+ const uint16_t* data = (const uint16_t*)((const char*)buffer + (*offset));
+
+ uint16_t rtype = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+ uint32_t ttl = ntohs(*(const uint32_t*)(const void*)data); data += 2;
+ uint16_t length = ntohs(*data++);
+
+ *offset += 10;
+
+ if (do_callback) {
+ ++parsed;
+ if (callback(from, type, rtype, rclass, ttl, buffer, size, *offset, length,
+ user_data))
+ do_callback = 0;
+ }
+
+ *offset += length;
+ }
+ return parsed;
+}
+
+static const uint8_t mdns_services_query[] = {
+ // Transaction ID
+ 0x00, 0x00,
+ // Flags
+ 0x00, 0x00,
+ // 1 question
+ 0x00, 0x01,
+ // No answer, authority or additional RRs
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+ // _services._dns-sd._udp.local.
+ 0x09, '_', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's',
+ 0x07, '_', 'd', 'n', 's', '-', 's', 'd',
+ 0x04, '_', 'u', 'd', 'p',
+ 0x05, 'l', 'o', 'c', 'a', 'l',
+ 0x00,
+ // PTR record
+ 0x00, MDNS_RECORDTYPE_PTR,
+ // QU (unicast response) and class IN
+ 0x80, MDNS_CLASS_IN
+};
+
+#if 0
+static int
+mdns_discovery_send(int sock) {
+ struct sockaddr_storage addr_storage;
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(struct sockaddr_storage);
+ if (getsockname(sock, saddr, &saddrlen))
+ return -1;
+ if (saddr->sa_family == AF_INET6) {
+ memset(&addr6, 0, sizeof(struct sockaddr_in6));
+ addr6.sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ addr6.sin6_addr.s6_addr[0] = 0xFF;
+ addr6.sin6_addr.s6_addr[1] = 0x02;
+ addr6.sin6_addr.s6_addr[15] = 0xFB;
+ addr6.sin6_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr6;
+ saddrlen = sizeof(struct sockaddr_in6);
+ }
+ else {
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+#ifdef __APPLE__
+ addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ addr.sin_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr;
+ saddrlen = sizeof(struct sockaddr_in);
+ }
+
+ if (sendto(sock, mdns_services_query, sizeof(mdns_services_query), 0,
+ saddr, saddrlen) < 0)
+ return -1;
+ return 0;
+}
+
+static size_t
+mdns_discovery_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ memset(&addr, 0, sizeof(addr));
+ saddr->sa_family = AF_INET;
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ socklen_t addrlen = sizeof(addr);
+ int ret = recvfrom(sock, buffer, capacity, 0,
+ saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ size_t records = 0;
+ uint16_t* data = (uint16_t*)buffer;
+
+ uint16_t transaction_id = ntohs(*data++);
+ uint16_t flags = ntohs(*data++);
+ uint16_t questions = ntohs(*data++);
+ uint16_t answer_rrs = ntohs(*data++);
+ uint16_t authority_rrs = ntohs(*data++);
+ uint16_t additional_rrs = ntohs(*data++);
+
+ if (transaction_id || (flags != 0x8400))
+ return 0; //Not a reply to our question
+
+ if (questions > 1)
+ return 0;
+
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ size_t verify_ofs = 12;
+ //Verify it's our question, _services._dns-sd._udp.local.
+ if (!mdns_string_equal(buffer, data_size, &ofs,
+ mdns_services_query, sizeof(mdns_services_query), &verify_ofs))
+ return 0;
+ data = (uint16_t*)((char*)buffer + ofs);
+
+ uint16_t type = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+
+ //Make sure we get a reply based on our PTR question for class IN
+ if ((type != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
+ return 0;
+ }
+
+ int do_callback = 1;
+ for (i = 0; i < answer_rrs; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ size_t verify_ofs = 12;
+ //Verify it's an answer to our question, _services._dns-sd._udp.local.
+ int is_answer = mdns_string_equal(buffer, data_size, &ofs,
+ mdns_services_query, sizeof(mdns_services_query), &verify_ofs);
+ data = (uint16_t*)((char*)buffer + ofs);
+
+ uint16_t type = ntohs(*data++);
+ uint16_t rclass = ntohs(*data++);
+ uint32_t ttl = ntohl(*(uint32_t*)(void*)data); data += 2;
+ uint16_t length = ntohs(*data++);
+
+ if (is_answer && do_callback) {
+ ++records;
+ if (callback(saddr, MDNS_ENTRYTYPE_ANSWER, type, rclass, ttl, buffer,
+ data_size, (size_t)((char*)data - (char*)buffer), length,
+ user_data))
+ do_callback = 0;
+ }
+ data = (void*)((char*)data + length);
+ }
+
+ size_t offset = (size_t)((char*)data - (char*)buffer);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, authority_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs,
+ callback, user_data);
+
+ return records;
+}
+#endif
+
+static uint16_t mdns_transaction_id = 0;
+
+static int
+mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length,
+ void* buffer, size_t capacity) {
+ if (capacity < (17 + length))
+ return -1;
+
+ uint16_t* data = buffer;
+ //Transaction ID
+ *data++ = htons(++mdns_transaction_id);
+ //Flags
+ *data++ = 0;
+ //Questions
+ *data++ = htons(1);
+ //No answer, authority or additional RRs
+ *data++ = 0;
+ *data++ = 0;
+ *data++ = 0;
+ //Name string
+ data = mdns_string_make(data, capacity - 17, name, length);
+ if (!data)
+ return -1;
+ //Record type
+ *data++ = htons(type);
+ //! Unicast response, class IN
+ *data++ = htons(0x8000U | MDNS_CLASS_IN);
+
+ struct sockaddr_storage addr_storage;
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
+ socklen_t saddrlen = sizeof(struct sockaddr_storage);
+ if (getsockname(sock, saddr, &saddrlen))
+ return -1;
+ if (saddr->sa_family == AF_INET6) {
+ memset(&addr6, 0, sizeof(struct sockaddr_in6));
+ addr6.sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ addr6.sin6_addr.s6_addr[0] = 0xFF;
+ addr6.sin6_addr.s6_addr[1] = 0x02;
+ addr6.sin6_addr.s6_addr[15] = 0xFB;
+ addr6.sin6_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr6;
+ saddrlen = sizeof(struct sockaddr_in6);
+ }
+ else {
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+#ifdef __APPLE__
+ addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
+ addr.sin_port = htons((unsigned short)5353);
+ saddr = (struct sockaddr*)&addr;
+ saddrlen = sizeof(struct sockaddr_in);
+ }
+
+ if (sendto(sock, buffer, (char*)data - (char*)buffer, 0,
+ saddr, saddrlen) < 0)
+ return -1;
+ return 0;
+}
+
+static size_t
+mdns_query_recv(int sock, void* buffer, size_t capacity,
+ mdns_record_callback_fn callback, void* user_data,
+ uint8_t one_shot) {
+ struct sockaddr_in6 addr;
+ struct sockaddr* saddr = (struct sockaddr*)&addr;
+ memset(&addr, 0, sizeof(addr));
+ saddr->sa_family = AF_INET;
+#ifdef __APPLE__
+ saddr->sa_len = sizeof(addr);
+#endif
+ socklen_t addrlen = sizeof(addr);
+ int ret = recvfrom(sock, buffer, capacity, 0,
+ saddr, &addrlen);
+ if (ret <= 0)
+ return 0;
+
+ size_t data_size = (size_t)ret;
+ uint16_t* data = (uint16_t*)buffer;
+
+ uint16_t transaction_id = ntohs(*data++);
+ ++data;// uint16_t flags = ntohs(*data++);
+ uint16_t questions = ntohs(*data++);
+ uint16_t answer_rrs = ntohs(*data++);
+ uint16_t authority_rrs = ntohs(*data++);
+ uint16_t additional_rrs = ntohs(*data++);
+
+ if (one_shot && transaction_id != mdns_transaction_id)// || (flags != 0x8400))
+ return 0; //Not a reply to our last question
+
+ if (questions > 1)
+ return 0;
+
+ //Skip questions part
+ int i;
+ for (i = 0; i < questions; ++i) {
+ size_t ofs = (size_t)((char*)data - (char*)buffer);
+ if (!mdns_string_skip(buffer, data_size, &ofs))
+ return 0;
+ data = (void*)((char*)buffer + ofs);
+ ++data;
+ ++data;
+ }
+
+ size_t records = 0;
+ size_t offset = (size_t)((char*)data - (char*)buffer);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ANSWER, answer_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_AUTHORITY, authority_rrs,
+ callback, user_data);
+ records += mdns_records_parse(saddr, buffer, data_size, &offset,
+ MDNS_ENTRYTYPE_ADDITIONAL, additional_rrs,
+ callback, user_data);
+ return records;
+}
+
+static mdns_string_t
+mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ //PTR record is just a string
+ if ((size >= offset + length) && (length >= 2))
+ return mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ mdns_string_t empty = {0, 0};
+ return empty;
+}
+
+static mdns_record_srv_t
+mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t length,
+ char* strbuffer, size_t capacity) {
+ mdns_record_srv_t srv;
+ memset(&srv, 0, sizeof(mdns_record_srv_t));
+ // Read the priority, weight, port number and the discovery name
+ // SRV record format (http://www.ietf.org/rfc/rfc2782.txt):
+ // 2 bytes network-order unsigned priority
+ // 2 bytes network-order unsigned weight
+ // 2 bytes network-order unsigned port
+ // string: discovery (domain) name, minimum 2 bytes when compressed
+ if ((size >= offset + length) && (length >= 8)) {
+ const uint16_t* recorddata = (const uint16_t*)((const char*)buffer + offset);
+ srv.priority = ntohs(*recorddata++);
+ srv.weight = ntohs(*recorddata++);
+ srv.port = ntohs(*recorddata++);
+ offset += 6;
+ srv.name = mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
+ }
+ return srv;
+}
+
+static struct sockaddr_in*
+mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in));
+ addr->sin_family = AF_INET;
+#ifdef __APPLE__
+ addr->sin_len = sizeof(struct sockaddr_in);
+#endif
+ if ((size >= offset + length) && (length == 4))
+ addr->sin_addr.s_addr = *(const uint32_t*)((const char*)buffer + offset);
+ return addr;
+}
+
+static struct sockaddr_in6*
+mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t length,
+ struct sockaddr_in6* addr) {
+ memset(addr, 0, sizeof(struct sockaddr_in6));
+ addr->sin6_family = AF_INET6;
+#ifdef __APPLE__
+ addr->sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ if ((size >= offset + length) && (length == 16))
+ addr->sin6_addr = *(const struct in6_addr*)((const char*)buffer + offset);
+ return addr;
+}
+
+static size_t
+mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t length,
+ mdns_record_txt_t* records, size_t capacity) {
+ size_t parsed = 0;
+ const char* strdata;
+ size_t separator, sublength;
+ size_t end = offset + length;
+
+ if (size < end)
+ end = size;
+
+ while ((offset < end) && (parsed < capacity)) {
+ strdata = (const char*)buffer + offset;
+ sublength = *(const unsigned char*)strdata;
+
+ ++strdata;
+ offset += sublength + 1;
+
+ separator = 0;
+ for (size_t c = 0; c < sublength; ++c) {
+ //DNS-SD TXT record keys MUST be printable US-ASCII, [0x20, 0x7E]
+ if ((strdata[c] < 0x20) || (strdata[c] > 0x7E))
+ break;
+ if (strdata[c] == '=') {
+ separator = c;
+ break;
+ }
+ }
+
+ if (!separator)
+ continue;
+
+ if (separator < sublength) {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = separator;
+ records[parsed].value.str = strdata + separator + 1;
+ records[parsed].value.length = sublength - (separator + 1);
+ }
+ else {
+ records[parsed].key.str = strdata;
+ records[parsed].key.length = sublength;
+ }
+
+ ++parsed;
+ }
+
+ return parsed;
+}
+
+#ifdef _WIN32
+#undef strncasecmp
+#endif
diff --git a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
index 1af3b4b2a..05276bc5a 100644
--- a/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/dummy/CMakeLists.txt
@@ -12,6 +12,7 @@
# limitations under the License.
list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/dummy.h
)
list(APPEND SOURCE_FILES
diff --git a/ctrl/facemgr/src/interfaces/dummy/dummy.c b/ctrl/facemgr/src/interfaces/dummy/dummy.c
index b0c558388..6a21792a2 100644
--- a/ctrl/facemgr/src/interfaces/dummy/dummy.c
+++ b/ctrl/facemgr/src/interfaces/dummy/dummy.c
@@ -19,31 +19,101 @@
*/
#include <stdlib.h>
+#include <unistd.h> // close
+
+#include <hicn/facemgr.h>
-#include "../../interface.h"
#include "../../common.h"
-#include "../../event.h"
-#include "../../face.h"
-#include "../../facemgr.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+
+#include "dummy.h"
#define DEFAULT_PORT 9695
-int dummy_initialize(interface_t * interface, face_rules_t * rules, void **pdata) {
- ip_address_t local = IPV4_LOOPBACK;
- ip_address_t remote = IPV4_LOOPBACK;
- face_t * face = face_create_udp(&local, DEFAULT_PORT, &remote, DEFAULT_PORT, AF_INET);
- event_raise(EVENT_TYPE_CREATE, face, interface);
- return FACEMGR_SUCCESS;
+#define UNUSED(x) ((void)x)
+
+/*
+ * Internal data
+ */
+typedef struct {
+ /* The configuration data will likely be allocated on the stack (or should
+ * be freed) by the caller, we recommend to make a copy of this data.
+ * This copy can further be altered with default values.
+ */
+ dummy_cfg_t cfg;
+
+ /* ... */
+
+ int fd; /* Sample internal data: file descriptor */
+} dummy_data_t;
+
+int dummy_initialize(interface_t * interface, void * cfg)
+{
+ dummy_data_t * data = malloc(sizeof(dummy_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ /* Use default values for unspecified configuration parameters */
+ if (cfg) {
+ data->cfg = *(dummy_cfg_t *)cfg;
+ } else {
+ memset(&data->cfg, 0, sizeof(data->cfg));
+ }
+
+ /* ... */
+
+ data->fd = 0;
+
+ /* ... */
+
+ /*
+ * We should return a negative value in case of error, and a positive value
+ * otherwise:
+ * - a file descriptor (>0) will be added to the event loop; or
+ * - 0 if we don't use any file descriptor
+ */
+ return data->fd;
+
+ERR_MALLOC:
+ return -1;
+}
+
+int dummy_finalize(interface_t * interface)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+
+ if (data->fd > 0)
+ close(data->fd);
+
+ return 0;
}
-int dummy_finalize(interface_t * interface) {
- return FACEMGR_SUCCESS;
+int dummy_callback(interface_t * interface)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+ UNUSED(data);
+
+ /* ... */
+
+ return 0;
+}
+
+int dummy_on_event(interface_t * interface, const facelet_t * facelet)
+{
+ dummy_data_t * data = (dummy_data_t*)interface->data;
+ UNUSED(data);
+
+ /* ... */
+
+ return 0;
}
interface_ops_t dummy_ops = {
.type = "dummy",
- .is_singleton = true,
.initialize = dummy_initialize,
.finalize = dummy_finalize,
- .on_event = NULL,
+ .callback = dummy_callback,
+ .on_event = dummy_on_event,
};
diff --git a/ctrl/facemgr/src/interface_ops_map.h b/ctrl/facemgr/src/interfaces/dummy/dummy.h
index 2d590390a..22fe5d1a6 100644
--- a/ctrl/facemgr/src/interface_ops_map.h
+++ b/ctrl/facemgr/src/interfaces/dummy/dummy.h
@@ -13,12 +13,22 @@
* limitations under the License.
*/
-#ifndef INTERFACE_OPS_MAP_H
-#define INTERFACE_OPS_MAP_H
+/**
+ * \file dummy.h
+ * \brief Dummy interface
+ *
+ * This class serves as a template to implement new face maanger interfaces, and
+ * can be used for test purposes.
+ */
-#include "interface.h"
-#include "util/map.h"
+#ifndef FACEMGR_INTERFACE_DUMMY_H
+#define FACEMGR_INTERFACE_DUMMY_H
-TYPEDEF_MAP_H(interface_ops_map, const char *, interface_ops_t *);
+/*
+ * Configuration data
+ */
+typedef struct {
+ /* ... */
+} dummy_cfg_t;
-#endif /* INTERFACE_OPS_MAP_H */
+#endif /* FACEMGR_INTERFACE_DUMMY_H */
diff --git a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
index 85694573d..e42c6c6ae 100644
--- a/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
+++ b/ctrl/facemgr/src/interfaces/hicn_light/hicn_light.c
@@ -18,27 +18,70 @@
* \brief hICN light interface
*/
#include <stdbool.h>
-#include <stdlib.h> // arc4random [random, rand]
#include <stdio.h> // snprintf
#include <time.h> // time
#include <hicn/ctrl.h>
+#include <hicn/facemgr.h>
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
-#include "../../facemgr.h"
+#include "../../facelet.h"
#include "../../interface.h"
-#include "../../util/ip_address.h"
-#include "../../util/log.h"
#include "../../util/map.h"
-#include "../../event.h"
#define DEFAULT_ROUTE_COST 0
+typedef enum {
+ HL_STATE_UNDEFINED,
+ HL_STATE_FACES_SENT,
+ HL_STATE_DONE,
+} hl_state_t;
+
typedef struct {
hc_sock_t * s;
- bool busy;
+ hl_state_t state;
} hl_data_t;
-int hl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+int hl_process_state(interface_t * interface)
+{
+ hl_data_t * data = (hl_data_t *)interface->data;
+
+ hc_data_t * faces;
+#if 0
+ char buf[MAXSZ_FACE];
+#endif
+
+ switch(data->state)
+ {
+ case HL_STATE_UNDEFINED:
+ if (hc_face_list(data->s, &faces) < 0) {
+ /* Blocking call */
+ printf("Could not retrieve face list\n");
+ return -1;
+ }
+ foreach_face(f, faces) {
+#if 0
+ hc_face_snprintf(buf, MAXSZ_FACE, f);
+ printf("Face: %s\n", buf);
+#endif
+ facelet_t * facelet = facelet_create_from_face(&f->face);
+ facelet_set_event(facelet, FACELET_EVENT_GET);
+ facelet_raise_event(facelet, interface);
+ }
+ break;
+
+ case HL_STATE_FACES_SENT:
+ break;
+
+ default: /* HL_STATE_DONE never called */
+ break;
+ }
+
+ return 0;
+}
+
+int hl_initialize(interface_t * interface, void * cfg)
{
hl_data_t * data = malloc(sizeof(hl_data_t));
if (!data) {
@@ -57,51 +100,52 @@ int hl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
goto ERR_CONNECT;
}
- data->busy = false;
+ data->state = HL_STATE_UNDEFINED;
+
+ interface->data = data;
- *pdata = data;
+ hl_process_state(interface);
- return FACEMGR_SUCCESS;
+ return 0;
ERR_CONNECT:
hc_sock_free(data->s);
ERR_SOCK:
free(data);
ERR_MALLOC:
- return FACEMGR_FAILURE;
+ return -1;
}
int hl_finalize(interface_t * interface)
{
//hc_data_t * data = interface->data;
//hc_sock_close(data->s);
- return FACEMGR_SUCCESS;
+ return 0;
}
-int hl_on_event(interface_t * interface, const event_t * event)
+int hl_on_event(interface_t * interface, const facelet_t * facelet)
{
- hc_face_t face;
+ hc_face_t hc_face;
hc_route_t route;
int rc;
hl_data_t * data = (hl_data_t *)interface->data;
- /* XXX We need a queue or a socket pool to process concurrent events */
- if (data->busy) {
- ERROR("[hicn_light] Busy !");
- return FACEMGR_FAILURE;
- }
+ face_t * face = NULL;
+ if (facelet_get_face(facelet, &face) < 0)
+ return -1;
+
+ switch(facelet_get_event(facelet)) {
- switch(event->type) {
- case EVENT_TYPE_CREATE:
+ case FACELET_EVENT_CREATE:
/* Create face */
- face.face = *event->face;
- rc = hc_face_create(data->s, &face);
+ hc_face.face = *face;
+ rc = hc_face_create(data->s, &hc_face);
if (rc < 0) {
ERROR("Failed to create face\n");
goto ERR;
}
- DEBUG("Created face id=%d\n", face.id);
+ INFO("Created face id=%d\n", hc_face.id);
#if 0
/* Add default route v4 */
@@ -134,88 +178,84 @@ int hl_on_event(interface_t * interface, const event_t * event)
}
#endif
-#if 1
- /* We add routes based on face tags */
-
- if (policy_tags_has(event->face->tags, POLICY_TAG_TRUSTED)) {
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("b001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
- goto ERR;
- }
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
- goto ERR;
- }
+ /* Adding default route */
+ route = (hc_route_t) {
+ .face_id = hc_face.id,
+ .family = AF_INET6,
+ .len = 0,
+ .cost = DEFAULT_ROUTE_COST,
+ };
+ if (ip_address_pton("::", &route.remote_addr) < 0) {
+ ERROR("Failed to convert prefix");
+ goto ERR;
+ }
+ if (hc_route_create(data->s, &route) < 0) {
+ ERROR("Failed to create hICN/IPv6 route");
+ goto ERR;
+ }
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("d001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
+ break;
+
+ case FACELET_EVENT_DELETE:
+ /* Removing a face should also remove associated routes */
+ /* Create face */
+ hc_face.face = *face;
+ rc = hc_face_delete(data->s, &hc_face);
+ if (rc < 0) {
+ ERROR("Failed to delete face\n");
+ goto ERR;
+ }
+ INFO("Deleted face id=%d\n", hc_face.id);
+ break;
+
+ case FACELET_EVENT_UPDATE:
+ /* Currently, only admin_state is supported */
+ if (facelet_get_admin_state_status(facelet) == FACELET_ATTR_STATUS_DIRTY) {
+ hc_face.face = *face;
+ hc_face_t * face_found;
+ rc = hc_face_get(data->s, &hc_face, &face_found);
+ if (rc < 0) {
+ ERROR("Failed to find face\n");
goto ERR;
}
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
+ if (!face_found) {
+ ERROR("Face to update has not been found");
goto ERR;
}
+ char conn_id_or_name[NAME_LEN];
+ snprintf(conn_id_or_name, NAME_LEN, "%d", face_found->id);
+ free(face_found);
+ printf("Face id = %d\n", face_found->id);
- } else {
-
- route = (hc_route_t) {
- .face_id = face.id,
- .family = AF_INET6,
- .len = 16,
- .cost = DEFAULT_ROUTE_COST,
- };
- if (ip_address_pton("c001::", &route.remote_addr) < 0) {
- ERROR("Failed to convert prefix");
+ face_state_t admin_state;
+ if (facelet_get_admin_state(facelet, &admin_state) < 0) {
+ ERROR("Failed to retrieve facelet admin state");
goto ERR;
}
- if (hc_route_create(data->s, &route) < 0) {
- ERROR("Failed to create hICN/IPv6 route");
+
+ printf("Setting admin state");
+ if (hc_connection_set_admin_state(data->s, conn_id_or_name, admin_state) < 0) {
+ ERROR("Failed to update admin state");
goto ERR;
}
+ INFO("Admin state updated");
}
-#endif
-
- break;
-
- case EVENT_TYPE_DELETE:
- /* Removing a face should also remove associated routes */
- /* Create face */
- face.face = *event->face;
- rc = hc_face_delete(data->s, &face);
- if (rc < 0) {
- ERROR("Failed to delete face\n");
- goto ERR;
- }
- INFO("Deleted face id=%d\n", face.id);
break;
default:
- ERROR("Unknown event %s\n", event_type_str[event->type]);
+ ERROR("Unknown event %s\n", facelet_event_str[facelet_get_event(facelet)]);
/* Unsupported events */
goto ERR;
}
- return FACEMGR_SUCCESS;
+ return 0;
ERR:
- return FACEMGR_FAILURE;
+ return -1;
}
const interface_ops_t hicn_light_ops = {
.type = "hicn_light",
- .is_singleton = false,
.initialize = hl_initialize,
.finalize = hl_finalize,
.on_event = hl_on_event,
diff --git a/ctrl/facemgr/src/interfaces/netlink/netlink.c b/ctrl/facemgr/src/interfaces/netlink/netlink.c
index 5bf0baf9f..08cbe4d3b 100644
--- a/ctrl/facemgr/src/interfaces/netlink/netlink.c
+++ b/ctrl/facemgr/src/interfaces/netlink/netlink.c
@@ -18,34 +18,120 @@
* \brief Netlink interface
*/
+#include <assert.h>
#include <linux/rtnetlink.h>
+#include <net/if_arp.h> // ARPHRD_LOOPBACK
#include <sys/types.h> // getpid
#include <unistd.h> // getpid
-#include "../../event.h"
-#include "../../facemgr.h"
+#include <hicn/facemgr.h>
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
#include "../../interface.h"
+typedef enum {
+ NL_STATE_UNDEFINED,
+ NL_STATE_LINK_SENT,
+ NL_STATE_ADDR_SENT,
+ NL_STATE_DONE,
+} nl_state_t;
+
/* Internal data storage */
typedef struct {
int fd;
+ nl_state_t state;
} nl_data_t;
-// little helper to parsing message using netlink macroses
-void parseRtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+static inline void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len,
+ unsigned short flags)
{
+ unsigned short type;
+
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+ while (RTA_OK(rta, len)) {
+ type = rta->rta_type & ~flags;
+ if (type <= max)
+ tb[type] = rta;
+ rta = RTA_NEXT(rta, len);
+ }
+}
+
+int nl_process_state(interface_t * interface)
+{
+ nl_data_t * data = (nl_data_t*)interface->data;
+ int rc;
+
+ switch(data->state) {
+ case NL_STATE_UNDEFINED:
+ {
+ struct {
+ struct nlmsghdr header;
+ struct rtgenmsg payload;
+ } msg2 = {
+ .header = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_pid = getpid(),
+ .nlmsg_seq = 3,
+ },
+ .payload = {
+ .rtgen_family = AF_PACKET,
+ }
+ };
+
+ rc = send(data->fd, &msg2, msg2.header.nlmsg_len, 0);
+ if (rc < 0)
+ printf("E: Error sending netlink query\n");
+
+ data->state = NL_STATE_LINK_SENT;
+ break;
+ }
+
+ case NL_STATE_LINK_SENT:
+ {
+ /* Issue a first query to receive static state */
+ struct {
+ struct nlmsghdr header;
+ struct ifaddrmsg payload;
+ } msg = {
+ .header = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nlmsg_type = RTM_GETADDR,
+ .nlmsg_pid = getpid(),
+ .nlmsg_seq = 7,
+ },
+ .payload = {
+ .ifa_family = AF_INET,
+ }
+ };
+
+ rc = send(data->fd, &msg, msg.header.nlmsg_len, 0);
+ if (rc < 0)
+ printf("E: Error sending netlink query\n");
+
+ data->state = NL_STATE_ADDR_SENT;
+ break;
+ }
- while (RTA_OK(rta, len)) { // while not end of the message
- if (rta->rta_type <= max) {
- tb[rta->rta_type] = rta; // read attr
+ case NL_STATE_ADDR_SENT:
+ {
+ data->state = NL_STATE_DONE;
+ break;
}
- rta = RTA_NEXT(rta,len); // get next attr
+
+ default: /* NL_STATE_DONE never called */
+ break;
}
-}
+ return 0;
+}
-int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+int nl_initialize(interface_t * interface, void * cfg)
{
nl_data_t * data = malloc(sizeof(nl_data_t));
if (!data)
@@ -57,31 +143,194 @@ int nl_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
goto ERR_SOCKET;
}
+ data->state = NL_STATE_UNDEFINED;
+
struct sockaddr_nl local; // local addr struct
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK; // set protocol family
- local.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; // set groups we interested in
+ // NOTE: RTNLGRP_LINK replaces obsolete RTMGRP_LINK, etc
+ local.nl_groups = 0
+ | RTMGRP_LINK
+ | RTMGRP_IPV4_IFADDR
+ | RTMGRP_IPV6_IFADDR
+#if 0
+ | RTMGRP_IPV4_ROUTE;
+ | RTMGRP_IPV6_ROUTE;
+#endif
+ ;
local.nl_pid = getpid(); // set out id using current process id
-
if (bind(data->fd, (struct sockaddr*)&local, sizeof(local)) < 0) { // bind socket
printf("Failed to bind netlink socket: %s\n", (char*)strerror(errno));
goto ERR_BIND;
}
- /* Issue a first query to receive static state */
+ interface->data = data;
+ nl_process_state(interface);
- *pdata = data;
- return data->fd; // FACEMGR_SUCCESS;
+ return data->fd; // 0;
ERR_BIND:
close(data->fd);
ERR_SOCKET:
free(data);
ERR_MALLOC:
- *pdata = NULL;
- return FACEMGR_FAILURE;
+ return -1;
+}
+
+int parse_link(struct nlmsghdr * h, facelet_t ** facelet,
+ char * interface_name, size_t interface_name_size,
+ bool * up, bool * running)
+{
+ struct ifinfomsg *ifi; // structure for network interface info
+ struct rtattr *tb[IFLA_MAX + 1];
+
+ assert(facelet);
+
+ ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(h), 1<<15);
+
+ if (interface_name) {
+ assert(tb[IFLA_IFNAME]);
+ snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tb[IFLA_IFNAME]));
+ }
+
+ if (up)
+ *up = ifi->ifi_flags & IFF_UP;
+ if (running)
+ *running = ifi->ifi_flags & IFF_RUNNING;
+
+
+ *facelet = facelet_create();
+ netdevice_t * netdevice = netdevice_create_from_name(interface_name);
+ if (!netdevice)
+ goto ERROR;
+ int rc = facelet_set_netdevice(*facelet, *netdevice);
+ if (rc < 0)
+ goto ERROR;
+
+// FIXME Tags
+#if 0
+ /* This is the only opportunity to identify a loopback interface on both
+ * linux _and_ android, as NetworkCapabilities does not have a flag for
+ * LOOPBACK... */
+ if (ifi->ifi_type==ARPHRD_LOOPBACK) {
+ DEBUG("loopback");
+ }
+
+#ifdef IFLA_WIRELESS
+ /*
+ * This signals a wirless event, but it typically occurs _after_ a face is
+ * created... we might need to update an existing face by setting a tag...
+ * or find a way to exploit this flag before actually creating the face...
+ */
+ if (tb[IFLA_WIRELESS])
+ DEBUG("wireless!!!");
+#else
+#warning "IFLA_WIRELESS not supported on this platform"
+#endif /* IFLA_WIRELESS */
+
+#endif
+
+ // TODO
+ // - ifi_change
+ // - IFLA_PROTINFO
+
+ return 0;
+
+ERROR:
+ facelet_free(*facelet);
+ *facelet = NULL;
+
+ return -1;
+}
+
+int parse_addr(struct nlmsghdr * h, facelet_t ** facelet,
+ char * interface_name, size_t interface_name_size,
+ char * interface_address, size_t interface_address_size)
+{
+ ip_address_t local_addr = IP_ADDRESS_EMPTY;
+ struct ifaddrmsg *ifa; // structure for network interface data
+ struct rtattr *tba[IFA_MAX+1];
+
+ assert(facelet);
+
+ ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface
+
+ parse_rtattr(tba, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(h), 0);
+
+ /* FIXME
+ *
+ * IFA_LOCAL ok for v4, not there for v6
+ *
+ * IFA_ADDRESS seems to work for both but with the following precaution
+ *
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ */
+ if (!tba[IFA_ADDRESS]) {
+ ERROR("[netlink.parse_addr] No local address");
+ return -1;
+ }
+
+ switch(ifa->ifa_family) {
+ case AF_INET:
+ local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_ADDRESS]);
+ break;
+ case AF_INET6:
+ local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_ADDRESS]);
+ break;
+ default:
+ return 0;
+ }
+
+#if 0 /* Not working for v6 */
+ if (interface_name) {
+ assert(tba[IFLA_IFNAME]);
+ snprintf(interface_name, interface_name_size, "%s", (char*)RTA_DATA(tba[IFLA_IFNAME]));
+ }
+#endif
+
+ /* See comment in parse_link */
+ if (interface_address) {
+ assert(tba[IFA_ADDRESS]);
+ ip_address_snprintf(interface_address, interface_address_size, &local_addr, ifa->ifa_family);
+ }
+
+ netdevice_t * netdevice = netdevice_create_from_index(ifa->ifa_index);
+ if (!netdevice) {
+ ERROR("[netlink.parse_addr] error creating netdevice '%s'", interface_name);
+ goto ERROR;
+ }
+
+ if (interface_name) {
+ snprintf(interface_name, interface_name_size, "%s", netdevice->name);
+ }
+
+ *facelet = facelet_create();
+ if (facelet_set_netdevice(*facelet, *netdevice) < 0) {
+ ERROR("[netlink.parse_addr] error setting netdevice");
+ goto ERROR;
+ }
+ if (facelet_set_family(*facelet, ifa->ifa_family) < 0) {
+ ERROR("[netlink.parse_addr] error setting family");
+ goto ERROR;
+ }
+ if (facelet_set_local_addr(*facelet, local_addr) < 0) {
+ ERROR("[netlink.parse_addr] error setting local address");
+ goto ERROR;
+ }
+
+ return 0;
+
+ERROR:
+ facelet_free(*facelet);
+ *facelet = NULL;
+
+ return -1;
}
int nl_callback(interface_t * interface)
@@ -97,13 +346,12 @@ int nl_callback(interface_t * interface)
iov.iov_len = sizeof(buf); // set size
// initialize protocol message header
- struct msghdr msg;
- {
- msg.msg_name = &local; // local address
- msg.msg_namelen = sizeof(local); // address size
- msg.msg_iov = &iov; // io vector
- msg.msg_iovlen = 1; // io size
- }
+ struct msghdr msg = {
+ .msg_name = &local, // local address
+ .msg_namelen = sizeof(local), // address size
+ .msg_iov = &iov, // io vector
+ .msg_iovlen = 1, // io size
+ };
ssize_t status = recvmsg(data->fd, &msg, 0);
@@ -115,12 +363,12 @@ int nl_callback(interface_t * interface)
*/
printf("Failed to read netlink: %s", (char*)strerror(errno));
- return FACEMGR_FAILURE;
+ return -1;
}
if (msg.msg_namelen != sizeof(local)) { // check message length, just in case
printf("Invalid length of the sender address struct\n");
- return FACEMGR_FAILURE;
+ return -1;
}
// message parser
@@ -129,103 +377,122 @@ int nl_callback(interface_t * interface)
for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { // read all messagess headers
int len = h->nlmsg_len;
int l = len - sizeof(*h);
- char *ifName = NULL;
if ((l < 0) || (len > status)) {
printf("Invalid message length: %i\n", len);
continue;
}
- // now we can check message type
- if ((h->nlmsg_type == RTM_NEWROUTE) || (h->nlmsg_type == RTM_DELROUTE)) { // some changes in routing table
- printf("Routing table was changed\n");
- } else { // in other case we need to go deeper
- char *ifUpp;
- char *ifRunn;
- struct ifinfomsg *ifi; // structure for network interface info
- struct rtattr *tb[IFLA_MAX + 1];
-
- ifi = (struct ifinfomsg*) NLMSG_DATA(h); // get information about changed network interface
-
- parseRtattr(tb, IFLA_MAX, IFLA_RTA(ifi), h->nlmsg_len); // get attributes
-
- if (tb[IFLA_IFNAME]) { // validation
- ifName = (char*)RTA_DATA(tb[IFLA_IFNAME]); // get network interface name
- }
-
- if (ifi->ifi_flags & IFF_UP) { // get UP flag of the network interface
- ifUpp = (char*)"UP";
- } else {
- ifUpp = (char*)"DOWN";
- }
+ switch(h->nlmsg_type) {
+#if 0
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ DEBUG("Routing table was changed");
+ break;
+#endif
+
+ case RTM_DELADDR:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ char interface_address[MAXSZ_IP_ADDRESS] = {0};
+
+ if (parse_addr(h, &facelet, interface_name, IFNAMSIZ,
+ interface_address, MAXSZ_IP_ADDRESS) < 0) {
+ ERROR("Error parsing address message");
+ break;
+ }
- if (ifi->ifi_flags & IFF_RUNNING) { // get RUNNING flag of the network interface
- ifRunn = (char*)"RUNNING";
- } else {
- ifRunn = (char*)"NOT RUNNING";
+ DEBUG("Interface %s: address was removed", interface_name);
+ if (facelet) {
+ facelet_set_event(facelet, FACELET_EVENT_DELETE);
+ facelet_raise_event(facelet, interface);
+ }
+ break;
}
- char ifAddress[256] = {0}; // network addr
- struct ifaddrmsg *ifa; // structure for network interface data
- struct rtattr *tba[IFA_MAX+1];
+ case RTM_NEWADDR:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ char interface_address[MAXSZ_IP_ADDRESS] = {0};
- ifa = (struct ifaddrmsg*)NLMSG_DATA(h); // get data from the network interface
+ if (parse_addr(h, &facelet, interface_name, IFNAMSIZ,
+ interface_address, MAXSZ_IP_ADDRESS) < 0) {
+ ERROR("Error parsing address message");
+ break;
+ }
- parseRtattr(tba, IFA_MAX, IFA_RTA(ifa), h->nlmsg_len);
+ DEBUG("Interface %s: new address was assigned: %s", interface_name, interface_address);
- if (tba[IFA_LOCAL]) {
- inet_ntop(AF_INET, RTA_DATA(tba[IFA_LOCAL]), ifAddress, sizeof(ifAddress)); // get IP addr
+ if (facelet) {
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+ facelet_raise_event(facelet, interface);
+ }
+ break;
}
- face_t * face;
-
- if (tba[IFA_LOCAL]) {
- ip_address_t local_addr = IP_ADDRESS_EMPTY;
- switch(ifa->ifa_family) {
- case AF_INET:
- local_addr.v4.as_inaddr = *(struct in_addr*)RTA_DATA(tba[IFA_LOCAL]);
- break;
- case AF_INET6:
- local_addr.v6.as_in6addr = *(struct in6_addr*)RTA_DATA(tba[IFA_LOCAL]);
- break;
- default:
- continue;
+ case RTM_DELLINK:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ if (parse_link(h, &facelet, interface_name, IFNAMSIZ,
+ NULL, NULL) < 0) {
+ ERROR("Error parsing link message");
+ break;
+ }
+ if (facelet) {
+ facelet_set_event(facelet, FACELET_EVENT_DELETE);
+ facelet_raise_event(facelet, interface);
}
- face = face_create_udp(&local_addr, 0, &IP_ADDRESS_EMPTY, 0, ifa->ifa_family);
- } else {
- face = NULL;
+
+ DEBUG("Network interface %s was removed", interface_name);
+ break;
}
- switch (h->nlmsg_type) {
- case RTM_DELADDR:
- // DOES NOT SEEM TO BE TRIGGERED
- printf("Interface %s: address was removed\n", ifName);
- if (face)
- event_raise(EVENT_TYPE_DELETE, face, interface);
- break;
+ case RTM_NEWLINK:
+ {
+ facelet_t * facelet = NULL;
+ char interface_name[IFNAMSIZ];
+ bool up, running;
- case RTM_DELLINK:
- printf("Network interface %s was removed\n", ifName);
+ if (parse_link(h, &facelet, interface_name, IFNAMSIZ, &up, &running) < 0) {
+ ERROR("Error parsing link message");
break;
+ }
- case RTM_NEWLINK:
- printf("New network interface %s, state: %s %s\n", ifName, ifUpp, ifRunn);
- // UP RUNNING
- // UP NOT RUNNING
- // DOWN NOT RUNNING
- if (!(ifi->ifi_flags & IFF_UP) || (!(ifi->ifi_flags & IFF_RUNNING))) {
- if(face)
- event_raise(EVENT_TYPE_DELETE, face, interface);
+ // UP RUNNING
+ // UP NOT RUNNING
+ // DOWN NOT RUNNING
+ DEBUG("New network interface %s, state: %s %s", interface_name,
+ up ? "UP" : "DOWN",
+ running ? "RUNNING" : "NOT_RUNNING");
+
+ if (facelet && up && running) {
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ facelet_t * facelet6 = facelet_dup(facelet);
+ if (!facelet6) {
+ ERROR("Could not duplicate face for v6");
+ break;
}
- break;
- case RTM_NEWADDR:
- printf("Interface %s: new address was assigned: %s\n", ifName, ifAddress);
- printf("NEW FACE\n");
- if (face)
- event_raise(EVENT_TYPE_CREATE, face, interface);
- break;
+ facelet_set_family(facelet, AF_INET);
+ facelet_raise_event(facelet, interface);
+
+ facelet_set_family(facelet6, AF_INET6);
+ facelet_raise_event(facelet6, interface);
+ }
+ break;
}
+
+ case NLMSG_ERROR:
+ break;
+ case NLMSG_DONE:
+ nl_process_state(interface);
+ break;
+ default:
+ break;
+
}
status -= NLMSG_ALIGN(len); // align offsets by the message length, this is important
@@ -233,20 +500,19 @@ int nl_callback(interface_t * interface)
h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); // get next message
}
- return FACEMGR_SUCCESS;
+ return 0;
}
int nl_finalize(interface_t * interface)
{
nl_data_t * data = (nl_data_t*)interface->data;
close(data->fd);
- return FACEMGR_SUCCESS;
+ return 0;
}
const interface_ops_t netlink_ops = {
.type = "netlink",
- .is_singleton = true,
.initialize = nl_initialize,
.callback = nl_callback,
.finalize = nl_finalize,
diff --git a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
index ca6659342..e8b0144b1 100644
--- a/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
+++ b/ctrl/facemgr/src/interfaces/network_framework/CMakeLists.txt
@@ -17,6 +17,7 @@ if (NOT NETWORK_LIBRARY)
endif()
list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/network_framework.h
)
list(APPEND SOURCE_FILES
diff --git a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
index 8a33129b4..4a9d24f61 100644
--- a/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
+++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.c
@@ -24,14 +24,17 @@
#include <Network/Network.h>
#include <err.h>
+#include <hicn/facemgr.h>
+#include <hicn/util/token.h>
+#include <hicn/util/log.h>
+
#include "../../common.h"
-#include "../../event.h"
-#include "../../face.h"
-#include "../../facemgr.h"
+#include <hicn/ctrl/face.h>
+#include "../../facelet.h"
#include "../../interface.h"
#include "../../util/map.h"
-#include "../../util/token.h"
-#include "../../util/log.h"
+
+#include "network_framework.h"
/*
* Bonjour service discovery for hICN forwarder
@@ -107,7 +110,7 @@ cmp_iface(const nw_interface_t iface1, const nw_interface_t iface2)
//TYPEDEF_MAP(map_cnx, nw_interface_t, nw_connection_t, cmp_iface);
typedef struct {
- face_rules_t * rules; /**< Face creation rules */
+ network_framework_cfg_t cfg;
nw_path_monitor_t pm; /**< Main path monitor */
// map_cnx_t map_cnx; /**< Map: interface -> connection for face status */
} nf_data_t;
@@ -209,97 +212,90 @@ dump_connection(nw_connection_t connection, int indent)
nw_release(path);
}
-face_t *
-face_create_from_connection(nw_connection_t connection, face_rules_t * rules)
+facelet_t *
+facelet_create_from_connection(nw_connection_t connection)
{
- face_t * face;
- struct sockaddr_in * sin;
- struct sockaddr_in6 * sin6;
+ facelet_t * facelet;
+ ip_address_t local_addr, remote_addr;
+ uint16_t remote_port;
nw_path_t path = nw_connection_copy_current_path(connection);
nw_endpoint_t local = nw_path_copy_effective_local_endpoint(path);
nw_endpoint_t remote = nw_path_copy_effective_remote_endpoint(path);
__block nw_interface_t interface;
- const struct sockaddr * local_addr = nw_endpoint_get_address(local);
- const struct sockaddr * remote_addr = nw_endpoint_get_address(remote);
+ const struct sockaddr * local_sa = nw_endpoint_get_address(local);
+ const struct sockaddr * remote_sa = nw_endpoint_get_address(remote);
- assert (local_addr->sa_family == remote_addr->sa_family);
- switch(local_addr->sa_family) {
+ assert (local_sa->sa_family == remote_sa->sa_family);
+ switch(local_sa->sa_family) {
case AF_INET:
- sin = (struct sockaddr_in *)local_addr;
- sin->sin_port = htons(DEFAULT_PORT);
- sin = (struct sockaddr_in *)remote_addr;
- sin->sin_port = htons(DEFAULT_PORT);
+ local_addr.v4.as_inaddr = ((struct sockaddr_in *)local_sa)->sin_addr;
+ remote_addr.v4.as_inaddr = ((struct sockaddr_in *)remote_sa)->sin_addr;
+ remote_port = ((struct sockaddr_in *)remote_sa)->sin_port;
break;
case AF_INET6:
- sin6 = (struct sockaddr_in6 *)local_addr;
- sin6->sin6_port = htons(DEFAULT_PORT);
- sin6 = (struct sockaddr_in6 *)remote_addr;
- sin6->sin6_port = htons(DEFAULT_PORT);
+ local_addr.v6.as_in6addr = ((struct sockaddr_in6 *)local_sa)->sin6_addr;
+ remote_addr.v6.as_in6addr = ((struct sockaddr_in6 *)remote_sa)->sin6_addr;
+ remote_port = ((struct sockaddr_in6 *)remote_sa)->sin6_port;
break;
default:
- ERROR("Unsupported address family: %d\n", local_addr->sa_family);
+ ERROR("Unsupported address family: %d\n", local_sa->sa_family);
return NULL;
}
- face = face_create_udp_sa(local_addr, remote_addr);
/* Retrieving path interface type (a single one expected */
nw_path_enumerate_interfaces(path, (nw_path_enumerate_interfaces_block_t)^(nw_interface_t path_interface) {
interface = path_interface;
return false;
});
- nw_interface_type_t type = nw_interface_get_type(interface);
- const char * name = nw_interface_get_name(interface);
-
- policy_tags_t tags = POLICY_TAGS_EMPTY;
- if (rules) {
- if (!FACEMGR_IS_ERROR(face_rules_get(rules, name, &tags)))
- goto SET_TAGS;
+ const char * name = nw_interface_get_name(interface);
+ netdevice_t netdevice;
+ snprintf(netdevice.name, IFNAMSIZ, "%s", name);
+ netdevice_update_index(&netdevice);
- char tags[MAXSZ_POLICY_TAGS];
- policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags);
- }
+ netdevice_type_t netdevice_type;
+ nw_interface_type_t type = nw_interface_get_type(interface);
switch(type) {
case INTERFACE_TYPE_OTHER:
- policy_tags_add(&tags, POLICY_TAG_WIFI);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_UNDEFINED;
break;
case INTERFACE_TYPE_WIFI:
- // XXX disambuiguate on interface name for now.
- policy_tags_add(&tags, POLICY_TAG_WIFI);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_WIFI;
break;
case INTERFACE_TYPE_CELLULAR:
- policy_tags_add(&tags, POLICY_TAG_CELLULAR);
+ netdevice_type = NETDEVICE_TYPE_CELLULAR;
break;
case INTERFACE_TYPE_WIRED:
- /* Both VPN and USB WiFi are not well detected on MacOS. For USB
- * WiFi, we currently have no solution. For VPN, until we have
- * proper support of AnyC APIs, we need to have heuristics to
- * determine VPN interfaces. */
- policy_tags_add(&tags, POLICY_TAG_WIRED);
- policy_tags_add(&tags, POLICY_TAG_TRUSTED);
+ netdevice_type = NETDEVICE_TYPE_WIRED;
break;
case INTERFACE_TYPE_LOOPBACK:
- tags = POLICY_TAGS_EMPTY;
+ netdevice_type = NETDEVICE_TYPE_LOOPBACK;
break;
default:
break;
}
-SET_TAGS:
- face_set_tags(face, tags);
-
nw_release(local);
nw_release(remote);
nw_release(path);
- return face;
+ facelet = facelet_create();
+ if (!facelet)
+ return NULL;
+
+ facelet_set_netdevice(facelet, netdevice);
+ facelet_set_netdevice_type(facelet, netdevice_type);
+ facelet_set_family(facelet, local_sa->sa_family);
+ facelet_set_local_addr(facelet, local_addr);
+ facelet_set_remote_addr(facelet, remote_addr);
+ facelet_set_remote_port(facelet, remote_port);
+
+ return facelet;
}
void
@@ -340,9 +336,11 @@ on_connection_state_event(interface_t * interface, nw_interface_t iface,
dump_connection(cnx, 1);
});
#endif
- nf_data_t * data = (nf_data_t*)interface->data;
- face_t * face = face_create_from_connection(cnx, data->rules);
- event_raise(EVENT_TYPE_CREATE, face, interface);
+ facelet_t * facelet = facelet_create_from_connection(cnx);
+ if (!facelet)
+ return;
+ facelet_set_event(facelet, FACELET_EVENT_CREATE);
+ facelet_raise_event(facelet, interface);
break;
}
case nw_connection_state_failed:
@@ -482,14 +480,11 @@ void on_interface_event(interface_t * interface, nw_interface_t iface)
* This is the first time we have a connection with address and port
* and thus the full identification of an hICN face
*/
- nf_data_t * data = (nf_data_t*)interface->data;
- face_t * face = face_create_from_connection(connection, data->rules);
- //event_raise(value ? EVENT_TYPE_SET_UP : EVENT_TYPE_SET_DOWN, face, interface);
- if(value) {
- event_raise(EVENT_TYPE_CREATE, face, interface);
- } else {
- event_raise(EVENT_TYPE_DELETE, face, interface);
- }
+ facelet_t * facelet = facelet_create_from_connection(connection);
+ if (!facelet)
+ return;
+ facelet_set_event(facelet, value ? FACELET_EVENT_CREATE : FACELET_EVENT_DELETE);
+ facelet_raise_event(facelet, interface);
});
@@ -528,13 +523,16 @@ void on_path_event(interface_t * interface, nw_path_t path)
}
-int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
+int nf_initialize(interface_t * interface, void * cfg)
{
nf_data_t * data = malloc(sizeof(nf_data_t));
if (!data)
goto ERR_MALLOC;
- data->rules = rules;
+ if (cfg)
+ data->cfg = * (network_framework_cfg_t *)cfg;
+ else
+ data->cfg.rules = NULL;
data->pm = nw_path_monitor_create();
if (!data->pm)
@@ -552,14 +550,13 @@ int nf_initialize(interface_t * interface, face_rules_t * rules, void ** pdata)
DEBUG("Starting network path monitor");
nw_path_monitor_start(data->pm);
- *pdata = data;
- return FACEMGR_SUCCESS;
+ interface->data = data;
+ return 0;
ERR_PM:
free(data);
ERR_MALLOC:
- *pdata = NULL;
- return FACEMGR_FAILURE;
+ return -1;
}
int nf_finalize(interface_t * interface)
@@ -569,12 +566,11 @@ int nf_finalize(interface_t * interface)
nw_path_monitor_cancel(data->pm);
data->pm = NULL;
}
- return FACEMGR_SUCCESS;
+ return 0;
}
const interface_ops_t network_framework_ops = {
.type = "network_framework",
- .is_singleton = true,
.initialize = nf_initialize,
.finalize = nf_finalize,
.on_event = NULL,
diff --git a/ctrl/facemgr/src/face_cache.c b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h
index bee36af30..edb35e904 100644
--- a/ctrl/facemgr/src/face_cache.c
+++ b/ctrl/facemgr/src/interfaces/network_framework/network_framework.h
@@ -13,9 +13,10 @@
* limitations under the License.
*/
-#include "face_cache.h"
-
-#include "face.h"
-#include "util/set.h"
+/**
+ * \file network_framework.h
+ * \brief Network framework interface
+ */
-TYPEDEF_SET(face_cache, face_t *, face_cmp, face_snprintf);
+typedef struct {
+} network_framework_cfg_t;
diff --git a/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt
new file mode 100644
index 000000000..e5fd2167e
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/updown/CMakeLists.txt
@@ -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.
+
+list(APPEND HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/updown.h
+)
+
+list(APPEND SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/updown.c
+)
+
+list(APPEND INCLUDE_DIRS
+)
+
+list(APPEND LIBRARIES
+)
+
+set(SOURCE_FILES ${SOURCE_FILES} PARENT_SCOPE)
+set(HEADER_FILES ${HEADER_FILES} PARENT_SCOPE)
+set(INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
+set(LIBRARIES ${LIBRARIES} PARENT_SCOPE)
diff --git a/ctrl/facemgr/src/interfaces/updown/updown.c b/ctrl/facemgr/src/interfaces/updown/updown.c
new file mode 100644
index 000000000..f5a813cd4
--- /dev/null
+++ b/ctrl/facemgr/src/interfaces/updown/updown.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017-2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 updown.c
+ * \brief Implementation of Example updown interface
+ */
+
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <hicn/facemgr.h>
+
+#include "../../common.h"
+#include "../../facelet.h"
+#include "../../interface.h"
+
+/**
+ * \brief Default unix socket path (the leading \0 means using the abstract
+ * namespace instead of the filesystem).
+ */
+#define UNIX_PATH "\0updownsrv"
+
+typedef struct {
+ int fd; /* Unix client socket */
+} updown_data_t;
+
+int updown_initialize(interface_t * interface, void * cfg)
+{
+ struct sockaddr_un addr;
+ char * socket_path = UNIX_PATH;
+
+ updown_data_t * data = malloc(sizeof(updown_data_t));
+ if (!data)
+ goto ERR_MALLOC;
+ interface->data = data;
+
+ data->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (data->fd == -1) {
+ perror("socket error");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ if (*socket_path == '\0') {
+ *addr.sun_path = '\0';
+ strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
+ } else {
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
+ }
+
+ if (connect(data->fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
+ perror("connect error");
+ return -1;
+ }
+
+ return data->fd;
+
+ERR_MALLOC:
+ return -1;
+}
+
+int updown_finalize(interface_t * interface)
+{
+ updown_data_t * data = (updown_data_t*)interface->data;
+
+ if (data->fd > 0)
+ close(data->fd);
+
+ return 0;
+}
+
+int updown_callback(interface_t * interface)
+{
+ updown_data_t * data = (updown_data_t*)interface->data;
+ char buf[100];
+ int rc;
+
+ rc = read(data->fd, buf, sizeof(buf));
+ if (rc < 0)
+ return -1;
+
+ /*
+ * If the process is paused (eg. in a debugger, we might have more than one
+ * read.
+ * XXX how big is the buffer
+ * XXX shall we drain the queue if it exceeds buffer size ?
+ */
+ //assert(rc == 1);
+
+ /* Raise facelet update event */
+ facelet_t * facelet = facelet_create();
+ facelet_set_netdevice_type(facelet, NETDEVICE_TYPE_WIFI); //CELLULAR);
+ facelet_set_status(facelet, FACELET_STATUS_CLEAN);
+ switch(buf[0]) {
+ case '\0':
+ facelet_set_admin_state(facelet, FACE_STATE_DOWN);
+ break;
+ case '\1':
+ facelet_set_admin_state(facelet, FACE_STATE_UP);
+ break;
+ break;
+ default:
+ ERROR("Invalid data received from updown server. Ignoring...");
+ facelet_free(facelet);
+ return -1;
+ }
+
+ facelet_set_event(facelet, FACELET_EVENT_UPDATE);
+
+ facelet_raise_event(facelet, interface);
+
+ return 0;
+}
+
+interface_ops_t updown_ops = {
+ .type = "updown",
+ .initialize = updown_initialize,
+ .finalize = updown_finalize,
+ .callback = updown_callback,
+};
diff --git a/ctrl/facemgr/src/main.c b/ctrl/facemgr/src/main.c
index 6a80d806b..2a336db8f 100644
--- a/ctrl/facemgr/src/main.c
+++ b/ctrl/facemgr/src/main.c
@@ -18,8 +18,21 @@
* \brief Face manager daemon entry point
*/
+#ifdef WITH_THREAD
+#ifndef __linux__
+#error "Not implemented"
+#endif /* __linux__ */
+#include <pthread.h>
+#endif /* WITH_THREAD */
+
+#ifndef __APPLE__
+#include <event2/event.h>
+#include <event2/thread.h>
+#endif /* __APPLE__ */
+
#include <getopt.h>
#include <limits.h>
+#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -27,20 +40,41 @@
#include <libconfig.h>
-#include "util/log.h"
-#include "util/policy.h"
-
#ifdef __APPLE__
#include <Dispatch/Dispatch.h>
#else
-// Note: we might want to use libevent on Apple too
#include <event2/event.h>
#endif
-#include "facemgr.h"
+#include <hicn/facemgr.h>
+#include <hicn/policy.h>
+
+#include <hicn/util/ip_address.h>
+#include <hicn/util/log.h>
+
+#include <hicn/facemgr/cfg.h>
#define FACEMGR_TIMEOUT 3
+static struct event_base * loop;
+
+void facemgr_signal_handler(int signal) {
+ fprintf(stderr, "Received ^C... quitting !\n");
+ exit(0);
+#if 0
+ return;
+
+ // FIXME
+
+ /* should be atomic */
+ // FIXME Don't use loop in a static variable as we should not need it if all
+ // events are properly unregistered...
+#endif
+#ifdef __linux__
+ event_base_loopbreak(loop);
+#endif /* __linux__ */
+ loop = NULL;
+}
static struct option long_options[] =
{
@@ -101,106 +135,305 @@ int parse_cmdline(int argc, char ** argv, facemgr_options_t * opts)
return 0;
}
-int parse_config_file(const char * cfgpath, facemgr_t * facemgr)
+int
+parse_config_global(facemgr_cfg_t * cfg, config_setting_t * setting)
{
- /* Reading configuration file */
- config_t cfg;
- config_setting_t *setting;
+ /* - face_type */
+
+ const char *face_type_str;
+ facemgr_face_type_t face_type;
+ if (config_setting_lookup_string(setting, "face_type", &face_type_str)) {
+ if (strcasecmp(face_type_str, "auto") == 0) {
+ face_type = FACEMGR_FACE_TYPE_DEFAULT;
+ } else
+ if (strcasecmp(face_type_str, "native-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_UDP;
+ } else
+ if (strcasecmp(face_type_str, "native-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ } else {
+ ERROR("Invalid face type in section 'global'");
+ return -1;
+ }
- config_init(&cfg);
+ int rc = facemgr_cfg_set_face_type(cfg, &face_type);
+ if (rc < 0)
+ goto ERR;
+ }
- /* Read the file. If there is an error, report it and exit. */
- if(!config_read_file(&cfg, cfgpath))
- goto ERR_FILE;
+ /* - disable_discovery */
- setting = config_lookup(&cfg, "log");
- if (setting) {
- const char *log_level_str;
- if (config_setting_lookup_string(setting, "log_level", &log_level_str)) {
- if (strcmp(log_level_str, "FATAL") == 0) {
- log_conf.log_level = LOG_FATAL;
- } else
- if (strcmp(log_level_str, "ERROR") == 0) {
- log_conf.log_level = LOG_ERROR;
- } else
- if (strcmp(log_level_str, "WARN") == 0) {
- log_conf.log_level = LOG_WARN;
- } else
- if (strcmp(log_level_str, "INFO") == 0) {
- log_conf.log_level = LOG_INFO;
- } else
- if (strcmp(log_level_str, "DEBUG") == 0) {
- log_conf.log_level = LOG_DEBUG;
- } else
- if (strcmp(log_level_str, "TRACE") == 0) {
- log_conf.log_level = LOG_TRACE;
- } else {
- printf("Ignored unknown log level\n");
- }
- }
+ int disable_discovery;
+ if (config_setting_lookup_bool(setting, "disable_discovery",
+ &disable_discovery)) {
+ int rc = facemgr_cfg_set_discovery(cfg, !disable_discovery);
+ if (rc < 0)
+ goto ERR;
}
- setting = config_lookup(&cfg, "faces.overlay.ipv4");
- if (setting) {
- const char * ip_address;
- int local_port, remote_port;
- if (config_setting_lookup_int(setting, "local_port", &local_port)) {
- if ((local_port < 0) || (local_port > MAX_PORT))
+ /* - disable_ipv4 */
+
+ int disable_ipv4;
+ if (config_setting_lookup_bool(setting, "disable_ipv4",
+ &disable_ipv4)) {
+ INFO("Ignored setting 'disable_ipv4' in section 'global' (not implemented).");
+#if 0
+ int rc = facemgr_cfg_set_ipv4(cfg, !disable_ipv4);
+ if (rc < 0)
+ goto ERR;
+#endif
+ }
+
+ /* - disable ipv6 */
+
+ int disable_ipv6;
+ if (config_setting_lookup_bool(setting, "disable_ipv6",
+ &disable_ipv6)) {
+ INFO("Ignored setting 'disable_ipv6' in section 'global': (not implemented).");
+#if 0
+ int rc = facemgr_cfg_set_ipv6(cfg, !disable_ipv6);
+ if (rc < 0)
+ goto ERR;
+#endif
+ }
+
+ /* - overlay */
+ config_setting_t *overlay = config_setting_get_member(setting, "overlay");
+ if (overlay) {
+
+ /* ipv4 */
+ config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4");
+ if (overlay_v4) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr, remote_addr;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_set_overlay(cfg, AF_INET,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
goto ERR;
- facemgr->overlay_v4_local_port = (uint16_t)local_port;
}
- if (config_setting_lookup_int(setting, "remote_port", &remote_port)) {
- if ((remote_port < 0) || (remote_port > MAX_PORT))
+ /* ipv6 */
+ config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6");
+ if (overlay_v6) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr, remote_addr;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_set_overlay(cfg, AF_INET6,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
goto ERR;
- facemgr->overlay_v4_remote_port = (uint16_t)remote_port;
}
- if (config_setting_lookup_string(setting, "remote_addr", &ip_address)) {
- ip_address_pton(ip_address, &facemgr->overlay_v4_remote_addr);
- printf("got v4 remote addr\n");
+ } /* overlay */
+
+ return 0;
+
+ERR:
+ return -1;
+}
+
+int
+parse_config_rules(facemgr_cfg_t * cfg, config_setting_t * setting)
+{
+ /* List of match-override tuples */
+ facemgr_cfg_rule_t * rule;
+
+ int count = config_setting_length(setting);
+ for (unsigned i = 0; i < count; ++i) {
+ config_setting_t * rule_setting = config_setting_get_elem(setting, i);
+
+ /* Sanity check */
+
+ config_setting_t * match_setting = config_setting_get_member(rule_setting, "match");
+ if (!match_setting) {
+ ERROR("Missing match section in rule #%d", i);
+ goto ERR_CHECK;
}
- }
- setting = config_lookup(&cfg, "faces.overlay.ipv6");
- if (setting) {
- const char * ip_address;
- int local_port, remote_port;
- if (config_setting_lookup_int(setting, "local_port", &local_port)) {
- if ((local_port < 0) || (local_port > MAX_PORT))
+ config_setting_t * override_setting = config_setting_get_member(rule_setting, "override");
+ if (!override_setting) {
+ ERROR("Missing override section in rule #%d", i);
+ goto ERR_CHECK;
+ }
+
+ rule = facemgr_cfg_rule_create();
+ if (!rule)
+ goto ERR_RULE;
+
+ /* Parse match */
+
+ const char * interface_name = NULL;
+ config_setting_lookup_string(match_setting, "interface_name", &interface_name);
+
+ const char * interface_type_str;
+ netdevice_type_t interface_type = NETDEVICE_TYPE_UNDEFINED;
+ if (config_setting_lookup_string(match_setting, "interface_type", &interface_type_str)) {
+ if (strcasecmp(interface_type_str, "wired") == 0) {
+ interface_type = NETDEVICE_TYPE_WIRED;
+ } else
+ if (strcasecmp(interface_type_str, "wifi") == 0) {
+ interface_type = NETDEVICE_TYPE_WIFI;
+ } else
+ if (strcasecmp(interface_type_str, "cellular") == 0) {
+ interface_type = NETDEVICE_TYPE_CELLULAR;
+ } else {
+ ERROR("Unknown interface type in rule #%d", i);
goto ERR;
- facemgr->overlay_v6_local_port = (uint16_t)local_port;
+ }
}
- if (config_setting_lookup_int(setting, "remote_port", &remote_port)) {
- if ((remote_port < 0) || (remote_port > MAX_PORT))
+ if ((!interface_name) && (interface_type == NETDEVICE_TYPE_UNDEFINED)) {
+ ERROR("Empty match section in rule #%d", i);
+ goto ERR;
+ }
+
+ /* Associate match to rule */
+
+ int rc = facemgr_cfg_rule_set_match(rule, interface_name, interface_type);
+ if (rc < 0)
+ goto ERR;
+
+ /* Parse override */
+
+ /* - face_type */
+
+ const char *face_type_str;
+ facemgr_face_type_t face_type;
+ if (config_setting_lookup_string(override_setting, "face_type", &face_type_str)) {
+ if (strcasecmp(face_type_str, "auto")) {
+ /* We currently hardcode different behaviours based on the OS */
+#ifdef __ANDROID__
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+#else
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+#endif
+ } else
+ if (strcasecmp(face_type_str, "native-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_UDP;
+ } else
+ if (strcasecmp(face_type_str, "native-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_NATIVE_TCP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-udp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_UDP;
+ } else
+ if (strcasecmp(face_type_str, "overlay-tcp") == 0) {
+ face_type = FACEMGR_FACE_TYPE_OVERLAY_TCP;
+ } else {
+ ERROR("Invalid face type in section 'global'");
+ return -1;
+ }
+
+ int rc = facemgr_cfg_rule_set_face_type(rule, &face_type);
+ if (rc < 0)
goto ERR;
- facemgr->overlay_v6_remote_port = (uint16_t)remote_port;
}
- if (config_setting_lookup_string(setting, "remote_addr", &ip_address))
- ip_address_pton(ip_address, &facemgr->overlay_v6_remote_addr);
- }
+ /* - disable_discovery */
- setting = config_lookup(&cfg, "faces.rules");
- if (setting) {
- int count = config_setting_length(setting);
- for(unsigned i = 0; i < count; ++i) {
- const char *interface_name;
- policy_tags_t tags = POLICY_TAGS_EMPTY;
+ int disable_discovery;
+ if (config_setting_lookup_bool(override_setting, "disable_discovery",
+ &disable_discovery)) {
+ int rc = facemgr_cfg_rule_set_discovery(rule, !disable_discovery);
+ if (rc < 0)
+ goto ERR;
+ }
- config_setting_t *rule = config_setting_get_elem(setting, i);
+ /* - disable_ipv4 */
- /* Interface name */
- if(!(config_setting_lookup_string(rule, "name", &interface_name)))
- continue;
+ int disable_ipv4;
+ if (config_setting_lookup_bool(override_setting, "disable_ipv4",
+ &disable_ipv4)) {
+ INFO("Ignored setting 'disable_ipv4' in rule #%d (not implemented).", i);
+#if 0
+ int rc = facemgr_cfg_rule_set_ipv4(rule, !disable_ipv4);
+ if (rc < 0)
+ goto ERR;
+#endif
+ }
- /* Associated tags */
- config_setting_t *tag_settings = config_setting_get_member(rule, "tags");
- if (!tag_settings)
+ /* - disable ipv6 */
+
+ int disable_ipv6;
+ if (config_setting_lookup_bool(override_setting, "disable_ipv6",
+ &disable_ipv6)) {
+ INFO("Ignored setting 'disable_ipv6' in rule #%d (not implemented).", i);
+#if 0
+ int rc = facemgr_cfg_rule_set_ipv6(rule, !disable_ipv6);
+ if (rc < 0)
goto ERR;
+#endif
+ }
+ /* - ignore */
+ int ignore;
+ if (config_setting_lookup_bool(override_setting, "ignore", &ignore)) {
+ int rc = facemgr_cfg_rule_set_ignore(rule, !!ignore);
+ if (rc < 0)
+ goto ERR;
+ }
+ /* - tags */
+ config_setting_t *tag_settings = config_setting_get_member(override_setting, "tags");
+ if (tag_settings) {
+ INFO("Ignored setting 'tags' in rule #%d (not implemented).", i);
+#if 0
+ policy_tags_t tags = POLICY_TAGS_EMPTY;
for (unsigned j = 0; j < config_setting_length(tag_settings); j++) {
const char * tag_str = config_setting_get_string_elem(tag_settings, j);
policy_tag_t tag = policy_tag_from_str(tag_str);
@@ -209,41 +442,267 @@ int parse_config_file(const char * cfgpath, facemgr_t * facemgr)
policy_tags_add(&tags, tag);
}
- /* debug */
+ int rc = facemgr_cfg_rule_set_tags(rule, tags);
+ if (rc < 0)
+ goto ERR;
+
+#if 0
char tags_str[MAXSZ_POLICY_TAGS];
policy_tags_snprintf(tags_str, MAXSZ_POLICY_TAGS, tags);
- printf("Rule #%d interface_name=%s, tags=%s\n", i, interface_name, tags_str);
- face_rules_add(&facemgr->rules, strdup(interface_name), tags);
+ DEBUG("Added tags tags=%s", tags_str);
+#endif
+#endif
}
+
+ /* - overlay */
+ config_setting_t *overlay = config_setting_get_member(override_setting, "overlay");
+ if (overlay) {
+
+ /* ipv4 */
+ config_setting_t *overlay_v4 = config_setting_get_member(overlay, "ipv4");
+ if (overlay_v4) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr, remote_addr;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v4, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v4, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v4, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ /* ipv6 */
+ config_setting_t *overlay_v6 = config_setting_get_member(overlay, "ipv6");
+ if (overlay_v6) {
+ const char * local_addr_str, * remote_addr_str;
+ ip_address_t local_addr, remote_addr;
+ ip_address_t * local_addr_p = NULL;
+ ip_address_t * remote_addr_p = NULL;
+ int local_port = 0;
+ int remote_port = 0;
+
+ if (config_setting_lookup_string(overlay_v6, "local_addr", &local_addr_str)) {
+ ip_address_pton(local_addr_str, &local_addr);
+ local_addr_p = &local_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "local_port", &local_port)) {
+ if (!IS_VALID_PORT(local_port))
+ goto ERR;
+ }
+
+ if (config_setting_lookup_string(overlay_v6, "remote_addr", &remote_addr_str)) {
+ ip_address_pton(remote_addr_str, &remote_addr);
+ remote_addr_p = &remote_addr;
+ }
+
+ if (config_setting_lookup_int(overlay_v6, "remote_port", &remote_port)) {
+ if (!IS_VALID_PORT(remote_port))
+ goto ERR;
+ }
+ int rc = facemgr_cfg_rule_set_overlay(rule, AF_INET6,
+ local_addr_p, local_port,
+ remote_addr_p, remote_port);
+ if (rc < 0)
+ goto ERR;
+ }
+
+ } /* overlay */
+
+ /* Add newly created rule */
+
+ rc = facemgr_cfg_add_rule(cfg, rule);
+ if (rc < 0)
+ goto ERR;
}
+ return 0;
+
+ERR:
+ facemgr_cfg_rule_free(rule);
+ERR_RULE:
+ERR_CHECK:
+ return -1;
+}
- config_destroy(&cfg);
+/* Currently not using facemgr_cfg_t */
+int
+parse_config_log(facemgr_cfg_t * cfg, config_setting_t * setting)
+{
+ const char *log_level_str;
+ if (config_setting_lookup_string(setting, "log_level", &log_level_str)) {
+ if (strcasecmp(log_level_str, "FATAL") == 0) {
+ log_conf.log_level = LOG_FATAL;
+ } else
+ if (strcasecmp(log_level_str, "ERROR") == 0) {
+ log_conf.log_level = LOG_ERROR;
+ } else
+ if (strcasecmp(log_level_str, "WARN") == 0) {
+ log_conf.log_level = LOG_WARN;
+ } else
+ if (strcasecmp(log_level_str, "INFO") == 0) {
+ log_conf.log_level = LOG_INFO;
+ } else
+ if (strcasecmp(log_level_str, "DEBUG") == 0) {
+ log_conf.log_level = LOG_DEBUG;
+ } else
+ if (strcasecmp(log_level_str, "TRACE") == 0) {
+ log_conf.log_level = LOG_TRACE;
+ } else {
+ ERROR("Invalid log level in section 'log'");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int
+parse_config_file(const char * cfgpath, facemgr_cfg_t * cfg)
+{
+ /* Reading configuration file */
+ config_t cfgfile;
+ config_setting_t *setting;
+
+ config_init(&cfgfile);
+
+ /* Read the file. If there is an error, report it and exit. */
+ if(!config_read_file(&cfgfile, cfgpath))
+ goto ERR_FILE;
+
+ setting = config_lookup(&cfgfile, "global");
+ if (setting) {
+ int rc = parse_config_global(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ setting = config_lookup(&cfgfile, "rules");
+ if (setting) {
+ int rc = parse_config_rules(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ setting = config_lookup(&cfgfile, "log");
+ if (setting) {
+ int rc = parse_config_log(cfg, setting);
+ if (rc < 0)
+ goto ERR_PARSE;
+ }
+
+ config_destroy(&cfgfile);
return 0;
ERR_FILE:
- printf("Could not read configuration file %s\n", cfgpath);
- fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
- config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
+ ERROR("Could not read configuration file %s", cfgpath);
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile),
+ config_error_line(&cfgfile), config_error_text(&cfgfile));
+ config_destroy(&cfgfile);
exit(EXIT_FAILURE);
return -1;
-ERR:
- fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
- config_error_line(&cfg), config_error_text(&cfg));
- config_destroy(&cfg);
+ERR_PARSE:
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfgfile),
+ config_error_line(&cfgfile), config_error_text(&cfgfile));
+ config_destroy(&cfgfile);
return -1;
}
-#ifndef APPLE
-void dummy_handler(int fd, short event, void *arg) { }
-#endif /* APPLE */
+#ifdef __linux__
+typedef struct {
+ void (*cb)(void *, ...);
+ void * args;
+} cb_wrapper_args_t;
+
+void cb_wrapper(evutil_socket_t fd, short what, void * arg) {
+ cb_wrapper_args_t * cb_wrapper_args = arg;
+ cb_wrapper_args->cb(cb_wrapper_args->args);
+}
-int main(int argc, char **argv)
+struct event *
+loop_register_fd(struct event_base * loop, int fd, void * cb, void * cb_args)
{
- facemgr_t * facemgr = facemgr_create();
- if (!facemgr)
- goto ERR_FACEMGR;
+ // TODO: not freed
+ cb_wrapper_args_t * cb_wrapper_args = malloc(sizeof(cb_wrapper_args_t));
+ *cb_wrapper_args = (cb_wrapper_args_t) {
+ .cb = cb,
+ .args = cb_args,
+ };
+
+ evutil_make_socket_nonblocking(fd);
+ struct event * event = event_new(loop, fd, EV_READ | EV_PERSIST, cb_wrapper, cb_wrapper_args);
+ if (!event)
+ goto ERR_EVENT_NEW;
+
+ if (event_add(event, NULL) < 0)
+ goto ERR_EVENT_ADD;
+
+ return event;
+
+ERR_EVENT_ADD:
+ event_free(event);
+ERR_EVENT_NEW:
+ return NULL;
+}
+
+int
+loop_unregister_event(struct event_base * loop, struct event * event)
+{
+ if (!event)
+ return 0;
+
+ event_del(event);
+ event_free(event);
+
+ return 0;
+}
+
+
+void * start_dispatch(void * loop_ptr)
+{
+ struct event_base * loop = (struct event_base *) loop_ptr;
+ event_base_dispatch(loop);
+
+ return NULL;
+}
+
+#endif /* __linux__ */
+
+int main(int argc, char ** argv)
+{
+ facemgr_cfg_t * cfg = NULL;
+ facemgr_t * facemgr;
+#ifdef WITH_THREAD
+ pthread_t facemgr_thread;
+#endif /* WITH_THREAD */
+
+ struct sigaction sigIntHandler;
+ sigIntHandler.sa_handler = facemgr_signal_handler;
+ sigemptyset(&sigIntHandler.sa_mask);
+ sigIntHandler.sa_flags = 0;
+ sigaction(SIGINT, &sigIntHandler, NULL);
char cfgfile[PATH_MAX];
@@ -252,7 +711,7 @@ int main(int argc, char **argv)
/* Commandline */
facemgr_options_t cmdline_opts = {0};
if (parse_cmdline(argc, argv, &cmdline_opts) < 0) {
- ERROR("Error parsing commandline\n");
+ ERROR("Error parsing commandline");
goto ERR_CMDLINE;
}
@@ -260,7 +719,7 @@ int main(int argc, char **argv)
//facemgr_options_t cfgfile_opts;
if (cmdline_opts.cfgfile) {
- if (strcmp(cmdline_opts.cfgfile, "none") == 0)
+ if (strcasecmp(cmdline_opts.cfgfile, "none") == 0)
goto NO_CFGFILE;
if (!realpath(cmdline_opts.cfgfile, (char*)&cfgfile))
@@ -274,76 +733,118 @@ int main(int argc, char **argv)
if (probe_cfgfile(cfgfile) < 0)
goto NO_CFGFILE;
- printf("Using configuration file %s\n", cfgfile);
-
PARSE_CFGFILE:
- if (parse_config_file(cfgfile, facemgr) < 0) {
- ERROR("Error parsing configuration file %s\n", cfgfile);
+ DEBUG("Using configuration file %s", cfgfile);
+ cfg = facemgr_cfg_create();
+ if (!cfg)
+ goto ERR_FACEMGR_CFG;
+
+ if (parse_config_file(cfgfile, cfg) < 0) {
+ ERROR("Error parsing configuration file %s", cfgfile);
goto ERR_PARSE;
}
+ facemgr = facemgr_create_with_config(cfg);
+ if (!facemgr)
+ goto ERR_FACEMGR_CONFIG;
+
+ goto MAIN_LOOP;
+
NO_CFGFILE:
+ facemgr = facemgr_create();
+ if (!facemgr)
+ goto ERR_FACEMGR;
+
+MAIN_LOOP:
+
+ /* Main loop */
+
+
+#ifdef WITH_THREAD
+ evthread_use_pthreads();
+#endif /* WITH_THREAD */
+
#ifdef __linux__
- facemgr->loop = event_base_new();
- if (!facemgr->loop)
- fatal("Could not create an event base");
-
- /* Main loop
- *
- * To avoid the loop to exit when empty, we might either rely on an option
- * introduced from versions 2.1.x:
- * event_base_loop(loop->base, EVLOOP_NO_EXIT_ON_EMPTY);
- * or use this workaround:
- * http://archives.seul.org/libevent/users/Sep-2012/msg00056.html
- *
- * TODO:
- * - HUP should interrupt the main loop
- */
- {
- struct event *ev;
- struct timeval tv;
- tv.tv_sec = FACEMGR_TIMEOUT;
- tv.tv_usec = 0;
-
- ev = event_new(facemgr->loop, fileno(stdin), EV_TIMEOUT | EV_PERSIST, dummy_handler, NULL);
- event_add(ev, &tv);
- }
+ /* Event loop */
+ loop = event_base_new();
+ if (!loop)
+ goto ERR_EVENT;
+
+ facemgr_set_event_loop_handler(facemgr, loop, loop_register_fd, loop_unregister_event);
#endif /* __linux__ */
- DEBUG("Bootstrap...\n");
+#ifdef __ANDROID__
+ facemgr_set_jvm(facemgr, NULL, NULL); // FIXME
+#endif /* __ ANDROID__ */
+
+ DEBUG("Bootstrap...");
+
if (facemgr_bootstrap(facemgr) < 0 )
goto ERR_BOOTSTRAP;
#ifdef __linux__
event_set_log_callback(NULL);
- event_base_dispatch(facemgr->loop);
- event_base_free(facemgr->loop);
+#ifdef WITH_THREAD
+ if (pthread_create(&facemgr_thread, NULL, start_dispatch, loop)) {
+ fprintf(stderr, "Error creating thread\n");
+ return EXIT_FAILURE;
+ }
+#else
+ event_base_dispatch(loop);
+#endif /* WITH_THREAD */
+
#endif /* __linux__ */
#ifdef __APPLE__
/* Main loop */
- facemgr->loop = NULL;
dispatch_main();
#endif /* __APPLE__ */
- /* Clean up */
- //interface_delete_all();
+#ifdef __linux__
+#ifdef WITH_THREAD
+ for(;;) {
+ facemgr_list_faces(facemgr, NULL, NULL);
+ sleep(5);
+ }
+#endif /* WITH_THREAD */
+#endif /* __linux__ */
+
+ facemgr_stop(facemgr);
+#ifdef __linux__
+#ifdef WITH_THREAD
+ DEBUG("Waiting for loop to terminate...");
+ if(pthread_join(facemgr_thread, NULL)) {
+ fprintf(stderr, "Error joining thread\n");
+ return EXIT_FAILURE;
+ }
+ DEBUG("Loop terminated !");
+#endif /* WITH_THREAD */
+#endif /* __linux__ */
facemgr_free(facemgr);
return EXIT_SUCCESS;
ERR_BOOTSTRAP:
+#ifdef __linux__
+ERR_EVENT:
+#endif /* __linux__ */
+
+ facemgr_free(facemgr);
+ERR_FACEMGR_CONFIG:
+ if (cfg)
+ facemgr_cfg_free(cfg);
+ERR_FACEMGR:
+ERR_FACEMGR_CFG:
+
ERR_PARSE:
ERR_PATH:
ERR_CMDLINE:
- facemgr_free(facemgr);
-ERR_FACEMGR:
return EXIT_FAILURE;
-}
+}
diff --git a/ctrl/facemgr/src/netdevice.h b/ctrl/facemgr/src/netdevice.h
deleted file mode 100644
index b64ad0f9a..000000000
--- a/ctrl/facemgr/src/netdevice.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 netdevice.h
- * \brief Netdevice abstraction
- */
-#ifndef FACEMGR_NETDEVICE_H
-#define FACEMGR_NETDEVICE_H
-
-#include <net/if.h> // IFNAMSIZ
-
-#include "common.h"
-
-#define foreach_netdevice_type \
- _(UNDEFINED) \
- _(WIRED) \
- _(WIFI) \
- _(CELLULAR) \
- _(VPN) \
- _(N)
-
-#define MAXSZ_NETDEVICE_TYPE 9
-#define MAXSZ_NETDEVICE_TYPE_ MAXSZ_NETDEVICE_TYPE
-
-typedef enum {
-#define _(x) x,
-foreach_netdevice_type
-#undef _
-} netdevice_type_t;
-
-extern const char * netdevice_type_str[];
-
-
-typedef struct {
- u32 index;
- char name[IFNAMSIZ];
-} netdevice_t;
-
-#endif /* FACEMGR_NETDEVICE_H */
diff --git a/ctrl/facemgr/src/util/ip_address.h b/ctrl/facemgr/src/util/ip_address.h
deleted file mode 100644
index 243ce048b..000000000
--- a/ctrl/facemgr/src/util/ip_address.h
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 ip_address.h
- * \brief IP address type support
- */
-#ifndef UTIL_IP_ADDRESS_H
-#define UTIL_IP_ADDRESS_H
-
-#include <arpa/inet.h> // inet_ntop
-#ifdef __APPLE__
-#include <libkern/OSByteOrder.h>
-#define __bswap_constant_32(x) OSSwapInt32(x)
-#include <machine/endian.h>
-#else
-#include <endian.h>
-#ifdef __ANDROID__
-#include <byteswap.h>
-#endif
-#endif
-#include <errno.h>
-#include <netdb.h> // struct addrinfo
-#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK
-#include <stdlib.h>
-#include <stdio.h> // snprintf
-#include <string.h> // memset
-
-#include "types.h"
-
-#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 DUMMY_PORT 1234
-
-typedef union {
- union {
- struct in_addr as_inaddr;
- u8 as_u8[4];
- u16 as_u16[2];
- u32 as_u32;
- } v4;
- union {
- struct in6_addr as_in6addr;
- u8 as_u8[16];
- u16 as_u16[8];
- u32 as_u32[4];
- u64 as_u64[2];
- } v6;
- 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];
-} ip_address_t;
-
-#define MAXSZ_IP4_ADDRESS_ INET_ADDRSTRLEN - 1
-#define MAXSZ_IP6_ADDRESS_ INET6_ADDRSTRLEN - 1
-#define MAXSZ_IP_ADDRESS_ MAXSZ_IP6_ADDRESS_
-#define MAXSZ_IP4_ADDRESS MAXSZ_IP4_ADDRESS_ + 1
-#define MAXSZ_IP6_ADDRESS MAXSZ_IP6_ADDRESS_ + 1
-#define MAXSZ_IP_ADDRESS MAXSZ_IP_ADDRESS_ + 1
-
-typedef struct {
- int family;
- ip_address_t address;
- u8 len;
-} ip_prefix_t;
-
-#define MAXSZ_PREFIX_ MAXSZ_IP_ADDRESS_ + 1 + 3
-#define MAXSZ_PREFIX MAXSZ_PREFIX_ + 1
-
-/* No htonl() with const */
-static const ip_address_t IPV4_LOOPBACK = {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#ifdef __ANDROID__
- .v4.as_inaddr.s_addr = bswap_32(INADDR_LOOPBACK),
-#else
- .v4.as_inaddr.s_addr = __bswap_constant_32(INADDR_LOOPBACK),
-#endif
-#else
- .v4.as_inaddr.s_addr = INADDR_LOOPBACK,
-#endif
-};
-
-static const ip_address_t IPV6_LOOPBACK = {
- .v6.as_in6addr = IN6ADDR_LOOPBACK_INIT,
-};
-
-static const ip_address_t IPV4_ANY = {
- .v4.as_inaddr.s_addr = INADDR_ANY,
-};
-
-static const ip_address_t IPV6_ANY = {
- .v6.as_in6addr = IN6ADDR_ANY_INIT,
-};
-
-#define IP_ANY(family) (family == AF_INET) ? IPV4_ANY : IPV6_ANY
-
-static const ip_address_t IP_ADDRESS_EMPTY = {
- .as_u64 = { 0 },
-};
-
-
-#define MAX_PORT 1 << (8 * sizeof(u16))
-#define IS_VALID_PORT(x) ((x > 0) && (x < MAX_PORT))
-
-#define MAXSZ_PORT_ 5
-#define MAXSZ_PORT MAXSZ_PORT_ + 1
-
-#define IS_VALID_FAMILY(x) ((x == AF_INET) || (x == AF_INET6))
-
-static inline
-int
-ip_address_get_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;
-}
-
-static inline
-int
-ip_address_len (const ip_address_t * ip_address, int family)
-{
- return (family == AF_INET6) ? IPV6_ADDR_LEN :
- (family == AF_INET) ? IPV4_ADDR_LEN : 0;
-}
-
-static inline
-int
-ip_address_ntop (const ip_address_t * ip_address, char *dst, const size_t len,
- int family)
-{
- const char * s = inet_ntop (family, ip_address->buffer, dst, len);
- return (s ? 1 : -1);
-}
-
-/*
- * Parse ip addresses in presentation format
- */
-static inline
-int
-ip_address_pton (const char *ip_address_str, ip_address_t * ip_address)
-{
- int pton_fd;
- char *addr = strdup (ip_address_str);
- int family;
-
-
- family = ip_address_get_family (addr);
-
- switch (family)
- {
- case AF_INET6:
- pton_fd = inet_pton (AF_INET6, addr, &ip_address->buffer);
- break;
- case AF_INET:
- pton_fd = inet_pton (AF_INET, addr, &ip_address->buffer);
- break;
- default:
- goto ERR;
- }
-
- // 0 = not in presentation format
- // < 0 = other error (use perror)
- if (pton_fd <= 0)
- {
- goto ERR;
- }
-
- return 1;
-ERR:
- free (addr);
- return -1;
-}
-
-
-
-static inline
-int
-ip_address_snprintf(char * s, size_t size, const ip_address_t * ip_address, int family)
-{
- size_t len = family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
- const char * rc = inet_ntop (family, ip_address->buffer, s, len);
- return rc ? strlen(rc) : -1;
-}
-
-
-static inline
-int
-ip_address_to_sockaddr(const ip_address_t * ip_address,
- struct sockaddr *sockaddr_address, int family)
-{
- struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *) sockaddr_address;
- struct sockaddr_in *tmp4 = (struct sockaddr_in *) sockaddr_address;
-
- switch (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 -1;
- }
-
- return 1;
-}
-
-static inline
-int
-ip_address_cmp(const ip_address_t * ip1, const ip_address_t * ip2, int family)
-{
- return memcmp(ip1, ip2, ip_address_len(ip1, family));
-}
-
-static inline
-int
-ip_address_empty(const ip_address_t * ip)
-{
- return (memcmp(ip, &IP_ADDRESS_EMPTY, sizeof(IP_ADDRESS_EMPTY)) == 0);
-}
-
-/* Parse IP Prefixes in presentation format (in bits, separated by a slash) */
-static inline
-int
-ip_prefix_pton (const char *ip_address_str, ip_prefix_t * ip_prefix)
-{
- int pton_fd;
- char *p;
- char *eptr;
- char *addr = strdup (ip_address_str);
-
- p = strchr (addr, '/');
- if (!p)
- {
- ip_prefix->len = 0; // until we get the ip address family
- }
- else
- {
- ip_prefix->len = strtoul (p + 1, &eptr, 10);
- *p = 0;
- }
-
- ip_prefix->family = ip_address_get_family (addr);
-
- switch (ip_prefix->family)
- {
- case AF_INET6:
- if (ip_prefix->len > IPV6_ADDR_LEN_BITS)
- goto ERR;
- pton_fd = inet_pton (AF_INET6, addr, &ip_prefix->address.buffer);
- break;
- case AF_INET:
- if (ip_prefix->len > IPV4_ADDR_LEN_BITS)
- goto ERR;
- pton_fd = inet_pton (AF_INET, addr, &ip_prefix->address.buffer);
- break;
- default:
- goto ERR;
- }
-
- // 0 = not in presentation format
- // < 0 = other error (use perror)
- if (pton_fd <= 0)
- {
- goto ERR;
- }
-
- return 1;
-ERR:
- free (addr);
- return -1;
-}
-
-static inline
-int
-ip_prefix_ntop (const ip_prefix_t * ip_prefix, char *dst, size_t size)
-{
- char ip_s[MAXSZ_IP_ADDRESS];
- const char * s = inet_ntop (ip_prefix->family, ip_prefix->address.buffer, ip_s, MAXSZ_IP_ADDRESS);
- if (!s)
- return -1;
- size_t n = snprintf(dst, size, "%s/%d", ip_s, ip_prefix->len);
-
- return (n > 0 ? 1 : -1);
-}
-
-
-#endif /* UTIL_IP_ADDRESS_H */
diff --git a/ctrl/facemgr/src/util/log.c b/ctrl/facemgr/src/util/log.c
index 54943cf45..c1fc999ad 100644
--- a/ctrl/facemgr/src/util/log.c
+++ b/ctrl/facemgr/src/util/log.c
@@ -13,12 +13,16 @@
* limitations under the License.
*/
-#include "log.h"
+#include <hicn/util/log.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+
log_conf_t log_conf = DEFAULT_LOG_CONF;
#define FMT_DATETIME "%02d-%02d-%04d %02d:%02d:%02d"
@@ -43,48 +47,96 @@ static char *timestamp(void)
}
void _log_va(int level, const char *fmt, va_list ap)
-{
- char *prefix;
- FILE *f = log_conf.log_file ? log_conf.log_file : stdout;
+{
#if 0
if (!conf.log_system)
return;
#endif
+ char *prefix;
+
+#ifdef __ANDROID__
+ int prio = -1;
if (level > log_conf.log_level)
return;
switch (level) {
case LOG_FATAL:
+ prio = ANDROID_LOG_FATAL;
prefix = "FATAL: ";
break;
case LOG_ERROR:
+ prio = ANDROID_LOG_ERROR;
prefix = "ERROR: ";
break;
case LOG_WARN:
+ prio = ANDROID_LOG_WARN;
prefix = "WARNING: ";
break;
case LOG_INFO:
+ prio = ANDROID_LOG_INFO;
prefix = "";
break;
case LOG_DEBUG:
+ prio = ANDROID_LOG_DEBUG;
prefix = "DEBUG: ";
break;
case LOG_TRACE:
+ prio = ANDROID_LOG_DEBUG;
prefix = "TRACE: ";
break;
default:
+ prio = ANDROID_LOG_INFO;
prefix = "";
break;
}
+ if (log_conf.log_file) {
+ FILE *f = log_conf.log_file;
+ fprintf(f, "%s %s", timestamp(), prefix);
+ vfprintf(f, fmt, ap);
+ fprintf(f, "\n");
+ } else {
+ __android_log_vprint(ANDROID_LOG_INFO, "HICN FACEMGR", fmt, ap);
+ }
+
+#else
+
+ if (level > log_conf.log_level)
+ return;
+
+ switch (level) {
+ case LOG_FATAL:
+ prefix = "FATAL: ";
+ break;
+ case LOG_ERROR:
+ prefix = "ERROR: ";
+ break;
+ case LOG_WARN:
+ prefix = "WARNING: ";
+ break;
+ case LOG_INFO:
+ prefix = "";
+ break;
+ case LOG_DEBUG:
+ prefix = "DEBUG: ";
+ break;
+ case LOG_TRACE:
+ prefix = "TRACE: ";
+ break;
+ default:
+ prefix = "";
+ break;
+ }
+ FILE *f = log_conf.log_file ? log_conf.log_file : stdout;
fprintf(f, "%s %s", timestamp(), prefix);
vfprintf(f, fmt, ap);
fprintf(f, "\n");
#ifdef DEBUG
fflush(f);
#endif
+#endif
}
void _log(int level, const char *fmt, ...)
diff --git a/ctrl/facemgr/src/util/map.h b/ctrl/facemgr/src/util/map.h
index 2694de2a7..b6773f209 100644
--- a/ctrl/facemgr/src/util/map.h
+++ b/ctrl/facemgr/src/util/map.h
@@ -31,6 +31,10 @@ typedef struct {
VAL_T value; \
} NAME ## _pair_t; \
\
+NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value); \
+ \
+void NAME ## _pair_free(NAME ## _pair_t * pair); \
+ \
int NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2); \
\
TYPEDEF_SET_H(NAME ## _pair_set, NAME ## _pair_t *) \
@@ -47,7 +51,7 @@ NAME ## _t * NAME ## _create();
\
void NAME ## _free(NAME ## _t * map); \
\
-int NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value); \
+int NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value); \
\
int NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value); \
\
@@ -60,6 +64,24 @@ void NAME ## _dump(NAME ## _t * map);
#define TYPEDEF_MAP(NAME, KEY_T, VAL_T, CMP, KEY_SNPRINTF, VALUE_SNPRINTF) \
\
+NAME ## _pair_t * NAME ## _pair_create(KEY_T key, VAL_T value) \
+{ \
+ /* Create pair */ \
+ NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \
+ if (!pair) \
+ return NULL; \
+ \
+ pair->key = key; \
+ pair->value = value; \
+ \
+ return pair; \
+} \
+ \
+void NAME ## _pair_free(NAME ## _pair_t * pair) \
+{ \
+ free(pair); \
+} \
+ \
int \
NAME ## _pair_cmp(const NAME ## _pair_t * p1, const NAME ## _pair_t * p2) \
{ \
@@ -72,7 +94,7 @@ NAME ## _pair_snprintf(char * buf, size_t size, const NAME ## _pair_t * pair) {
rc = KEY_SNPRINTF(buf, BUFSIZE/2, (KEY_T)pair->key); \
if (rc < 0) \
return rc; \
- rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \
+ rc = VALUE_SNPRINTF(buf+rc, BUFSIZE/2, (VAL_T)pair->value); \
return rc; \
} \
\
@@ -93,57 +115,98 @@ NAME ## _finalize(NAME ## _t * map)
AUTOGENERATE_CREATE_FREE(NAME) \
\
int \
-NAME ## _add(NAME ## _t * map, KEY_T key, const VAL_T value) \
+NAME ## _add(NAME ## _t * map, KEY_T key, VAL_T value) \
{ \
int rc; \
+ NAME ## _pair_t * found = NULL; \
\
- /* Create pair */ \
- NAME ## _pair_t * pair = malloc(sizeof(NAME ## _pair_t)); \
+ NAME ## _pair_t * pair = NAME ## _pair_create(key, value); \
if (!pair) \
- return FACEMGR_FAILURE; \
- \
- pair->key = key; \
- pair->value = (VAL_T)value; \
+ return -1; \
\
- rc = NAME ## _pair_set_get(&map->pair_set, pair, NULL); \
- if (!FACEMGR_IS_ERROR(rc)) { \
- free(pair); \
+ rc = NAME ## _pair_set_get(&map->pair_set, pair, &found); \
+ if (rc < 0) \
+ return -1; \
+ if (found) { \
+ NAME ## _pair_free(pair); \
return ERR_MAP_EXISTS; \
} \
\
rc = NAME ## _pair_set_add(&map->pair_set, pair); \
- if (FACEMGR_IS_ERROR(rc)) { \
- free(pair); \
- return FACEMGR_FAILURE; \
+ if (rc < 0) { \
+ NAME ## _pair_free(pair); \
+ return -1; \
} \
- return FACEMGR_SUCCESS; \
+ return 0; \
} \
\
int \
NAME ## _remove(NAME ## _t * map, KEY_T key, VAL_T * value) \
{ \
- NAME ## _pair_t * found, search = { .key = key }; \
+ NAME ## _pair_t * found = NULL; \
+ NAME ## _pair_t search = { .key = key }; \
int rc = NAME ## _pair_set_remove(&map->pair_set, &search, &found); \
- if (FACEMGR_IS_ERROR(rc)) \
+ if (rc < 0) \
return ERR_MAP_NOT_FOUND; \
- *value = found->value; \
- return FACEMGR_SUCCESS; \
+ if (value) \
+ *value = found->value; \
+ NAME ## _pair_free(found); \
+ return 0; \
} \
\
int \
NAME ## _get(NAME ## _t * map, KEY_T key, VAL_T * value) \
{ \
- NAME ## _pair_t * found, search = { .key = key }; \
+ NAME ## _pair_t * found = NULL, search = { .key = key }; \
int rc = NAME ## _pair_set_get(&map->pair_set, &search, &found); \
- if (FACEMGR_IS_ERROR(rc)) \
- return ERR_MAP_NOT_FOUND; \
- *value = found->value; \
- return FACEMGR_SUCCESS; \
+ if (rc < 0) \
+ return -1; \
+ if (found) \
+ *value = found->value; \
+ return 0; \
} \
\
void \
NAME ## _dump(NAME ## _t * map) { \
NAME ## _pair_set_dump(&map->pair_set); \
+} \
+ \
+int \
+NAME ## _get_key_array(NAME ## _t * map, KEY_T **array) { \
+ NAME ## _pair_t ** pair_array; \
+ int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \
+ if (n < 0) \
+ return -1; \
+ /* Allocate result array */ \
+ array = malloc(n * sizeof(KEY_T)); \
+ if (!array) { \
+ free(pair_array); \
+ return -1; \
+ } \
+ /* Copy keys */ \
+ for (int i = 0; i < n; i++) \
+ array[i] = &pair_array[i]->key; \
+ free(pair_array); \
+ return 0; \
+} \
+ \
+int \
+NAME ## _get_value_array(NAME ## _t * map, VAL_T **array) { \
+ NAME ## _pair_t ** pair_array; \
+ int n = NAME ## _pair_set_get_array(&map->pair_set, &pair_array); \
+ if (n < 0) \
+ return -1; \
+ /* Allocate result array */ \
+ array = malloc(n * sizeof(VAL_T)); \
+ if (!array) { \
+ free(pair_array); \
+ return -1; \
+ } \
+ /* Copy values */ \
+ for (int i = 0; i < n; i++) \
+ array[i] = &pair_array[i]->value; \
+ free(pair_array); \
+ return 0; \
}
#endif /* UTIL_MAP_H */
diff --git a/ctrl/facemgr/src/util/policy.c b/ctrl/facemgr/src/util/policy.c
deleted file mode 100644
index 6c8651ee3..000000000
--- a/ctrl/facemgr/src/util/policy.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 policy.h
- * \brief Implementation of policy description
- */
-
-#include <stdio.h>
-#include "policy.h"
-
-const char * policy_tag_str[] = {
- #define _(x, y) [POLICY_TAG_ ## x] = STRINGIZE(x),
- foreach_policy_tag
- #undef _
-};
-
-const char policy_tag_short_str[] = {
- #define _(x, y) [POLICY_TAG_ ## x] = y,
- foreach_policy_tag
- #undef _
-};
-
-const char * policy_state_str[] = {
- #define _(x) [POLICY_STATE_ ## x] = STRINGIZE(x),
- foreach_policy_state
- #undef _
-};
-
-int
-policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state)
-{
- char *cur = s;
- int rc;
-
- if (tag_state->disabled > 1)
- return -1;
-
- rc = snprintf(cur, s + size - cur, "%s%s", (tag_state->disabled == 1) ? "!" : "", policy_state_str[tag_state->state]);
- if (rc < 0)
- return rc;
- cur += rc;
- if (size != 0 && cur >= s + size)
- return cur - s;
-
- return cur - s;
-}
diff --git a/ctrl/facemgr/src/util/policy.h b/ctrl/facemgr/src/util/policy.h
deleted file mode 100644
index e20af6560..000000000
--- a/ctrl/facemgr/src/util/policy.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 policy.h
- * \brief Policy description
- */
-#ifndef HICN_POLICY_H
-#define HICN_POLICY_H
-
-#include <netinet/in.h> // INET*_ADDRSTRLEN
-#include <string.h> // strcasecmp
-#include "token.h"
-
-/* POLICY TAG */
-
-#define foreach_policy_tag \
- /* Interface type */ \
- _(WIRED, 'E') \
- _(WIFI, 'W') \
- _(CELLULAR, 'C') \
- /* QoS */ \
- _(BEST_EFFORT, 'b') \
- _(REALTIME, 'r') \
- _(MULTIPATH, 'M') \
- /* Security */ \
- _(TRUSTED, 'T')
-
-typedef enum {
-#define _(x, y) POLICY_TAG_ ## x,
-foreach_policy_tag
-#undef _
- POLICY_TAG_N
-} policy_tag_t;
-
-#define MAXSZ_POLICY_TAG_ 11
-#define MAXSZ_POLICY_TAG MAXSZ_POLICY_TAG_ + 1
-
-extern const char * policy_tag_str[];
-extern const char policy_tag_short_str[];
-
-static inline
-policy_tag_t
-policy_tag_from_str(const char * str)
-{
-#define _(x, y) if (strcasecmp(str, policy_tag_str[POLICY_TAG_ ## x] ) == 0) { return POLICY_TAG_ ## x; } else
-foreach_policy_tag
-#undef _
- return POLICY_TAG_N;
-}
-
-/* POLICY_TAGS */
-
-typedef int policy_tags_t;
-
-static inline
-void policy_tags_add(policy_tags_t * tags, policy_tag_t tag)
-{
- *tags |= (1 << tag);
-}
-
-static inline
-void policy_tags_remove(policy_tags_t * tags, policy_tag_t tag)
-{
- *tags &= ~(1 << tag);
-}
-
-static inline
-int policy_tags_has(policy_tags_t tags, policy_tag_t tag)
-{
- return tags & (1 << tag);
-}
-
-#define POLICY_TAGS_EMPTY 0
-
-static inline
-int
-policy_tags_snprintf(char * s, size_t size, policy_tags_t tags)
-{
-#define _(x, y) s[POLICY_TAG_ ## x] = policy_tags_has(tags, POLICY_TAG_ ## x) ? y : '.';
-foreach_policy_tag
-#undef _
- s[POLICY_TAG_N] = '\0';
- return POLICY_TAG_N + 1;
-}
-
-#define MAXSZ_POLICY_TAGS_ POLICY_TAG_N
-#define MAXSZ_POLICY_TAGS MAXSZ_POLICY_TAGS_ + 1
-
-/* POLICY STATE */
-
-/* TODO vs. weight */
-
-#define foreach_policy_state \
- _(NEUTRAL) \
- _(REQUIRE) \
- _(PREFER) \
- _(AVOID) \
- _(PROHIBIT) \
- _(N)
-
-typedef enum {
-#define _(x) POLICY_STATE_ ## x,
-foreach_policy_state
-#undef _
-} policy_state_t;
-
-#define MAXSZ_POLICY_STATE_ 8
-#define MAXSZ_POLICY_STATE MAXSZ_POLICY_STATE_ + 1
-
-extern const char * policy_state_str[];
-
-
-/* POLICY TAG STATE */
-
-typedef struct {
- policy_state_t state;
- uint8_t disabled;
-} policy_tag_state_t;
-
-#define MAXSZ_POLICY_TAG_STATE_ 8
-#define MAXSZ_POLICY_TAG_STATE MAXSZ_POLICY_TAG_STATE_ + 1
-
-int policy_tag_state_snprintf(char * s, size_t size, const policy_tag_state_t * tag_state);
-
-
-/* INTERFACE STATS */
-
-typedef struct {
- float throughput;
- float latency;
- float loss_rate;
-} interface_stats_t;
-
-#define INTERFACE_STATS_NONE { \
- .throughput = 0, \
- .latency = 0, \
- .loss_rate = 0, \
-}
-
-
-/* POLICY STATS */
-
-typedef struct {
- interface_stats_t wired;
- interface_stats_t wifi;
- interface_stats_t cellular;
- interface_stats_t all;
-} policy_stats_t;
-
-#define POLICY_STATS_NONE { \
- .wired = INTERFACE_STATS_NONE, \
- .wifi = INTERFACE_STATS_NONE, \
- .cellular = INTERFACE_STATS_NONE, \
- .all = INTERFACE_STATS_NONE, \
-}
-
-typedef struct {
- uint32_t num_packets;
- uint32_t num_bytes;
- uint32_t num_losses;
- uint32_t latency_idle;
-} interface_counters_t;
-
-#define INTERFACE_COUNTERS_NONE { \
- .num_packets = 0, \
- .num_bytes = 0, \
- .num_losses = 0, \
- .latency_idle = 0, \
-}
-
-typedef struct {
- interface_counters_t wired;
- interface_counters_t wifi;
- interface_counters_t cellular;
- interface_counters_t all;
- uint64_t last_update;
-} policy_counters_t;
-
-#define POLICY_COUNTERS_NONE (policy_counters_t) { \
- .wired = INTERFACE_COUNTERS_NONE, \
- .wifi = INTERFACE_COUNTERS_NONE, \
- .cellular = INTERFACE_COUNTERS_NONE, \
- .all = INTERFACE_COUNTERS_NONE, \
- .last_update = 0, \
-}
-
-/* POLICY */
-
-#define APP_NAME_LEN 128
-
-typedef struct {
- char app_name[APP_NAME_LEN];
- policy_tag_state_t tags[POLICY_TAG_N];
- policy_stats_t stats;
-} policy_t;
-
-static const policy_t POLICY_NONE = {
- .app_name = { 0 },
- .tags = {
-#define _(x, y) [POLICY_TAG_ ## x] = { POLICY_STATE_NEUTRAL, 0 },
-foreach_policy_tag
-#undef _
- },
- .stats = POLICY_STATS_NONE,
-};
-
-
-/* POLICY DESCRIPTION */
-
-#define PFX_STRLEN 4 /* eg. /128 */
-
-typedef struct {
- int family;
- union {
- char ipv4_prefix[INET_ADDRSTRLEN + PFX_STRLEN];
- char ipv6_prefix[INET6_ADDRSTRLEN + PFX_STRLEN];
- };
- policy_t policy;
-} policy_description_t;
-
-#endif /* HICN_POLICY_H */
diff --git a/ctrl/facemgr/src/util/set.h b/ctrl/facemgr/src/util/set.h
index 47a6eeaff..61df209ab 100644
--- a/ctrl/facemgr/src/util/set.h
+++ b/ctrl/facemgr/src/util/set.h
@@ -16,15 +16,27 @@
#ifndef UTIL_SET_H
#define UTIL_SET_H
+#include <hicn/util/log.h>
#include <search.h>
#include <string.h>
-#include "token.h"
+//#if !defined(__ANDROID__) && !defined(__APPLE__)
+//#include <threads.h>
+//#else
+#define thread_local _Thread_local
+//#endif /* ! __ANDROID__ */
#include "../common.h"
#define ERR_SET_EXISTS -2
#define ERR_SET_NOT_FOUND -3
-#define BUFSIZE 80
+/* FIXME: buffer overflow when this is too small... investigate */
+#define BUFSIZE 1024
+
+static inline
+int
+int_snprintf(char * buf, size_t size, int value) {
+ return snprintf(buf, size, "%d", value);
+}
static inline
int
@@ -34,7 +46,7 @@ string_snprintf(char * buf, size_t size, const char * s) {
static inline
int
-generic_snprintf(char * buf, size_t size, void * value) {
+generic_snprintf(char * buf, size_t size, const void * value) {
return snprintf(buf, BUFSIZE, "%p", value);
}
@@ -57,7 +69,9 @@ int NAME ## _add(NAME ## _t * set, const T element); \
\
int NAME ## _remove(NAME ## _t * set, const T search, T * element); \
\
-int NAME ## _get(NAME ## _t * set, const T search, T * element); \
+int NAME ## _get(const NAME ## _t * set, const T search, T * element); \
+ \
+int NAME ## _get_array(const NAME ## _t * set, T ** element); \
\
void NAME ## _dump(NAME ## _t * set);
@@ -70,7 +84,7 @@ NAME ## _initialize(NAME ## _t * set) \
{ \
set->root = NULL; \
set->size = 0; \
- return FACEMGR_SUCCESS; \
+ return 0; \
} \
\
NO_FINALIZE(NAME); \
@@ -79,49 +93,88 @@ AUTOGENERATE_CREATE_FREE(NAME); \
int \
NAME ## _add(NAME ## _t * set, const T element) \
{ \
- return tsearch(element, &set->root, (cmp_t)CMP) \
- ? FACEMGR_SUCCESS : FACEMGR_FAILURE; \
+ void * ptr = tsearch(element, &set->root, (cmp_t)CMP); \
+ if (!ptr) \
+ return -1; \
+ set->size++; \
+ return 0; \
} \
\
int \
NAME ## _remove(NAME ## _t * set, const T search, T * element) \
{ \
- T * found = tdelete(search, &set->root, (cmp_t)CMP); \
- if (found && element) \
+ T * found = tfind(search, &set->root, (cmp_t)CMP); \
+ if (!found) \
+ return ERR_SET_NOT_FOUND; \
+ if (element) \
*element = *found; \
- return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \
+ tdelete(search, &set->root, (cmp_t)CMP); \
+ set->size--; \
+ return 0; \
} \
\
int \
-NAME ## _get(NAME ## _t * set, const T search, T * element) \
+NAME ## _get(const NAME ## _t * set, const T search, T * element) \
{ \
T * found = tfind(search, &set->root, (cmp_t)CMP); \
- if (found && element) \
- *element = *found; \
- return found ? FACEMGR_SUCCESS : ERR_SET_NOT_FOUND; \
+ if (element) \
+ *element = found ? *found : NULL; \
+ return 0; \
} \
\
-void \
-__ ## NAME ## _dump_node(const void *nodep, const VISIT which, const int depth) \
+static void \
+NAME ## _dump_node(const void *nodep, const VISIT which, \
+ const int depth) \
{ \
char buf[BUFSIZE]; \
switch (which) { \
case preorder: \
- break; \
- case postorder: \
- break; \
case endorder: \
break; \
+ case postorder: \
case leaf: \
SNPRINTF(buf, BUFSIZE, *(T*)nodep); \
- printf("%s\n", buf); \
+ INFO("%s", buf); \
break; \
} \
} \
\
void \
NAME ## _dump(NAME ## _t * set) { \
- twalk(set->root, __ ## NAME ## _dump_node); \
+ twalk(set->root, NAME ## _dump_node); \
} \
+ \
+thread_local \
+T * NAME ## _array_pos = NULL; \
+ \
+static void \
+NAME ## _add_node_to_array(const void *nodep, const VISIT which, \
+ const int depth) \
+{ \
+ if (!NAME ## _array_pos) \
+ return; \
+ switch (which) { \
+ case preorder: \
+ case endorder: \
+ break; \
+ case postorder: \
+ case leaf: \
+ *NAME ## _array_pos = *(T*)nodep; \
+ NAME ## _array_pos++; \
+ break; \
+ } \
+} \
+ \
+int \
+NAME ## _get_array(const NAME ## _t * set, T ** element) \
+{ \
+ *element = malloc(set->size * sizeof(T)); \
+ if (!*element) \
+ return -1; \
+ NAME ## _array_pos = *element; \
+ twalk(set->root, NAME ## _add_node_to_array); \
+ NAME ## _array_pos = NULL; \
+ return set->size; \
+}
#endif /* UTIL_SET_H */
diff --git a/ctrl/facemgr/src/util/token.h b/ctrl/facemgr/src/util/token.h
deleted file mode 100644
index 43e0a77b2..000000000
--- a/ctrl/facemgr/src/util/token.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Token concatenation */
-
-/*
- * Concatenate preprocessor tokens A and B without expanding macro definitions
- * (however, if invoked from a macro, macro arguments are expanded).
- */
-#define PPCAT_NX(A, B) A ## B
-
-/*
- * Concatenate preprocessor tokens A and B after macro-expanding them.
- */
-#define PPCAT(A, B) PPCAT_NX(A, B)
-
-/* Token stringification */
-
-/*
- * Turn A into a string literal without expanding macro definitions
- * (however, if invoked from a macro, macro arguments are expanded).
- */
-#define STRINGIZE_NX(A) #A
-
-/*
- * Turn A into a string literal after macro-expanding it.
- */
-#define STRINGIZE(A) STRINGIZE_NX(A)
diff --git a/ctrl/facemgr/src/util/types.h b/ctrl/facemgr/src/util/types.h
deleted file mode 100644
index 10a0bdca0..000000000
--- a/ctrl/facemgr/src/util/types.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2017-2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 UTIL_TYPES
-#define UTIL_TYPES
-
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-
-/* Helper for avoiding warnings about type-punning */
-#define UNION_CAST(x, destType) \
- (((union {__typeof__(x) a; destType b;})x).b)
-
-typedef unsigned int hash_t;
-
-typedef int (*cmp_t)(const void *, const void *);
-
-/* Enums */
-
-#define IS_VALID_ENUM_TYPE(NAME, x) ((x > NAME ## _UNDEFINED) && (x < NAME ## _N))
-
-#endif /* UTIL_TYPES */