diff options
Diffstat (limited to 'ctrl')
80 files changed, 9284 insertions, 3530 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, ¶m); +#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, ¶m); +#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 */ diff --git a/ctrl/libhicnctrl/CMakeLists.txt b/ctrl/libhicnctrl/CMakeLists.txt index cb1bd722c..6b67544ee 100644 --- a/ctrl/libhicnctrl/CMakeLists.txt +++ b/ctrl/libhicnctrl/CMakeLists.txt @@ -26,21 +26,38 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" ) +include(BuildMacros) + set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_MACOSX_RPATH ON) if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) - set(HICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL hicn-ctrl) - set(LIBHICN_CTRL_SHARED ${LIBHICNCTRL}.shared) - set(LIBHICN_CTRL_STATIC ${LIBHICNCTRL}.static) -endif() -set(LIBHICNCTRL_COMPONENT lib${LIBHICN_CTRL}) + find_package_wrapper(Libhicn REQUIRED) + + set(HICNCTRL hicnctrl) + set(LIBHICNCTRL hicnctrl) + set(LIBHICNCTRL_SHARED ${LIBHICNCTRL}.shared) + set(LIBHICNCTRL_STATIC ${LIBHICNCTRL}.static) + +else() + if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + list(APPEND DEPENDENCIES + ${LIBHICN_STATIC} + ) + else () + set(HICN_LIBRARIES ${LIBHICN_SHARED}) + list(APPEND DEPENDENCIES + ${LIBHICN_SHARED} + ) + endif () + +endif() -set(TO_INSTALL_HEADER_FILES) +set(LIBHICNCTRL_COMPONENT lib${LIBHICNCTRL}) add_subdirectory(includes) add_subdirectory(src) diff --git a/ctrl/libhicnctrl/includes/ctrl.h b/ctrl/libhicnctrl/includes/ctrl.h index 646630968..e61b7a482 120000..100644 --- a/ctrl/libhicnctrl/includes/ctrl.h +++ b/ctrl/libhicnctrl/includes/ctrl.h @@ -1 +1,25 @@ -hicn/ctrl.h
\ No newline at end of file +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 ctrl.h + * \brief Main interface for hICN control library + */ +#ifndef HICNCTRL_H +#define HICNCTRL_H + +#include <hicn/ctrl/api.h> + +#endif /* HICNCTRL_H */ diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h index 45efb39f9..a0ee828b9 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/api.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/api.h @@ -68,42 +68,19 @@ #include <stdbool.h> #include <stdint.h> +#include <hicn/util/ip_address.h> #include "face.h" -#include "util/types.h" + +#define HICN_DEFAULT_PORT 9695 #define LIBHICNCTRL_SUCCESS 0 #define LIBHICNCTRL_FAILURE -1 #define LIBHICNCTRL_NOT_IMPLEMENTED -99 #define LIBHICNCTRL_IS_ERROR(x) (x < 0) - -/** - * This allows to selectively define convenience types to avoid any collision - * when using the library in conjunction with other frameworks including similar - * defines - */ -#ifdef _HICNTRL_NO_DEFS -#define _HICNTRL_NO_DEF_TYPES -#define _HICNTRL_NO_DEF_IPADDR -#define _HICNTRL_NO_DEF_UNIONCAST -#endif - -#ifndef _HICNTRL_NO_DEF_TYPES -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -#endif /* _HICNTRL_NO_DEF_TYPES */ - -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ - -#ifndef _HICNTRL_NO_DEF_UNIONCAST /* Helper for avoiding warnings about type-punning */ #define UNION_CAST(x, destType) \ (((union {__typeof__(x) a; destType b;})x).b) -#endif /* _HICNTRL_NO_DEF_UNIONCAST */ /****************************************************************************** * Message helper types and aliases @@ -419,27 +396,13 @@ hc_sock_reset(hc_sock_t * s); #endif #define NAME_LEN 16 /* NULL-terminated right ? */ -#ifdef __linux__ #define INTERFACE_LEN 16 -#endif #define MAXSZ_HC_NAME_ NAME_LEN #define MAXSZ_HC_NAME MAXSZ_HC_NAME_ + NULLTERM #define MAXSZ_HC_ID_ 10 /* Number of digits for MAX_INT */ #define MAXSZ_HC_ID MAXSZ_HC_ID_ + NULLTERM -#define MAXSZ_HC_PROTO_ 8 /* inetX:// */ -#define MAXSZ_HC_PROTO MAXSZ_HC_PROTO_ + NULLTERM - -#define MAXSZ_HC_URL4_ MAXSZ_HC_PROTO_ + MAXSZ_IP4_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL6_ MAXSZ_HC_PROTO_ + MAXSZ_IP6_ADDRESS_ + MAXSZ_PORT_ -#define MAXSZ_HC_URL_ MAXSZ_HC_URL6_ -#define MAXSZ_HC_URL4 MAXSZ_HC_URL4_ + NULLTERM -#define MAXSZ_HC_URL6 MAXSZ_HC_URL6_ + NULLTERM -#define MAXSZ_HC_URL MAXSZ_HC_URL_ + NULLTERM - -int hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port); #define foreach_type(TYPE, VAR, data) \ for (TYPE * VAR = (TYPE*)data->buffer; \ @@ -498,9 +461,7 @@ typedef int (*HC_PARSE)(const u8 *, u8 *); // FIXME the listener should not require any port for hICN... typedef struct { char name[NAME_LEN]; /* K.w */ // XXX clarify what used for -#ifdef __linux__ char interface_name[INTERFACE_LEN]; /* Kr. */ -#endif u32 id; hc_connection_type_t type; /* .rw */ int family; /* .rw */ @@ -509,6 +470,7 @@ typedef struct { } hc_listener_t; int hc_listener_create(hc_sock_t * s, hc_listener_t * listener); +/* listener_found might eventually be allocated, and needs to be freed */ int hc_listener_get(hc_sock_t *s, hc_listener_t * listener, hc_listener_t ** listener_found); int hc_listener_delete(hc_sock_t * s, hc_listener_t * listener); @@ -520,7 +482,7 @@ int hc_listener_parse(void * in, hc_listener_t * listener); #define foreach_listener(VAR, data) foreach_type(hc_listener_t, VAR, data) -#define MAXSZ_HC_LISTENER_ MAXSZ_HC_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ +#define MAXSZ_HC_LISTENER_ INTERFACE_LEN + SPACE + MAXSZ_URL_ + SPACE + MAXSZ_HC_CONNECTION_TYPE_ #define MAXSZ_HC_LISTENER MAXSZ_HC_LISTENER_ + NULLTERM GENERATE_FIND_HEADER(listener); @@ -531,9 +493,15 @@ int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener); * Connections *----------------------------------------------------------------------------*/ +/* + * NOTE : + * - interface_name is mainly used to derive listeners from connections, but is + * not itself used to create connections. + */ typedef struct { u32 id; /* Kr. */ char name[NAME_LEN]; /* K.w */ + char interface_name[INTERFACE_LEN]; /* Kr. */ hc_connection_type_t type; /* .rw */ int family; /* .rw */ ip_address_t local_addr; /* .rw */ @@ -549,6 +517,7 @@ typedef struct { int hc_connection_create(hc_sock_t * s, hc_connection_t * connection); +/* connection_found will be allocated, and must be freed */ int hc_connection_get(hc_sock_t *s, hc_connection_t * connection, hc_connection_t ** connection_found); int hc_connection_update_by_id(hc_sock_t * s, int hc_connection_id, @@ -567,13 +536,14 @@ int hc_connection_cmp(const hc_connection_t * c1, const hc_connection_t * c2); int hc_connection_parse(void * in, hc_connection_t * connection); #ifdef WITH_POLICY -int hc_connection_set_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); +int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, face_state_t state); #endif /* WITH_POLICY */ #define foreach_connection(VAR, data) foreach_type(hc_connection_t, VAR, data) -#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ - 2 * MAXSZ_HC_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) +#define MAXSZ_HC_CONNECTION_ MAXSZ_HC_CONNECTION_STATE_ + \ + INTERFACE_LEN + SPACE + \ + 2 * MAXSZ_URL_ + MAXSZ_HC_CONNECTION_TYPE_ + SPACES(3) #define MAXSZ_HC_CONNECTION MAXSZ_HC_CONNECTION_ + NULLTERM GENERATE_FIND_HEADER(connection); @@ -581,38 +551,6 @@ GENERATE_FIND_HEADER(connection); int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection); /*----------------------------------------------------------------------------* - * Routes - *----------------------------------------------------------------------------*/ - -typedef struct { - u8 face_id; /* Kr. */ - int family; /* Krw */ - ip_address_t remote_addr; /* krw */ - u8 len; /* krw */ - u16 cost; /* .rw */ -} hc_route_t; - -int hc_route_parse(void * in, hc_route_t * route); - -int hc_route_create(hc_sock_t * s, hc_route_t * route); -int hc_route_delete(hc_sock_t * s, hc_route_t * route); -int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); - -#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) - -#define MAX_FACE_ID 255 -#define MAXSZ_FACE_ID 3 -#define MAX_COST 65535 -#define MAXSZ_COST 5 -#define MAX_LEN 255 -#define MAXSZ_LEN 3 - -#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN -#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM - -int hc_route_snprintf(char * s, size_t size, hc_route_t * route); - -/*----------------------------------------------------------------------------* * Faces * * A face is an abstraction introduced by the control library to abstract the @@ -623,7 +561,7 @@ int hc_route_snprintf(char * s, size_t size, hc_route_t * route); *----------------------------------------------------------------------------*/ typedef struct { - u32 id; + u8 id; char name[NAME_LEN]; face_t face; // or embed ? //face_id_t parent; /* Pointer from connection to listener */ @@ -644,12 +582,47 @@ int hc_face_list(hc_sock_t * s, hc_data_t ** pdata); #define foreach_face(VAR, data) foreach_type(hc_face_t, VAR, data) -#define MAXSZ_HC_FACE_ 0 +#define MAX_FACE_ID 255 +#define MAXSZ_FACE_ID_ 3 +#define MAXSZ_FACE_ID MAXSZ_FACE_ID_ + NULLTERM +#define MAXSZ_FACE_NAME_ NAMELEN +#define MAXSZ_FACE_NAME MAXSZ_FACE_NAME_ + NULLTERM + +#define MAXSZ_HC_FACE_ MAXSZ_FACE_ID_ + MAXSZ_FACE_NAME_ + MAXSZ_FACE_ + 5 #define MAXSZ_HC_FACE MAXSZ_HC_FACE_ + NULLTERM int hc_face_snprintf(char * s, size_t size, hc_face_t * face); -/////// XXX XXX XXX XXX missing face api functions, cf punting now... +/*----------------------------------------------------------------------------* + * Routes + *----------------------------------------------------------------------------*/ + +typedef struct { + u8 face_id; /* Kr. */ + int family; /* Krw */ + ip_address_t remote_addr; /* krw */ + u8 len; /* krw */ + u16 cost; /* .rw */ +} hc_route_t; + +int hc_route_parse(void * in, hc_route_t * route); + +int hc_route_create(hc_sock_t * s, hc_route_t * route); +int hc_route_delete(hc_sock_t * s, hc_route_t * route); +int hc_route_list(hc_sock_t * s, hc_data_t ** pdata); + +#define foreach_route(VAR, data) foreach_type(hc_route_t, VAR, data) + +#define MAX_COST 65535 +#define MAXSZ_COST 5 +#define MAX_LEN 255 +#define MAXSZ_LEN 3 + +#define MAXSZ_HC_ROUTE_ MAXSZ_FACE_ID + 1 + MAXSZ_COST + 1 + MAXSZ_IP_ADDRESS + 1 + MAXSZ_LEN +#define MAXSZ_HC_ROUTE MAXSZ_HC_ROUTE_ + NULLTERM + +int hc_route_snprintf(char * s, size_t size, hc_route_t * route); + /*----------------------------------------------------------------------------* * Punting diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h index 1d07c9b72..4209c6eb6 100755 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/commands.h @@ -32,7 +32,7 @@ #include <stdlib.h> #ifdef WITH_POLICY -#include "util/policy.h" +#include <hicn/policy.h> #endif /* WITH_POLICY */ typedef struct in6_addr ipv6_addr_t; @@ -131,6 +131,7 @@ typedef struct { typedef struct { char symbolic[16]; + //char interfaceName[16]; union commandAddr remoteIp; union commandAddr localIp; uint16_t remotePort; @@ -166,9 +167,9 @@ typedef struct { add_connection_command connectionData; uint32_t connid; uint8_t state; -#ifdef WITH_UPDATE + uint8_t admin_state; char connectionName[16]; -#endif /* WITH_UPDATE */ + char interfaceName[16]; } list_connections_command; // SIZE=64 @@ -282,10 +283,8 @@ typedef struct { typedef struct { union commandAddr address; -#ifdef WITH_UPDATE char listenerName[16]; char interfaceName[16]; -#endif /* WITH_UPDATE */ uint32_t connid; uint16_t port; uint8_t addressType; @@ -310,11 +309,10 @@ typedef struct { // SIZE=1 -//========== NEW COMMANDS ========== - typedef struct { char symbolicOrConnid[16]; uint8_t admin_state; + uint8_t pad8[3]; } connection_set_admin_state_command; #ifdef WITH_POLICY diff --git a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h index 2856ce89b..5c1fecd55 100644 --- a/ctrl/libhicnctrl/includes/hicn/ctrl/face.h +++ b/ctrl/libhicnctrl/includes/hicn/ctrl/face.h @@ -30,12 +30,11 @@ #define NULLTERM 1 #endif -#ifndef _HICNTRL_NO_DEF_IPADDR -#include "util/ip_address.h" -#endif /* _HICNTRL_NO_DEF_IPADDR */ -#include "util/policy.h" -#include "util/types.h" +#include <hicn/policy.h> +#include <hicn/util/ip_address.h> + +typedef unsigned int hash_t; /* Netdevice type */ @@ -43,6 +42,7 @@ #define foreach_netdevice_type \ _(UNDEFINED) \ + _(LOOPBACK) \ _(WIRED) \ _(WIFI) \ _(CELLULAR) \ @@ -63,25 +63,48 @@ extern const char * netdevice_type_str[]; /* Netdevice */ +/** + * \brief Netdevice type + * + * NOTE + * - This struct cannot be made opaque as it is currently part of face_t + * - We recommand using the API as to keep redundant attributes consistent + */ typedef struct { u32 index; char name[IFNAMSIZ]; } netdevice_t; +#define NETDEVICE_EMPTY (netdevice_t) { \ + .index = 0, \ + .name = {0}, \ +} + +netdevice_t * netdevice_create_from_index(u32 index); +netdevice_t * netdevice_create_from_name(const char * name); +#define netdevice_initialize_from_index netdevice_set_index +#define netdevice_initialize_from_name netdevice_set_name +void netdevice_free(netdevice_t * netdevice); +int netdevice_get_index(const netdevice_t * netdevice, u32 * index); +int netdevice_set_index(netdevice_t * netdevice, u32 index); +int netdevice_get_name(const netdevice_t * netdevice, const char ** name); +int netdevice_set_name(netdevice_t * netdevice, const char * name); +int netdevice_update_index(netdevice_t * netdevice); +int netdevice_update_name(netdevice_t * netdevice); +int netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2); + #define NETDEVICE_UNDEFINED_INDEX 0 /* Face state */ #define foreach_face_state \ _(UNDEFINED) \ - _(PENDING_UP) \ - _(UP) \ - _(PENDING_DOWN) \ _(DOWN) \ - _(ERROR) \ + _(UP) \ _(N) -#define MAXSZ_FACE_STATE_ 12 + +#define MAXSZ_FACE_STATE_ 9 #define MAXSZ_FACE_STATE MAXSZ_FACE_STATE_ + 1 typedef enum { @@ -116,49 +139,49 @@ foreach_face_type extern const char * face_type_str[]; -#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_IP_ADDRESS + 2 * MAXSZ_PORT + 9 +#ifdef WITH_POLICY +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + MAXSZ_POLICY_TAGS_ + 7 +#else +#define MAXSZ_FACE_ MAXSZ_FACE_TYPE_ + 2 * MAXSZ_URL_ + 2 * MAXSZ_FACE_STATE_ + 4 +#endif /* WITH_POLICY */ #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 */ + + /* + * Depending on the face type, some of the following fields will be unused + */ + netdevice_t netdevice; + int family; /* To access family independently of face type */ + ip_address_t local_addr; + ip_address_t remote_addr; + u16 local_port; + u16 remote_port; } 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 face_initialize_udp(face_t * face, const char * interface_name, + 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 char * interface_name, 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, +face_t * face_create_udp(const char * interface_name, + 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, +face_t * face_create_udp_sa(const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr); int face_finalize(face_t * face); @@ -173,6 +196,7 @@ hash_t face_hash(const face_t * face); size_t face_snprintf(char * s, size_t size, const face_t * face); +policy_tags_t face_get_tags(const face_t * face); int face_set_tags(face_t * face, policy_tags_t tags); #endif /* HICN_FACE_H */ diff --git a/ctrl/libhicnctrl/src/CMakeLists.txt b/ctrl/libhicnctrl/src/CMakeLists.txt index 204311c39..7b4413d55 100644 --- a/ctrl/libhicnctrl/src/CMakeLists.txt +++ b/ctrl/libhicnctrl/src/CMakeLists.txt @@ -11,11 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(BuildMacros) - list(APPEND COMPILER_DEFINITIONS "-DWITH_POLICY" -# "-DWITH_UPDATE" ) set(HEADER_FILES @@ -26,34 +23,34 @@ set(HEADER_FILES set(UTIL_HEADER_FILES face.h - util/ip_address.h util/log.h - util/policy.h - util/token.h - util/types.h ) set(SOURCE_FILES api.c - util/policy.c + face.c util/log.c ) set(LIBRARIES m + ${HICN_LIBRARIES} ) set(INCLUDE_DIRS ./ ../includes/ + ${HICN_INCLUDE_DIRS} ) -if (ANDROID_API) - build_library(${LIBHICN_CTRL} +if (${CMAKE_SYSTEM_NAME} STREQUAL "Android") + set(HICN_LIBRARIES ${LIBHICN_STATIC}) + build_library(${LIBHICNCTRL} STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_STATIC} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_STATIC} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -61,11 +58,12 @@ if (ANDROID_API) DEFINITIONS ${COMPILER_DEFINITIONS} ) else () - build_library(${LIBHICN_CTRL} + build_library(${LIBHICNCTRL} SHARED STATIC SOURCES ${SOURCE_FILES} INSTALL_HEADERS ${TO_INSTALL_HEADER_FILES} LINK_LIBRARIES ${LIBRARIES} + DEPENDS ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} DEPENDS ${LIBHICN_SHARED} INCLUDE_DIRS ${INCLUDE_DIRS} @@ -74,14 +72,14 @@ else () ) 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 cli.c ) - build_executable(${HICN_CTRL} + build_executable(${HICNCTRL} SOURCES ${DAEMON_SRC} - LINK_LIBRARIES ${LIBHICN_CTRL_SHARED} - DEPENDS ${LIBHICN_CTRL_SHARED} + LINK_LIBRARIES ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} + DEPENDS ${LIBHICNCTRL_SHARED} ${LIBHICN_SHARED} COMPONENT ${LIBHICNCTRL_COMPONENT} INCLUDE_DIRS ${INCLUDE_DIRS} DEFINITIONS ${COMPILER_DEFINITIONS} diff --git a/ctrl/libhicnctrl/src/api.c b/ctrl/libhicnctrl/src/api.c index 3d8a2c166..769c96076 100644 --- a/ctrl/libhicnctrl/src/api.c +++ b/ctrl/libhicnctrl/src/api.c @@ -28,12 +28,21 @@ #include <hicn/ctrl/api.h> #include <hicn/ctrl/commands.h> +#include <hicn/util/token.h> #include "util/log.h" -#include "util/token.h" #include <strings.h> #define PORT 9695 +#if 0 +#ifdef __APPLE__ +#define RANDBYTE() (u8)(arc4random() & 0xFF) +#else +#define RANDBYTE() (u8)(random() & 0xFF) +#endif +#endif +#define RANDBYTE() (u8)(rand() & 0xFF) + /* * list was working with all seq set to 0, but it seems hicnLightControl uses * 1, and replies with the same seqno @@ -159,8 +168,8 @@ static const hc_connection_state_t map_from_list_connections_state[] = { }; -#define connection_state_to_face_state(x) ((face_state_t)x) -#define face_state_to_connection_state(x) ((hc_connection_state_t)x) +#define connection_state_to_face_state(x) ((face_state_t)(x)) +#define face_state_to_connection_state(x) ((hc_connection_state_t)(x)) #define IS_VALID_ADDR_TYPE(x) ((x >= ADDR_INET) && (x <= ADDR_UNIX)) @@ -342,6 +351,8 @@ hc_sock_parse_url(const char * url, struct sockaddr * sa) /* FIXME URL parsing is currently not implemented */ assert(!url); + srand(time(NULL)); + /* * A temporary solution is to inspect the sa_family fields of the passed in * sockaddr, which defaults to AF_UNSPEC (0) and thus creates an IPv4/TCP @@ -443,7 +454,13 @@ ERR_PARSE: int hc_sock_send(hc_sock_t * s, hc_msg_t * msg, size_t msglen) { - return send(s->fd, msg, msglen, 0); + int rc; + rc = send(s->fd, msg, msglen, 0); + if (rc < 0) { + perror("hc_sock_send"); + return -1; + } + return 0; } int @@ -473,6 +490,7 @@ hc_sock_recv(hc_sock_t * s, hc_data_t * data) // XXX } if (rc < 0) { + perror("hc_sock_recv"); /* Error occurred */ // XXX check for EWOULDBLOCK; // XXX @@ -647,7 +665,8 @@ hc_execute_command(hc_sock_t * s, hc_msg_t * msg, size_t msg_len, if (!data) goto ERR_DATA; - hc_sock_send(s, msg, msg_len); + if (hc_sock_send(s, msg, msg_len) < 0) + goto ERR_PROCESS; while(!data->complete) { if (hc_sock_recv(s, data) < 0) break; @@ -667,52 +686,6 @@ ERR_DATA: return LIBHICNCTRL_FAILURE; } -/* /!\ Please update constants in header file upon changes */ -int -hc_url_snprintf(char * s, size_t size, int family, - const ip_address_t * ip_address, u16 port) -{ - char * cur = s; - int rc; - - /* Other address are currently not supported */ - if (!IS_VALID_FAMILY(family)) { - ERROR("Invalid family %d for IP address", family); - return -1; - } - - rc = snprintf(cur, s + size - cur, "inet%c://", - (family == AF_INET) ? '4' : '6'); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - rc = ip_address_snprintf(cur, s + size - cur, ip_address, family); - 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; - - rc = snprintf(cur, s + size - cur, "%d", port); - if (rc < 0) - return rc; - cur += rc; - if (size != 0 && cur >= s + size) - return cur - s; - - return cur - s; -} - /*----------------------------------------------------------------------------* * Listeners *----------------------------------------------------------------------------*/ @@ -750,9 +723,7 @@ hc_listener_create(hc_sock_t * s, hc_listener_t * listener) }; snprintf(msg.payload.symbolic, NAME_LEN, "%s", listener->name); -#ifdef __linux__ snprintf(msg.payload.interfaceName, INTERFACE_LEN, "%s", listener->interface_name); -#endif hc_command_params_t params = { .cmd = ACTION_CREATE, @@ -772,13 +743,25 @@ hc_listener_get(hc_sock_t *s, hc_listener_t * listener, hc_listener_t ** listener_found) { hc_data_t * listeners; + hc_listener_t * found; if (hc_listener_list(s, &listeners) < 0) return LIBHICNCTRL_FAILURE; /* Test */ - if (hc_listener_find(listeners, listener, listener_found) < 0) + if (hc_listener_find(listeners, listener, &found) < 0) { + hc_data_free(listeners); return LIBHICNCTRL_FAILURE; + } + + if (found) { + *listener_found = malloc(sizeof(hc_listener_t)); + if (!*listener_found) + return LIBHICNCTRL_FAILURE; + **listener_found = *found; + } else { + *listener_found = NULL; + } hc_data_free(listeners); @@ -818,6 +801,7 @@ hc_listener_delete(hc_sock_t * s, hc_listener_t * listener) return LIBHICNCTRL_FAILURE; printf("Delete listener ID=%d\n", listener_found->id); snprintf(msg.payload.symbolicOrListenerid, NAME_LEN, "%d", listener_found->id); + free(listener_found); } hc_command_params_t params = { @@ -879,6 +863,7 @@ hc_listener_cmp(const hc_listener_t * l1, const hc_listener_t * l2) { return ((l1->type == l2->type) && (l1->family == l2->family) && + (strncmp(l1->interface_name, l2->interface_name, INTERFACE_LEN) == 0) && (ip_address_cmp(&l1->local_addr, &l2->local_addr, l1->family) == 0) && (l1->local_port == l2->local_port)) ? LIBHICNCTRL_SUCCESS @@ -913,7 +898,8 @@ hc_listener_parse(void * in, hc_listener_t * listener) .local_addr = UNION_CAST(cmd->address, ip_address_t), .local_port = ntohs(cmd->port), }; - memset(listener->name, 0, NAME_LEN); + snprintf(listener->name, NAME_LEN, "%s", cmd->listenerName); + snprintf(listener->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); return LIBHICNCTRL_SUCCESS; } @@ -925,14 +911,15 @@ GENERATE_FIND(listener) int hc_listener_snprintf(char * s, size_t size, hc_listener_t * listener) { - char local[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; int rc; - rc = hc_url_snprintf(local, MAXSZ_HC_URL, + rc = url_snprintf(local, MAXSZ_URL, listener->family, &listener->local_addr, listener->local_port); if (rc < 0) return rc; - return snprintf(s, size+17, "%s %s", + return snprintf(s, size+17, "%s %s %s", + listener->interface_name, local, connection_type_str[listener->type]); } @@ -993,13 +980,25 @@ hc_connection_get(hc_sock_t *s, hc_connection_t * connection, hc_connection_t ** connection_found) { hc_data_t * connections; + hc_connection_t * found; if (hc_connection_list(s, &connections) < 0) return LIBHICNCTRL_FAILURE; /* Test */ - if (hc_connection_find(connections, connection, connection_found) < 0) + if (hc_connection_find(connections, connection, &found) < 0) { + hc_data_free(connections); return LIBHICNCTRL_FAILURE; + } + + if (found) { + *connection_found = malloc(sizeof(hc_connection_t)); + if (!*connection_found) + return LIBHICNCTRL_FAILURE; + **connection_found = *found; + } else { + *connection_found = NULL; + } hc_data_free(connections); @@ -1039,6 +1038,7 @@ hc_connection_delete(hc_sock_t * s, hc_connection_t * connection) return LIBHICNCTRL_FAILURE; printf("Delete connection ID=%d\n", connection_found->id); snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%d", connection_found->id); + free(connection_found); } hc_command_params_t params = { @@ -1158,6 +1158,7 @@ hc_connection_parse(void * in, hc_connection_t * connection) .state = state, }; snprintf(connection->name, NAME_LEN, "%s", cmd->connectionData.symbolic); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", cmd->interfaceName); return LIBHICNCTRL_SUCCESS; } @@ -1169,23 +1170,24 @@ GENERATE_FIND(connection) int hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection) { - char local[MAXSZ_HC_URL]; - char remote[MAXSZ_HC_URL]; + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; int rc; // assert(connection->connection_state) - rc = hc_url_snprintf(local, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(local, MAXSZ_URL, connection->family, &connection->local_addr, connection->local_port); if (rc < 0) return rc; - rc = hc_url_snprintf(remote, MAXSZ_HC_URL, connection->family, + rc = url_snprintf(remote, MAXSZ_URL, connection->family, &connection->remote_addr, connection->remote_port); if (rc < 0) return rc; - return snprintf(s, size, "%s %s %s %s", + return snprintf(s, size, "%s %s %s %s %s", connection_state_str[connection->state], + connection->interface_name, local, remote, connection_type_str[connection->type]); @@ -1195,7 +1197,7 @@ hc_connection_snprintf(char * s, size_t size, const hc_connection_t * connection int hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, - hc_connection_state_t admin_state) + face_state_t state) { struct { header_control_message hdr; @@ -1208,7 +1210,7 @@ hc_connection_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, .seqNum = s->send_seq, }, .payload = { - .admin_state = admin_state, + .admin_state = state, }, }; snprintf(msg.payload.symbolicOrConnid, NAME_LEN, "%s", conn_id_or_name); @@ -1436,13 +1438,12 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool switch(f->type) { case FACE_TYPE_HICN: - /* FIXME truncations, collisions, ... */ *connection = (hc_connection_t) { .type = CONNECTION_TYPE_HICN, - .family = f->params.hicn.family, - .local_addr = f->params.hicn.local_addr, + .family = f->family, + .local_addr = f->local_addr, .local_port = 0, - .remote_addr = f->params.hicn.remote_addr, + .remote_addr = f->remote_addr, .remote_port = 0, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), @@ -1451,16 +1452,18 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; snprintf(connection->name, NAME_LEN, "%s", - f->params.hicn.netdevice.name); + f->netdevice.name); + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; case FACE_TYPE_TCP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_TCP, - .family = f->params.hicn.family, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .family = f->family, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1468,23 +1471,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "tcp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "tcp%ld", random() & 0xFF); -#endif + snprintf(connection->name, NAME_LEN, "tcp%u", RANDBYTE()); } else { memset(connection->name, 0, NAME_LEN); } + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; case FACE_TYPE_UDP: *connection = (hc_connection_t) { .type = CONNECTION_TYPE_UDP, .family = AF_INET, - .local_addr = f->params.tunnel.local_addr, - .local_port = f->params.tunnel.local_port, - .remote_addr = f->params.tunnel.remote_addr, - .remote_port = f->params.tunnel.remote_port, + .local_addr = f->local_addr, + .local_port = f->local_port, + .remote_addr = f->remote_addr, + .remote_port = f->remote_port, .admin_state = face_state_to_connection_state(f->admin_state), .state = face_state_to_connection_state(f->state), #ifdef WITH_POLICY @@ -1492,20 +1493,21 @@ hc_face_to_connection(const hc_face_t * face, hc_connection_t * connection, bool #endif /* WITH_POLICY */ }; if (generate_name) { -#ifdef __APPLE__ - snprintf(connection->name, NAME_LEN, "udp%d", arc4random() & 0xFF); -#else - snprintf(connection->name, NAME_LEN, "udp%ld", random() & 0xFF); -#endif + snprintf(connection->name, NAME_LEN, "udp%u", RANDBYTE()); } else { memset(connection->name, 0, NAME_LEN); } + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); break; default: return LIBHICNCTRL_FAILURE; } - return LIBHICNCTRL_SUCCESS; + snprintf(connection->interface_name, INTERFACE_LEN, "%s", + f->netdevice.name); + + return LIBHICNCTRL_SUCCESS; } /* CONNECTION -> FACE */ @@ -1519,13 +1521,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_TCP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1539,13 +1539,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_UDP, - .params.tunnel = { - .family = connection->family, - .local_addr = connection->local_addr, - .local_port = connection->local_port, - .remote_addr = connection->remote_addr, - .remote_port = connection->remote_port, - }, + .family = connection->family, + .local_addr = connection->local_addr, + .local_port = connection->local_port, + .remote_addr = connection->remote_addr, + .remote_port = connection->remote_port, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1559,12 +1557,10 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) .id = connection->id, .face = { .type = FACE_TYPE_HICN, - .params.hicn = { - .family = connection->family, - .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX - .local_addr = connection->local_addr, - .remote_addr = connection->remote_addr, - }, + .family = connection->family, + .netdevice.index = NETDEVICE_UNDEFINED_INDEX, // XXX + .local_addr = connection->local_addr, + .remote_addr = connection->remote_addr, .admin_state = connection_state_to_face_state(connection->admin_state), .state = connection_state_to_face_state(connection->state), #ifdef WITH_POLICY @@ -1576,7 +1572,11 @@ hc_connection_to_face(const hc_connection_t * connection, hc_face_t * face) default: return LIBHICNCTRL_FAILURE; } + face->face.netdevice.name[0] = '\0'; + face->face.netdevice.index = 0; snprintf(face->name, NAME_LEN, "%s", connection->name); + snprintf(face->face.netdevice.name, INTERFACE_LEN, "%s", connection->interface_name); + netdevice_update_index(&face->face.netdevice); return LIBHICNCTRL_SUCCESS; } @@ -1592,6 +1592,8 @@ hc_connection_to_local_listener(const hc_connection_t * connection, hc_listener_ .local_addr = connection->local_addr, .local_port = connection->local_port, }; + snprintf(listener->name, NAME_LEN, "lst%u", RANDBYTE()); // generate name + snprintf(listener->interface_name, INTERFACE_LEN, "%s", connection->interface_name); return LIBHICNCTRL_SUCCESS; } @@ -1631,8 +1633,11 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) /* We need to create the listener if it does not exist */ if (hc_listener_create(s, &listener) < 0) { ERROR("[hc_face_create] Could not create listener."); + free(listener_found); return LIBHICNCTRL_FAILURE; } + } else { + free(listener_found); } /* Create corresponding connection */ @@ -1656,6 +1661,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) } face->id = connection_found->id; + free(connection_found); break; @@ -1674,6 +1680,7 @@ hc_face_create(hc_sock_t * s, hc_face_t * face) break; default: ERROR("[hc_face_create] Unknwon face type."); + return LIBHICNCTRL_FAILURE; }; @@ -1702,7 +1709,9 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) *face_found = NULL; return LIBHICNCTRL_SUCCESS; } + *face_found = malloc(sizeof(face_t)); hc_connection_to_face(connection_found, *face_found); + free(connection_found); break; case FACE_TYPE_HICN_LISTENER: @@ -1716,7 +1725,9 @@ hc_face_get(hc_sock_t * s, hc_face_t * face, hc_face_t ** face_found) *face_found = NULL; return LIBHICNCTRL_SUCCESS; } + *face_found = malloc(sizeof(face_t)); hc_listener_to_face(listener_found, *face_found); + free(listener_found); break; default: @@ -1776,6 +1787,71 @@ ERR: int hc_face_snprintf(char * s, size_t size, hc_face_t * face) { + /* URLs are also big enough to contain IP addresses in the hICN case */ + char local[MAXSZ_URL]; + char remote[MAXSZ_URL]; +#ifdef WITH_POLICY + char tags[MAXSZ_POLICY_TAGS]; +#endif /* WITH_POLICY */ + int rc; + + switch(face->face.type) { + case FACE_TYPE_HICN: + case FACE_TYPE_HICN_LISTENER: + rc = ip_address_snprintf(local, MAXSZ_URL, + &face->face.local_addr, + face->face.family); + if (rc < 0) + return rc; + rc = ip_address_snprintf(remote, MAXSZ_URL, + &face->face.remote_addr, + face->face.family); + if (rc < 0) + return rc; + break; + case FACE_TYPE_TCP: + case FACE_TYPE_UDP: + case FACE_TYPE_TCP_LISTENER: + case FACE_TYPE_UDP_LISTENER: + rc = url_snprintf(local, MAXSZ_URL, face->face.family, + &face->face.local_addr, + face->face.local_port); if (rc < 0) + return rc; + rc = url_snprintf(remote, MAXSZ_URL, face->face.family, + &face->face.remote_addr, + face->face.remote_port); if (rc < 0) + if (rc < 0) + return rc; + break; + default: + return LIBHICNCTRL_FAILURE; + } + + // [#ID NAME] TYPE LOCAL_URL REMOTE_URL STATE/ADMIN_STATE (TAGS) +#ifdef WITH_POLICY + rc = policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->face.tags); + if (rc < 0) + return rc; + + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s (%s)", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state], + tags); +#else + return snprintf(s, size, "[#%d %s] %s %s %s %s/%s", + face->id, + face->name, + face_type_str[face->face.type], + local, + remote, + face_state_str[face->face.state], + face_state_str[face->face.admin_state]); +#endif /* WITH_POLICY */ return LIBHICNCTRL_SUCCESS; } @@ -1783,7 +1859,7 @@ int hc_face_set_admin_state(hc_sock_t * s, const char * conn_id_or_name, // XXX wrong identifier face_state_t admin_state) { - return hc_connection_set_admin_state(s, conn_id_or_name, (hc_connection_state_t)admin_state); + return hc_connection_set_admin_state(s, conn_id_or_name, admin_state); } /*----------------------------------------------------------------------------* diff --git a/ctrl/libhicnctrl/src/cli.c b/ctrl/libhicnctrl/src/cli.c index 70620a84f..6798b5aec 100644 --- a/ctrl/libhicnctrl/src/cli.c +++ b/ctrl/libhicnctrl/src/cli.c @@ -22,9 +22,8 @@ #include <unistd.h> // getopt #include <hicn/ctrl.h> - -#include "util/ip_address.h" -#include "util/token.h" +#include <hicn/util/ip_address.h> +#include <hicn/util/token.h> #define die(LABEL, MESSAGE) do { \ diff --git a/ctrl/libhicnctrl/src/face.c b/ctrl/libhicnctrl/src/face.c index 9e0fbb597..41ff58f81 100644 --- a/ctrl/libhicnctrl/src/face.c +++ b/ctrl/libhicnctrl/src/face.c @@ -21,10 +21,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <hicn/util/token.h> -#include "face.h" +#include <hicn/ctrl/face.h> #include "util/hash.h" -#include "util/token.h" #define member_size(type, member) sizeof(((type *)0)->member) @@ -37,6 +37,112 @@ foreach_netdevice_type #undef _ }; +netdevice_t * +netdevice_create_from_index(u32 index) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_index(netdevice, index); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +netdevice_t * +netdevice_create_from_name(const char * name) +{ + netdevice_t * netdevice = malloc(sizeof(netdevice_t)); + if (!netdevice) + goto ERR_MALLOC; + + int rc = netdevice_set_name(netdevice, name); + if (rc < 0) + goto ERR_INIT; + + return netdevice; + +ERR_INIT: + free(netdevice); +ERR_MALLOC: + return NULL; +} + +/** + * \brief Update the index of the netdevice based on the name + */ +int +netdevice_update_index(netdevice_t * netdevice) +{ + netdevice->index = if_nametoindex(netdevice->name); + if (netdevice->index == 0) + return -1; + return 0; +} + +int +netdevice_update_name(netdevice_t * netdevice) +{ + if (!if_indextoname(netdevice->index, netdevice->name)) + return -1; + return 0; +} + +void +netdevice_free(netdevice_t * netdevice) +{ + free(netdevice); +} + +int +netdevice_get_index(const netdevice_t * netdevice, u32 * index) +{ + if (netdevice->index == 0) + return -1; + *index = netdevice->index; + return 0; +} + +int +netdevice_set_index(netdevice_t * netdevice, u32 index) +{ + netdevice->index = index; + return netdevice_update_name(netdevice); +} + +int +netdevice_get_name(const netdevice_t * netdevice, const char ** name) +{ + if (netdevice->name[0] == '\0') + return -1; + *name = netdevice->name; + return 0; +} + +int +netdevice_set_name(netdevice_t * netdevice, const char * name) +{ + int rc = snprintf(netdevice->name, IFNAMSIZ, "%s", name); + if (rc < 0) + return -1; + if (rc >= IFNAMSIZ) + return -2; /* truncated */ + return netdevice_update_index(netdevice); +} + +int +netdevice_cmp(const netdevice_t * nd1, const netdevice_t * nd2) +{ + return (nd1->index - nd2->index); +} + /* Face state */ @@ -61,33 +167,42 @@ foreach_face_type int face_initialize(face_t * face) { - bzero(face, sizeof(face_t)); /* 0'ed for hash */ + memset(face, 0, 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, +face_initialize_udp(face_t * face, const char * interface_name, 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_port = remote_port, - }, + .family = family, + .local_addr = *local_addr, + .local_port = local_port, + .remote_addr = remote_addr ? *remote_addr : IP_ADDRESS_EMPTY, + .remote_port = remote_port, }; + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } int -face_initialize_udp_sa(face_t * face, const struct sockaddr * local_addr, +face_initialize_udp_sa(face_t * face, const char * interface_name, + const struct sockaddr * local_addr, const struct sockaddr * remote_addr) { - if (local_addr->sa_family != remote_addr->sa_family) + if (!local_addr) + return -1; + + if (remote_addr && (local_addr->sa_family != remote_addr->sa_family)) return -1; switch (local_addr->sa_family) { @@ -97,14 +212,14 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * 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 = ntohs(lsai->sin_port), - .remote_addr.v4.as_inaddr = rsai->sin_addr, - .remote_port = ntohs(rsai->sin_port), - }, + .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->remote_addr.v4.as_inaddr = rsai->sin_addr; } break; case AF_INET6: @@ -113,19 +228,22 @@ face_initialize_udp_sa(face_t * face, const struct sockaddr * 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 = ntohs(lsai->sin6_port), - .remote_addr.v6.as_in6addr = rsai->sin6_addr, - .remote_port = ntohs(rsai->sin6_port), - }, + .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->remote_addr.v6.as_in6addr = rsai->sin6_addr; } break; default: return -1; } + + snprintf(face->netdevice.name, IFNAMSIZ, "%s", interface_name); + return 1; } @@ -135,11 +253,12 @@ face_t * face_create() return face; } -face_t * face_create_udp(const ip_address_t * local_addr, u16 local_port, +face_t * face_create_udp(const char * interface_name, + 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) + if (face_initialize_udp(face, interface_name, local_addr, local_port, remote_addr, remote_port, family) < 0) goto ERR_INIT; return face; @@ -148,11 +267,12 @@ ERR_INIT: return NULL; } -face_t * face_create_udp_sa(const struct sockaddr * local_addr, +face_t * face_create_udp_sa(const char * interface_name, + 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) + if (face_initialize_udp_sa(face, interface_name, local_addr, remote_addr) < 0) goto ERR_INIT; return face; @@ -166,10 +286,6 @@ 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 @@ -182,18 +298,61 @@ void face_free(face_t * face) int face_cmp(const face_t * f1, const face_t * f2) { - if (f1->type != f2->type) - return false; + + int ret = f1->type - f2->type; + if (ret != 0) + return ret; + + ret = f1->family - f2->family; + if (ret != 0) + return ret; + + /* + * FIXME As hicn-light API might not return the netdevice, we can discard the + * comparison when one of the two is not set for now... + */ + if ((f1->netdevice.index != 0) && (f2->netdevice.index != 0)) { + ret = netdevice_cmp(&f1->netdevice, &f2->netdevice); + if (ret != 0) + return ret; + } switch(f1->type) { case FACE_TYPE_HICN: - return face_param_cmp(f1, f2, hicn); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + break; + case FACE_TYPE_TCP: case FACE_TYPE_UDP: - return face_param_cmp(f1, f2, tunnel); + ret = ip_address_cmp(&f1->local_addr, &f2->local_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->local_port - f2->local_port; + if (ret != 0) + return ret; + + ret = ip_address_cmp(&f1->remote_addr, &f2->remote_addr, f1->family); + if (ret != 0) + return ret; + + ret = f1->remote_port - f2->remote_port; + if (ret != 0) + return ret; + + break; default: - return false; + break; } + + return 0; } hash_t @@ -209,34 +368,59 @@ face_snprintf(char * s, size_t size, const face_t * face) { switch(face->type) { case FACE_TYPE_HICN: - return 0; // XXX Not implemented + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->family); + policy_tags_snprintf(tags, MAXSZ_POLICY_TAGS, face->tags); + return snprintf(s, size, "%s [%s -> %s] [%s]", + face_type_str[face->type], + local, + remote, + tags); + } + case FACE_TYPE_UNDEFINED: case FACE_TYPE_TCP: case FACE_TYPE_UDP: - { - char local[MAXSZ_IP_ADDRESS]; - char remote[MAXSZ_IP_ADDRESS]; - - 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); - - return snprintf(s, size, "%s [%s:%d -> %s:%d]", - face_type_str[face->type], - local, - face->params.tunnel.local_port, - remote, - face->params.tunnel.remote_port); - } - break; + { + char local[MAXSZ_IP_ADDRESS]; + char remote[MAXSZ_IP_ADDRESS]; + char tags[MAXSZ_POLICY_TAGS]; + + ip_address_snprintf(local, MAXSZ_IP_ADDRESS, + &face->local_addr, + face->family); + ip_address_snprintf(remote, MAXSZ_IP_ADDRESS, + &face->remote_addr, + face->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->local_port, + remote, + face->remote_port, + tags); + } default: - return 0; + return -1; } } +policy_tags_t face_get_tags(const face_t * face) +{ + return face->tags; +} + int face_set_tags(face_t * face, policy_tags_t tags) { diff --git a/ctrl/libhicnctrl/src/util/ip_address.h b/ctrl/libhicnctrl/src/util/ip_address.h deleted file mode 100644 index 472cceeea..000000000 --- a/ctrl/libhicnctrl/src/util/ip_address.h +++ /dev/null @@ -1,316 +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 -#ifdef __ANDROID__ -#include <byteswap.h> -#endif -#include <endian.h> -#endif -#include <errno.h> -#include <netdb.h> // struct addrinfo -#include <netinet/in.h> // INET*_ADDRSTRLEN, IN*ADDR_LOOPBACK -#include <stdlib.h> -#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 - -#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)); -} - -/* 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/libhicnctrl/src/util/policy.c b/ctrl/libhicnctrl/src/util/policy.c deleted file mode 100644 index 90dbc72cd..000000000 --- a/ctrl/libhicnctrl/src/util/policy.c +++ /dev/null @@ -1,53 +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) [POLICY_TAG_ ## x] = STRINGIZE(x), - 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/libhicnctrl/src/util/policy.h b/ctrl/libhicnctrl/src/util/policy.h deleted file mode 100644 index 231e53f73..000000000 --- a/ctrl/libhicnctrl/src/util/policy.h +++ /dev/null @@ -1,266 +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 "token.h" - -/* POLICY TAG */ - -#define foreach_policy_tag \ - /* Interface type */ \ - _(WIRED) \ - _(WIFI) \ - _(CELLULAR) \ - /* QoS */ \ - _(BEST_EFFORT) \ - _(REALTIME) \ - _(MULTIPATH) \ - /* Security */ \ - _(TRUSTED) - -typedef enum { -#define _(x) 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[]; - - -/* 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 - - -/* 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) [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; - -/* DEFAULT POLICY */ - -static const policy_description_t default_policy[] = { - { - .family = AF_INET6, - .ipv6_prefix = "a001::/16", - .policy = { - .app_name = "Webex", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_AVOID, 1 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 1 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_REQUIRE, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "b001::/16", - .policy = { - .app_name = "Video Streaming", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PREFER, 0 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, - { - .family = AF_INET6, - .ipv6_prefix = "c001::/16", - .policy = { - .app_name = "*", - .tags = { - [POLICY_TAG_WIRED] = { POLICY_STATE_PREFER, 0 }, - [POLICY_TAG_WIFI] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_CELLULAR] = { POLICY_STATE_NEUTRAL, 0 }, - [POLICY_TAG_BEST_EFFORT] = { POLICY_STATE_PROHIBIT, 0 }, - [POLICY_TAG_REALTIME] = { POLICY_STATE_REQUIRE, 0 }, - [POLICY_TAG_MULTIPATH] = { POLICY_STATE_AVOID, 0 }, - [POLICY_TAG_TRUSTED] = { POLICY_STATE_PROHIBIT, 1 }, - }, - .stats = POLICY_STATS_NONE, - }, - }, -}; - -#endif /* HICN_POLICY_H */ diff --git a/ctrl/libhicnctrl/src/util/token.h b/ctrl/libhicnctrl/src/util/token.h deleted file mode 100644 index 43e0a77b2..000000000 --- a/ctrl/libhicnctrl/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/libhicnctrl/src/util/types.h b/ctrl/libhicnctrl/src/util/types.h deleted file mode 100644 index 10a0bdca0..000000000 --- a/ctrl/libhicnctrl/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 */ diff --git a/ctrl/sysrepo-plugins/README.md b/ctrl/sysrepo-plugins/README.md index 3f0ed2e34..0940fff67 100644 --- a/ctrl/sysrepo-plugins/README.md +++ b/ctrl/sysrepo-plugins/README.md @@ -1,6 +1,8 @@ # Sysrepo plugin for hicn-plugin (2019) -These plugins serve as a data management agent. They provide yang models via NETCONF to allow the management of hicn-light, and hicn-plugin which runs in VPP instance from out-of-box. +These plugins serve as a data management agent. They provide yang models via +NETCONF to allow the management of hicn-light, and hicn-plugin which runs in VPP +instance from out-of-box. ## Software Requirement @@ -15,7 +17,7 @@ These plugins serve as a data management agent. They provide yang models via NET ## hICN yang model You can install the yang model using the following bash script: - +``` EXIT_CODE=0 command -v sysrepoctl > /dev/null if [ $? != 0 ]; then @@ -24,53 +26,21 @@ if [ $? != 0 ]; then else sysrepoctl --install --yang=path_to_hicn_yang_model fi - -hicn.yang can be found in the yang-model. It consists of two container nodes: hicn-conf and hicn-state. One is used to hold the configuration data (i.e., hicn-conf) and one for providing the state data (i.e., hicn-state). The hicn-conf has one node, params, which contains the hICN configuration parameters. Controler can configure these parameters through the edit-config RPC call. This node can be used to enable and to initialize the hicn-plugin in VPP instance. Hicn-state container is used to provide the state data to the controler. It consists of state, strategy, strategies, route, and face-ip-params nodes with the coresponding leaves. In hicn model variety of RPCs are provided to allow controler to communicate with hicn-plugin as well as update the state data in hicn-state. Here you can find the schematic view of the described hicn model: - - -module: hicn - +--rw hicn-conf - | +--rw params - | +--rw enable_disable? boolean - | +--rw pit_max_size? int32 - | +--rw cs_max_size? int32 - | +--rw cs_reserved_app? int32 - | +--rw pit_dflt_lifetime_sec? float - | +--rw pit_max_lifetime_sec? float - | +--rw pit_min_lifetime_sec? float - +--ro hicn-state - +--ro states - | +--ro pkts_processed? uint64 - | +--ro pkts_interest_count? uint64 - | +--ro pkts_data_count? uint64 - | +--ro pkts_from_cache_count? uint64 - | +--ro pkts_no_pit_count? uint64 - | +--ro pit_expired_count? uint64 - | +--ro cs_expired_count? uint64 - | +--ro cs_lru_count? uint64 - | +--ro pkts_drop_no_buf? uint64 - | +--ro interests_aggregated? uint64 - | +--ro interests_retx? uint64 - | +--ro interests_hash_collision? uint64 - | +--ro pit_entries_count? uint64 - | +--ro cs_entries_count? uint64 - | +--ro cs_entries_ntw_count? uint64 - +--ro strategy - | +--ro description? uint8 - +--ro route - | +--ro faceids? uint16 - | +--ro strategy_id? uint32 - +--ro strategies - | +--ro n_strategies? uint8 - | +--ro strategy_id? uint32 - +--ro face-ip-params - +--ro nh_addr? uint64 - +--ro swif? uint32 - +--ro flags? uint32 - +``` +hicn.yang can be found in the yang-model. It consists of two container nodes: +hicn-conf and hicn-state. One is used to hold the configuration data (i.e., +hicn-conf) and one for providing the state data (i.e., hicn-state). The +hicn-conf has one node, params, which contains the hICN configuration +parameters. A controller can configure these parameters through the edit-config RPC +call. This node can be used to enable and to initialize the hicn-plugin in VPP +instance. Hicn-state container is used to provide the state data to the +controller. It consists of state, strategy, strategies, route, and face-ip-params +nodes with the corresponding leaves. In the hicn model a variety of RPCs are provided +to allow controller to communicate with the hicn-plugin as well as update the state +data in hicn-state. To setup the startup configuration you can use the following script: - +``` EXIT_CODE=0 command -v sysrepocfg > /dev/null if [ $? != 0 ]; then @@ -79,10 +49,10 @@ if [ $? != 0 ]; then else sysrepocfg -d startup -i path_to_startup_xml -f xml hicn fi - +``` startup.xml is placed in the yang-model. Here you can find the content: - +``` <hicn-conf xmlns="urn:sysrepo:hicn"> <params> <enable_disable>false</enable_disable> @@ -94,81 +64,17 @@ startup.xml is placed in the yang-model. Here you can find the content: <pit_min_lifetime_sec>-1</pit_min_lifetime_sec> </params> </hicn-conf> - -As can be seen, it contains the leaves of the params in hicn-conf node which is used as the startup configuration. This configuration can be changed through the controler by subscribing which changes the target to the running state. hicn yang model provides a list of RPCs which allows controler to communicate directly with the hicn-plugin. This RPCs may also cause the modification in state data. Here you can find the list of RPCs: - - rpcs: - +---x node-params-set - | +---w input - | +---w enable_disable? boolean - | +---w pit_max_size? int32 - | +---w cs_max_size? int32 - | +---w cs_reserved_app? int32 - | +---w pit_dflt_lifetime_sec? float - | +---w pit_max_lifetime_sec? float - | +---w pit_min_lifetime_sec? float - +---x node-params-get - +---x node-stat-get - +---x strategy-get - | +---w input - | +---w strategy_id? uint32 - +---x strategies-get - +---x route-get - | +---w input - | +---w prefix0? uint64 - | +---w prefix1? uint64 - | +---w len? uint8 - +---x route-del - | +---w input - | +---w prefix0? uint64 - | +---w prefix1? uint64 - | +---w len? uint8 - +---x route-nhops-add - | +---w input - | +---w prefix0? uint64 - | +---w prefix1? uint64 - | +---w len? uint8 - | +---w face_ids0? uint32 - | +---w face_ids1? uint32 - | +---w face_ids2? uint32 - | +---w face_ids3? uint32 - | +---w face_ids4? uint32 - | +---w face_ids5? uint32 - | +---w face_ids6? uint32 - | +---w n_faces? uint8 - +---x route-nhops-del - | +---w input - | +---w prefix0? uint64 - | +---w prefix1? uint64 - | +---w len? uint8 - | +---w faceid? uint16 - +---x face-ip-params-get - | +---w input - | +---w faceid? uint16 - +---x face-ip-add - | +---w input - | +---w nh_addr0? uint64 - | +---w nh_addr1? uint64 - | +---w swif? uint32 - +---x face-ip-del - | +---w input - | +---w faceid? uint16 - +---x punting-add - | +---w input - | +---w prefix0? uint64 - | +---w prefix1? uint64 - | +---w len? uint8 - | +---w swif? uint32 - +---x punting-del - +---w input - +---w prefix0? uint64 - +---w prefix1? uint64 - +---w len? uint8 - +---w swif? uint32 - - -In order to run different RPCs from controler you can use the examples in the controler_rpcs_instances.xml in the yang-model. Here you can find the content: - +``` +As can be seen, it contains the leaves of the params in hicn-conf node which is +used as the startup configuration. This configuration can be changed through the +controller by subscribing which changes the target to the running state. hicn +yang model provides a list of RPCs which allows controller to communicate +directly with the hicn-plugin. This RPCs may also cause the modification in +state data. + +In order to run different RPCs from controller you can use the examples in the +controler_rpcs_instances.xml in the yang-model. Here you can find the content: +``` <node-params-get xmlns="urn:sysrepo:hicn"/> <node-stat-get xmlns="urn:sysrepo:hicn"/> @@ -179,7 +85,6 @@ In order to run different RPCs from controler you can use the examples in the co <strategies-get xmlns="urn:sysrepo:hicn"/> - <route-get xmlns="urn:sysrepo:hicn"> <prefix0>10</prefix0> <prefix1>20</prefix1> @@ -213,7 +118,6 @@ In order to run different RPCs from controler you can use the examples in the co <faceid>40</faceid> </route-nhops-del> - <face-ip-params-get xmlns="urn:sysrepo:hicn"> <faceid>10</faceid> </face-ip-params-get> @@ -235,27 +139,33 @@ In order to run different RPCs from controler you can use the examples in the co <swif>40</swif> </punting-add> - <punting-del xmlns="urn:sysrepo:hicn"> <prefix0>10</prefix0> <prefix1>20</prefix1> <len>30</len> <swif>40</swif> </punting-del> - +``` ## Run the plugin -Firstly, verify the plugin and binary libraries are located correctly, then run the vpp through (service vpp start). Next, run the sysrepo daemon (sysrepod), for debug mode: sysrepo -d -l 4 which runs with high verbosity. Then, run the sysrepo plugin (sysrepo-plugind), for debug mode: sysrep-plugind -d -l 4 which runs with high verbosity. Now, the hicn sysrepo plugin is loaded. Then, run the netopeer2-server which serves as NETCONF server. +Firstly, verify the plugin and binary libraries are located correctly, then run +the vpp through (service vpp start). Next, run the sysrepo daemon (sysrepod), +for debug mode: sysrepo -d -l 4 which runs with high verbosity. Then, run the +sysrepo plugin (sysrepo-plugind), for debug mode: sysrep-plugind -d -l 4 which +runs with high verbosity. Now, the hicn sysrepo plugin is loaded. Then, run the +netopeer2-server which serves as NETCONF server. ## Connect from netopeer2-cli In order to connect through the netopeer client run the netopeer2-cli. Then, follow these steps: -connect --host XXX --login XXX ---> get (you can get the configuration and operational data) ---> get-config (you can get the configuratoin data) ---> edit-config --target running --config (you can modify the configuration but it needs an xml configuration input. For example, +- connect --host XXX --login XXX +- get (you can get the configuration and operational data) +- get-config (you can get the configuration data) +- edit-config --target running --config + you can modify the configuration but it needs an xml configuration input +``` <hicn-conf xmlns="urn:sysrepo:hicn"> <params> <enable_disable>false</enable_disable> @@ -267,15 +177,16 @@ connect --host XXX --login XXX <pit_min_lifetime_sec>-1</pit_min_lifetime_sec> </params> </hicn-conf> -) ---> user-rpc (you can call one of the rpc proposed by hicn model but it needs an xml input, you can pick one in controler_rpcs_instances.xml) +``` +- user-rpc (you can call one of the rpc proposed by hicn model but it needs an xml input) -## Connect from OpenDayligh (ODL) controller +## Connect from OpenDaylight (ODL) controller -In order to connect througt the OpenDaylight follow these procedure: +In order to connect through the OpenDaylight follow these procedure: - run karaf distribution (./opendayligh_installation_folder/bin/karaf) -- install the required feature list in DOL (feature:install odl-netconf-server odl-netconf-connector odl-restconf-all odl-netconf-topology or +- install the required feature list in DOL (feature:install odl-netconf-server + odl-netconf-connector odl-restconf-all odl-netconf-topology or odl-netconf-clustered-topology) - run a rest client program (e.g., postman or RESTClient) - mount the remote netopeer2-server to the OpenDaylight by the following REST API: @@ -283,7 +194,7 @@ In order to connect througt the OpenDaylight follow these procedure: PUT http://localhost:8181/restconf/config/network-topology:network-topology/topology/topology-netconf/node/hicn-node with the following body - +``` <node xmlns="urn:TBD:params:xml:ns:yang:network-topology"> <node-id>hicn-node</node-id> <host xmlns="urn:opendaylight:netconf-node-topology">Remote_NETCONF_SERVER_IP</host> @@ -293,8 +204,8 @@ with the following body <tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only> <keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">1</keepalive-delay> </node> - -Note that the header files must be set to Content-Type: application/xml, Accept: application/xml. There are more options which can be set but for simplicity we keep a short configuration to mount the remote node. +``` +Note that the header files must be set to Content-Type: application/xml, Accept: application/xml. - send the operation through the following REST API: @@ -304,7 +215,9 @@ The body can be used the same as edit-config in netopeer2-cli. ## Connect from Network Services Orchestrator (NSO) -To connect NSO to the netopeer2-server, first, you need to write a NED package for your device. The procudeure to create NED for hicn is explaned in the following: +To connect NSO to the netopeer2-server, first, you need to write a NED package +for your device. The procedure to create NED for hicn is explained in the +following: Place hicn.yang model in a folder called hicn-yang-model, and follow these steps: @@ -323,7 +236,6 @@ Place hicn.yang model in a folder called hicn-yang-model, and follow these steps At this point, we are able to connect to the remote device. - ## Release note -The current version is compatible with the 19.01 VPP stable and sysrepo 0.7.7. +The current version is compatible with the 19.01 VPP stable and sysrepo 0.7.7.
\ No newline at end of file |