/** @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 #include #include #include #include #include #include #include #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 { /** @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 empty function (device_pm_control_nop) 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_ */