324 lines
8.7 KiB
C
324 lines
8.7 KiB
C
/** @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 device_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_ */
|