blob: 6a430ab664ebfa78d80aaaa6f93ec3cc5931e3bf [file] [log] [blame]
/** @file
* @brief Virtual Network Interface
*/
/*
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_NET_VIRTUAL_H_
#define ZEPHYR_INCLUDE_NET_VIRTUAL_H_
#include <kernel.h>
#include <zephyr/types.h>
#include <stdbool.h>
#include <sys/atomic.h>
#include <net/net_ip.h>
#include <net/net_pkt.h>
#include <sys/util.h>
#include <net/net_if.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Virtual network interface support functions
* @defgroup virtual Virtual Network Interface Support Functions
* @ingroup networking
* @{
*/
/** Virtual interface capabilities */
enum virtual_interface_caps {
/** IPIP tunnel */
VIRTUAL_INTERFACE_IPIP = BIT(1),
/** @cond INTERNAL_HIDDEN */
/* Marker for capabilities - must be at the end of the enum.
* It is here because the capability list cannot be empty.
*/
VIRTUAL_INTERFACE_NUM_CAPS
/** @endcond */
};
/** @cond INTERNAL_HIDDEN */
enum virtual_interface_config_type {
VIRTUAL_INTERFACE_CONFIG_TYPE_PEER_ADDRESS,
VIRTUAL_INTERFACE_CONFIG_TYPE_MTU,
};
struct virtual_interface_config {
sa_family_t family;
union {
struct in_addr peer4addr;
struct in6_addr peer6addr;
int mtu;
};
};
#if defined(CONFIG_NET_L2_VIRTUAL)
#define VIRTUAL_MAX_NAME_LEN CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN
#else
#define VIRTUAL_MAX_NAME_LEN 0
#endif
/** @endcond */
struct virtual_interface_api {
/**
* The net_if_api must be placed in first position in this
* struct so that we are compatible with network interface API.
*/
struct net_if_api iface_api;
/** Get the virtual interface capabilities */
enum virtual_interface_caps (*get_capabilities)(struct net_if *iface);
/** Start the device */
int (*start)(const struct device *dev);
/** Stop the device */
int (*stop)(const struct device *dev);
/** Send a network packet */
int (*send)(struct net_if *iface, struct net_pkt *pkt);
/** Receive a network packet */
enum net_verdict (*recv)(struct net_if *iface, struct net_pkt *pkt);
/** Check if this received network packet is for this interface.
* The callback returns NET_CONTINUE if this interface will accept the
* packet and pass it upper layers, NET_DROP if the packet is to be
* dropped and NET_OK to pass it to next interface.
*/
enum net_verdict (*input)(struct net_if *input_iface,
struct net_if *iface,
struct net_addr *remote_addr,
struct net_pkt *pkt);
/** Pass the attachment information to virtual interface */
int (*attach)(struct net_if *virtual_iface, struct net_if *iface);
/** Set specific L2 configuration */
int (*set_config)(struct net_if *iface,
enum virtual_interface_config_type type,
const struct virtual_interface_config *config);
/** Get specific L2 configuration */
int (*get_config)(struct net_if *iface,
enum virtual_interface_config_type type,
struct virtual_interface_config *config);
};
/* Make sure that the network interface API is properly setup inside
* Virtual API struct (it is the first one).
*/
BUILD_ASSERT(offsetof(struct virtual_interface_api, iface_api) == 0);
/** Virtual L2 context that is needed to binding to the real network interface
*/
struct virtual_interface_context {
/** @cond INTERNAL_HIDDEN */
/* Keep track of contexts */
sys_snode_t node;
/* My virtual network interface */
struct net_if *virtual_iface;
/** @endcond */
/**
* Other network interface this virtual network interface is
* attached to. These values can be chained so virtual network
* interfaces can run on top of other virtual interfaces.
*/
struct net_if *iface;
/**
* This tells what L2 features does virtual support.
*/
enum net_l2_flags virtual_l2_flags;
/** Is this context already initialized */
bool is_init;
/** Link address for this network interface */
struct net_linkaddr_storage lladdr;
/** User friendly name of this L2 layer. */
char name[VIRTUAL_MAX_NAME_LEN];
};
/**
* @brief Attach virtual network interface to the given network interface.
*
* @param virtual_iface Virtual network interface.
* @param iface Network interface we are attached to. This can be NULL,
* if we want to detach.
*
* @return 0 if ok, <0 if attaching failed
*/
int net_virtual_interface_attach(struct net_if *virtual_iface,
struct net_if *iface);
/**
* @brief Return network interface related to this virtual network interface.
* The returned network interface is below this virtual network interface.
*
* @param iface Virtual network interface.
*
* @return Network interface related to this virtual interface or
* NULL if no such interface exists.
*/
struct net_if *net_virtual_get_iface(struct net_if *iface);
/**
* @brief Return the name of the virtual network interface L2.
*
* @param iface Virtual network interface.
* @param buf Buffer to store the name
* @param len Max buffer length
*
* @return Name of the virtual network interface.
*/
char *net_virtual_get_name(struct net_if *iface, char *buf, size_t len);
/**
* @brief Set the name of the virtual network interface L2.
*
* @param iface Virtual network interface.
* @param name Name of the virtual L2 layer.
*/
void net_virtual_set_name(struct net_if *iface, const char *name);
/**
* @brief Set the L2 flags of the virtual network interface.
*
* @param iface Virtual network interface.
* @param flags L2 flags to set.
*
* @return Previous flags that were set.
*/
enum net_l2_flags net_virtual_set_flags(struct net_if *iface,
enum net_l2_flags flags);
/**
* @brief Feed the IP pkt to stack if tunneling is enabled.
*
* @param input_iface Network interface receiving the pkt.
* @param remote_addr IP address of the sender.
* @param pkt Network packet.
*
* @return Verdict what to do with the packet.
*/
enum net_verdict net_virtual_input(struct net_if *input_iface,
struct net_addr *remote_addr,
struct net_pkt *pkt);
/** @cond INTERNAL_HIDDEN */
/**
* @brief Initialize the network interface so that a virtual
* interface can be attached to it.
*
* @param iface Network interface
*/
#if defined(CONFIG_NET_L2_VIRTUAL)
void net_virtual_init(struct net_if *iface);
#else
static inline void net_virtual_init(struct net_if *iface)
{
ARG_UNUSED(iface);
}
#endif
/**
* @brief Take virtual network interface down. This is called
* if the underlying interface is going down.
*
* @param iface Network interface
*/
#if defined(CONFIG_NET_L2_VIRTUAL)
void net_virtual_disable(struct net_if *iface);
#else
static inline void net_virtual_disable(struct net_if *iface)
{
ARG_UNUSED(iface);
}
#endif
#define VIRTUAL_L2_CTX_TYPE struct virtual_interface_context
/**
* @brief Return virtual device hardware capability information.
*
* @param iface Network interface
*
* @return Hardware capabilities
*/
static inline enum virtual_interface_caps
net_virtual_get_iface_capabilities(struct net_if *iface)
{
const struct virtual_interface_api *virt =
(struct virtual_interface_api *)net_if_get_device(iface)->api;
if (!virt->get_capabilities) {
return (enum virtual_interface_caps)0;
}
return virt->get_capabilities(iface);
}
#define Z_NET_VIRTUAL_INTERFACE_INIT(node_id, dev_name, drv_name, \
init_fn, pm_control_fn, data, cfg, \
prio, api, mtu) \
Z_NET_DEVICE_INIT(node_id, dev_name, drv_name, init_fn, \
pm_control_fn, data, cfg, prio, api, \
VIRTUAL_L2, NET_L2_GET_CTX_TYPE(VIRTUAL_L2), \
mtu)
/** @endcond */
/**
* @def NET_VIRTUAL_INTERFACE_INIT
*
* @brief Create a virtual network interface. Binding to another interface
* is done at runtime by calling net_virtual_interface_attach().
* The attaching is done automatically when setting up tunneling
* when peer IP address is set in IP tunneling driver.
*
* @param dev_name Network device name.
* @param drv_name The name this instance of the driver exposes to
* the system.
* @param init_fn Address to the init function of the driver.
* @param pm_control_fn Pointer to pm_control function.
* Can be NULL if not implemented.
* @param data Pointer to the device's private data.
* @param cfg The address to the structure containing the
* configuration information for this instance of the driver.
* @param prio The initialization level at which configuration occurs.
* @param api Provides an initial pointer to the API function struct
* used by the driver. Can be NULL.
* @param mtu Maximum transfer unit in bytes for this network interface.
* This is the default value and its value can be tweaked at runtime.
*/
#define NET_VIRTUAL_INTERFACE_INIT(dev_name, drv_name, init_fn, \
pm_control_fn, \
data, cfg, prio, api, mtu) \
Z_NET_VIRTUAL_INTERFACE_INIT(DT_INVALID_NODE, dev_name, \
drv_name, init_fn, pm_control_fn, \
data, cfg, prio, api, mtu)
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_NET_VIRTUAL_H_ */