1 /** @file
2  * @brief Virtual Network Interface
3  */
4 
5 /*
6  * Copyright (c) 2021 Intel Corporation
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #ifndef ZEPHYR_INCLUDE_NET_VIRTUAL_H_
12 #define ZEPHYR_INCLUDE_NET_VIRTUAL_H_
13 
14 #include <zephyr/kernel.h>
15 #include <zephyr/types.h>
16 #include <stdbool.h>
17 #include <zephyr/sys/atomic.h>
18 
19 #include <zephyr/net/net_ip.h>
20 #include <zephyr/net/net_pkt.h>
21 
22 #include <zephyr/sys/util.h>
23 #include <zephyr/net/net_if.h>
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 /**
30  * @brief Virtual network interface support functions
31  * @defgroup virtual Virtual Network Interface Support Functions
32  * @since 2.6
33  * @version 0.8.0
34  * @ingroup networking
35  * @{
36  */
37 
38 /** Virtual interface capabilities */
39 enum virtual_interface_caps {
40 	/** IPIP tunnel */
41 	VIRTUAL_INTERFACE_IPIP = BIT(1),
42 
43 	/** Virtual LAN interface (VLAN) */
44 	VIRTUAL_INTERFACE_VLAN = BIT(2),
45 
46 	/** Virtual Ethernet bridge interface. */
47 	VIRTUAL_INTERFACE_BRIDGE = BIT(3),
48 
49 /** @cond INTERNAL_HIDDEN */
50 	/* Marker for capabilities - must be at the end of the enum.
51 	 * It is here because the capability list cannot be empty.
52 	 */
53 	VIRTUAL_INTERFACE_NUM_CAPS
54 /** @endcond */
55 };
56 
57 /** @cond INTERNAL_HIDDEN */
58 
59 enum virtual_interface_config_type {
60 	VIRTUAL_INTERFACE_CONFIG_TYPE_PEER_ADDRESS,
61 	VIRTUAL_INTERFACE_CONFIG_TYPE_MTU,
62 	VIRTUAL_INTERFACE_CONFIG_TYPE_LINK_TYPE,
63 };
64 
65 struct virtual_interface_link_types {
66 	int count;
67 	uint16_t type[COND_CODE_1(CONFIG_NET_CAPTURE_COOKED_MODE,
68 				  (CONFIG_NET_CAPTURE_COOKED_MODE_MAX_LINK_TYPES),
69 				  (1))];
70 };
71 
72 struct virtual_interface_config {
73 	sa_family_t family;
74 	union {
75 		struct in_addr peer4addr;
76 		struct in6_addr peer6addr;
77 		int mtu;
78 		struct virtual_interface_link_types link_types;
79 	};
80 };
81 
82 #if defined(CONFIG_NET_L2_VIRTUAL)
83 #define VIRTUAL_MAX_NAME_LEN CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN
84 #else
85 #define VIRTUAL_MAX_NAME_LEN 0
86 #endif
87 /** @endcond */
88 
89 /** Virtual L2 API operations. */
90 struct virtual_interface_api {
91 	/**
92 	 * The net_if_api must be placed in first position in this
93 	 * struct so that we are compatible with network interface API.
94 	 */
95 	struct net_if_api iface_api;
96 
97 	/** Get the virtual interface capabilities */
98 	enum virtual_interface_caps (*get_capabilities)(struct net_if *iface);
99 
100 	/** Start the device */
101 	int (*start)(const struct device *dev);
102 
103 	/** Stop the device */
104 	int (*stop)(const struct device *dev);
105 
106 	/** Send a network packet */
107 	int (*send)(struct net_if *iface, struct net_pkt *pkt);
108 
109 	/**
110 	 * Receive a network packet.
111 	 * The callback returns NET_OK if this interface will accept the
112 	 * packet and pass it upper layers, NET_DROP if the packet is to be
113 	 * dropped and NET_CONTINUE to pass it to next interface.
114 	 */
115 	enum net_verdict (*recv)(struct net_if *iface, struct net_pkt *pkt);
116 
117 	/** Pass the attachment information to virtual interface */
118 	int (*attach)(struct net_if *virtual_iface, struct net_if *iface);
119 
120 	/** Set specific L2 configuration */
121 	int (*set_config)(struct net_if *iface,
122 			  enum virtual_interface_config_type type,
123 			  const struct virtual_interface_config *config);
124 
125 	/** Get specific L2 configuration */
126 	int (*get_config)(struct net_if *iface,
127 			  enum virtual_interface_config_type type,
128 			  struct virtual_interface_config *config);
129 };
130 
131 /* Make sure that the network interface API is properly setup inside
132  * Virtual API struct (it is the first one).
133  */
134 BUILD_ASSERT(offsetof(struct virtual_interface_api, iface_api) == 0);
135 
136 /** Virtual L2 context that is needed to binding to the real network interface
137  */
138 struct virtual_interface_context {
139 /** @cond INTERNAL_HIDDEN */
140 	/* Keep track of contexts */
141 	sys_snode_t node;
142 
143 	/* My virtual network interface */
144 	struct net_if *virtual_iface;
145 /** @endcond */
146 
147 	/**
148 	 * Other network interface this virtual network interface is
149 	 * attached to. These values can be chained so virtual network
150 	 * interfaces can run on top of other virtual interfaces.
151 	 */
152 	struct net_if *iface;
153 
154 	/**
155 	 * This tells what L2 features does virtual support.
156 	 */
157 	enum net_l2_flags virtual_l2_flags;
158 
159 	/** Is this context already initialized */
160 	bool is_init;
161 
162 	/** Link address for this network interface */
163 	struct net_linkaddr_storage lladdr;
164 
165 	/** User friendly name of this L2 layer. */
166 	char name[VIRTUAL_MAX_NAME_LEN];
167 };
168 
169 /**
170  * @brief Attach virtual network interface to the given network interface.
171  *
172  * @param virtual_iface Virtual network interface.
173  * @param iface Network interface we are attached to. This can be NULL,
174  * if we want to detach.
175  *
176  * @return 0 if ok, <0 if attaching failed
177  */
178 int net_virtual_interface_attach(struct net_if *virtual_iface,
179 				  struct net_if *iface);
180 
181 /**
182  * @brief Return network interface related to this virtual network interface.
183  * The returned network interface is below this virtual network interface.
184  *
185  * @param iface Virtual network interface.
186  *
187  * @return Network interface related to this virtual interface or
188  *         NULL if no such interface exists.
189  */
190 struct net_if *net_virtual_get_iface(struct net_if *iface);
191 
192 /**
193  * @brief Return the name of the virtual network interface L2.
194  *
195  * @param iface Virtual network interface.
196  * @param buf Buffer to store the name
197  * @param len Max buffer length
198  *
199  * @return Name of the virtual network interface.
200  */
201 char *net_virtual_get_name(struct net_if *iface, char *buf, size_t len);
202 
203 /**
204  * @brief Set the name of the virtual network interface L2.
205  *
206  * @param iface Virtual network interface.
207  * @param name Name of the virtual L2 layer.
208  */
209 void net_virtual_set_name(struct net_if *iface, const char *name);
210 
211 /**
212  * @brief Set the L2 flags of the virtual network interface.
213  *
214  * @param iface Virtual network interface.
215  * @param flags L2 flags to set.
216  *
217  * @return Previous flags that were set.
218  */
219 enum net_l2_flags net_virtual_set_flags(struct net_if *iface,
220 					enum net_l2_flags flags);
221 
222 /**
223  * @brief Feed the IP pkt to stack if tunneling is enabled.
224  *
225  * @param input_iface Network interface receiving the pkt.
226  * @param remote_addr IP address of the sender.
227  * @param pkt Network packet.
228  *
229  * @return Verdict what to do with the packet.
230  */
231 enum net_verdict net_virtual_input(struct net_if *input_iface,
232 				   struct net_addr *remote_addr,
233 				   struct net_pkt *pkt);
234 
235 /** @cond INTERNAL_HIDDEN */
236 
237 /**
238  * @brief Initialize the network interface so that a virtual
239  *        interface can be attached to it.
240  *
241  * @param iface Network interface
242  */
243 #if defined(CONFIG_NET_L2_VIRTUAL)
244 void net_virtual_init(struct net_if *iface);
245 #else
net_virtual_init(struct net_if * iface)246 static inline void net_virtual_init(struct net_if *iface)
247 {
248 	ARG_UNUSED(iface);
249 }
250 #endif
251 
252 /**
253  * @brief Update the carrier state of the virtual network interface.
254  *        This is called if the underlying interface is going down.
255  *
256  * @param iface Network interface
257  */
258 #if defined(CONFIG_NET_L2_VIRTUAL)
259 void net_virtual_disable(struct net_if *iface);
260 #else
net_virtual_disable(struct net_if * iface)261 static inline void net_virtual_disable(struct net_if *iface)
262 {
263 	ARG_UNUSED(iface);
264 }
265 #endif
266 
267 /**
268  * @brief Update the carrier state of the virtual network interface.
269  *        This is called if the underlying interface is going up.
270  *
271  * @param iface Network interface
272  */
273 #if defined(CONFIG_NET_L2_VIRTUAL)
274 void net_virtual_enable(struct net_if *iface);
275 #else
net_virtual_enable(struct net_if * iface)276 static inline void net_virtual_enable(struct net_if *iface)
277 {
278 	ARG_UNUSED(iface);
279 }
280 #endif
281 
282 #define VIRTUAL_L2_CTX_TYPE	struct virtual_interface_context
283 
284 /**
285  * @brief Return virtual device hardware capability information.
286  *
287  * @param iface Network interface
288  *
289  * @return Hardware capabilities
290  */
291 static inline enum virtual_interface_caps
net_virtual_get_iface_capabilities(struct net_if * iface)292 net_virtual_get_iface_capabilities(struct net_if *iface)
293 {
294 	const struct virtual_interface_api *virt =
295 		(struct virtual_interface_api *)net_if_get_device(iface)->api;
296 
297 	if (!virt->get_capabilities) {
298 		return (enum virtual_interface_caps)0;
299 	}
300 
301 	return virt->get_capabilities(iface);
302 }
303 
304 #define Z_NET_VIRTUAL_INTERFACE_INIT(node_id, dev_id, name, init_fn,	\
305 				     pm, data, config, prio, api, mtu)	\
306 	Z_NET_DEVICE_INIT(node_id, dev_id, name, init_fn, pm, data,	\
307 			  config, prio, api, VIRTUAL_L2,		\
308 			  NET_L2_GET_CTX_TYPE(VIRTUAL_L2), mtu)
309 
310 #define Z_NET_VIRTUAL_INTERFACE_INIT_INSTANCE(node_id, dev_id, name,	\
311 					      inst, init_fn, pm, data,	\
312 					      config, prio, api, mtu)	\
313 	Z_NET_DEVICE_INIT_INSTANCE(node_id, dev_id, name, inst,		\
314 				   init_fn, pm, data,			\
315 				   config, prio, api, VIRTUAL_L2,	\
316 				   NET_L2_GET_CTX_TYPE(VIRTUAL_L2), mtu)
317 /** @endcond */
318 
319 /**
320  * @brief Create a virtual network interface. Binding to another interface
321  *        is done at runtime by calling net_virtual_interface_attach().
322  *        The attaching is done automatically when setting up tunneling
323  *        when peer IP address is set in IP tunneling driver.
324  *
325  * @param dev_id Network device id.
326  * @param name The name this instance of the driver exposes to
327  * the system.
328  * @param init_fn Address to the init function of the driver.
329  * @param pm Reference to struct pm_device associated with the device.
330  * (optional).
331  * @param data Pointer to the device's private data.
332  * @param config The address to the structure containing the
333  * configuration information for this instance of the driver.
334  * @param prio The initialization level at which configuration occurs.
335  * @param api Provides an initial pointer to the API function struct
336  * used by the driver. Can be NULL.
337  * @param mtu Maximum transfer unit in bytes for this network interface.
338  * This is the default value and its value can be tweaked at runtime.
339  */
340 #define NET_VIRTUAL_INTERFACE_INIT(dev_id, name, init_fn, pm, data,	\
341 				   config, prio, api, mtu)		\
342 	Z_NET_VIRTUAL_INTERFACE_INIT(DT_INVALID_NODE, dev_id, name,	\
343 				     init_fn, pm, data, config, prio,	\
344 				     api, mtu)
345 
346 /**
347  * @brief Create a virtual network interface. Binding to another interface
348  *        is done at runtime by calling net_virtual_interface_attach().
349  *        The attaching is done automatically when setting up tunneling
350  *        when peer IP address is set in IP tunneling driver.
351  *
352  * @param dev_id Network device id.
353  * @param name The name this instance of the driver exposes to
354  * the system.
355  * @param inst instance number
356  * @param init_fn Address to the init function of the driver.
357  * @param pm Reference to struct pm_device associated with the device.
358  * (optional).
359  * @param data Pointer to the device's private data.
360  * @param config The address to the structure containing the
361  * configuration information for this instance of the driver.
362  * @param prio The initialization level at which configuration occurs.
363  * @param api Provides an initial pointer to the API function struct
364  * used by the driver. Can be NULL.
365  * @param mtu Maximum transfer unit in bytes for this network interface.
366  * This is the default value and its value can be tweaked at runtime.
367  */
368 #define NET_VIRTUAL_INTERFACE_INIT_INSTANCE(dev_id, name, inst,		 \
369 					    init_fn, pm, data,		 \
370 					    config, prio, api, mtu)	 \
371 	Z_NET_VIRTUAL_INTERFACE_INIT_INSTANCE(DT_INVALID_NODE, dev_id,	 \
372 					      name, inst,		 \
373 					      init_fn, pm, data, config, \
374 					      prio, api, mtu)
375 
376 /**
377  * @}
378  */
379 
380 #ifdef __cplusplus
381 }
382 #endif
383 
384 #endif /* ZEPHYR_INCLUDE_NET_VIRTUAL_H_ */
385