11// SPDX-License-Identifier: BSD-3-Clause
22// Copyright (c) 2024 Christophe Fontaine
33
4+ #include <gr_config.h>
45#include <gr_control_input.h>
56#include <gr_control_output.h>
67#include <gr_eth.h>
1415#include <event2/event.h>
1516#include <rte_errno.h>
1617#include <rte_malloc.h>
18+ #include <rte_net.h>
1719
1820#include <fcntl.h>
1921#include <linux/if_tun.h>
@@ -32,6 +34,7 @@ static struct event_base *ev_base;
3234struct iface_info_loopback {
3335 int fd ;
3436 struct event * ev ;
37+ struct rte_ether_addr mac ;
3538};
3639
3740static void finalize_fd (struct event * ev , void * /*priv*/ ) {
@@ -40,14 +43,26 @@ static void finalize_fd(struct event *ev, void * /*priv*/) {
4043 close (fd );
4144}
4245
46+ static int loopback_mac_get (const struct iface * iface , struct rte_ether_addr * mac ) {
47+ struct iface_info_loopback * lo = (struct iface_info_loopback * )iface -> info ;
48+ * mac = lo -> mac ;
49+ return 0 ;
50+ }
51+
4352void loopback_tx (struct rte_mbuf * m ) {
4453 struct mbuf_data * d = mbuf_data (m );
4554 struct iface_info_loopback * lo ;
46- struct iovec iov [ 2 ] ;
47- struct tun_pi pi ;
48- char * data ;
55+ struct rte_ether_hdr * eth ;
56+ struct iface_stats * stats ;
57+ char * data = NULL ;
4958
5059 lo = (struct iface_info_loopback * )d -> iface -> info ;
60+
61+ eth = rte_pktmbuf_mtod (m , struct rte_ether_hdr * );
62+ if (rte_is_broadcast_ether_addr (& eth -> dst_addr ) == 0 )
63+ loopback_mac_get (d -> iface , & eth -> dst_addr );
64+ loopback_mac_get (d -> iface , & eth -> src_addr );
65+
5166 if (rte_pktmbuf_linearize (m ) == 0 ) {
5267 data = rte_pktmbuf_mtod (m , char * );
5368 } else {
@@ -60,42 +75,41 @@ void loopback_tx(struct rte_mbuf *m) {
6075 // to the user provided buffer.
6176 rte_pktmbuf_read (m , 0 , rte_pktmbuf_pkt_len (m ), data );
6277 }
63- pi .flags = 0 ;
64- if ((data [0 ] & 0xf0 ) == 0x40 )
65- pi .proto = RTE_BE16 (RTE_ETHER_TYPE_IPV4 );
66- else if ((data [0 ] & 0xf0 ) == 0x60 )
67- pi .proto = RTE_BE16 (RTE_ETHER_TYPE_IPV6 );
68- else {
69- LOG (ERR , "Bad proto: 0x%x - drop packet" , data [0 ]);
70- goto end ;
71- }
78+
7279 // Do not retry even in case of if EAGAIN || EWOULDBLOCK
7380 // If the tun device queue is full, something really bad is
7481 // already happening on the management plane side.
75- iov [0 ].iov_base = & pi ;
76- iov [0 ].iov_len = sizeof (pi );
77- iov [1 ].iov_base = data ;
78- iov [1 ].iov_len = rte_pktmbuf_pkt_len (m );
79-
80- if (writev (lo -> fd , iov , ARRAY_DIM (iov )) < 0 ) {
82+ if (write (lo -> fd , data , rte_pktmbuf_pkt_len (m )) < 0 ) {
8183 // The user messed up and removed gr-loopX
8284 // release resources on our side to try to recover
8385 if (errno == EBADFD ) {
8486 iface_destroy (d -> iface -> id );
8587 }
86- LOG (ERR , "write to tun device failed %s" , strerror (errno ));
88+ LOG (ERR , "write to tap device failed %s" , strerror (errno ));
8789 }
8890
91+ stats = iface_get_stats (rte_lcore_id (), d -> iface -> id );
92+ stats -> tx_packets += 1 ;
93+ stats -> tx_bytes += rte_pktmbuf_pkt_len (m );
94+
95+ if (gr_config .log_packets )
96+ trace_log_packet (m , "tx" , d -> iface -> name );
97+
98+ // TODO: add a trace for that fake node
99+ if (gr_mbuf_is_traced (m ))
100+ gr_mbuf_trace_finish (m );
89101end :
90102 if (!rte_pktmbuf_is_contiguous (m ))
91103 rte_free (data );
92104 rte_pktmbuf_free (m );
93105}
94106
95107static void iface_loopback_poll (evutil_socket_t , short reason , void * ev_iface ) {
96- struct eth_input_mbuf_data * e ;
97108 struct iface_info_loopback * lo ;
98109 struct iface * iface = ev_iface ;
110+ struct eth_input_mbuf_data * e ;
111+ struct rte_ether_hdr * eth ;
112+ struct iface_stats * stats ;
99113 struct rte_mbuf * mbuf ;
100114 size_t read_len ;
101115 size_t len ;
@@ -105,7 +119,7 @@ static void iface_loopback_poll(evutil_socket_t, short reason, void *ev_iface) {
105119
106120 if (reason & EV_CLOSED ) {
107121 // The user messed up and removed gr-loopX
108- LOG (ERR , "tun device %s deleted" , iface -> name );
122+ LOG (ERR , "tap device %s deleted" , iface -> name );
109123 iface_destroy (iface -> id );
110124 return ;
111125 }
@@ -116,7 +130,7 @@ static void iface_loopback_poll(evutil_socket_t, short reason, void *ev_iface) {
116130 goto err ;
117131 }
118132
119- read_len = iface -> mtu + sizeof ( struct tun_pi ) ;
133+ read_len = iface -> mtu ;
120134 if ((data = rte_pktmbuf_append (mbuf , read_len )) == NULL ) {
121135 LOG (ERR , "rte_pktmbuf_alloc %s" , rte_strerror (rte_errno ));
122136 goto err ;
@@ -130,20 +144,28 @@ static void iface_loopback_poll(evutil_socket_t, short reason, void *ev_iface) {
130144 }
131145
132146 rte_pktmbuf_trim (mbuf , read_len - len );
147+ eth = rte_pktmbuf_mtod (mbuf , struct rte_ether_hdr * );
148+
149+ if (rte_is_broadcast_ether_addr (& eth -> dst_addr ) == 0 )
150+ loopback_mac_get (iface , & eth -> dst_addr );
133151
134152 // packet sent from linux tun iface, no need to compute checksum;
135153 mbuf -> ol_flags = RTE_MBUF_F_RX_IP_CKSUM_GOOD ;
154+ mbuf -> packet_type = rte_net_get_ptype (mbuf , NULL , RTE_PTYPE_ALL_MASK );
136155
137- // We can't call rte_net_get_ptype directly as we do not have an ethernet frame.
138- // An option would be to prepend/adjust every buffer, but let's set directly
139- // the information we need instead.
140- mbuf -> packet_type = data [0 ] == 6 ? RTE_PTYPE_L3_IPV6 : RTE_PTYPE_L3_IPV4 ;
141-
142- // required by ip(6)_input
143156 e = eth_input_mbuf_data (mbuf );
144157 e -> iface = iface ;
145158 e -> domain = ETH_DOMAIN_LOOPBACK ;
146159
160+ stats = iface_get_stats (rte_lcore_id (), iface -> id );
161+ stats -> rx_packets += 1 ;
162+ stats -> rx_bytes += rte_pktmbuf_pkt_len (mbuf );
163+
164+ if (gr_config .log_packets )
165+ trace_log_packet (mbuf , "rx" , iface -> name );
166+
167+ // TODO: add trace for that fake node
168+
147169 post_to_stack (loopback_get_control_id (), mbuf );
148170 return ;
149171
@@ -175,7 +197,7 @@ static int iface_loopback_init(struct iface *iface, const void * /* api_info */)
175197
176198 memset (& ifr , 0 , sizeof (struct ifreq ));
177199 memccpy (ifr .ifr_name , iface -> name , 0 , IFNAMSIZ );
178- ifr .ifr_flags = IFF_TUN | IFF_POINTOPOINT | IFF_ONE_QUEUE ;
200+ ifr .ifr_flags = IFF_TAP | IFF_ONE_QUEUE | IFF_NO_PI ;
179201
180202 if ((ioctl_sock = socket (AF_INET , SOCK_DGRAM , 0 )) < 0 ) {
181203 LOG (ERR , "socket(SOCK_DGRAM): %s" , strerror (errno ));
@@ -209,12 +231,18 @@ static int iface_loopback_init(struct iface *iface, const void * /* api_info */)
209231 goto err ;
210232 }
211233
212- ifr .ifr_flags |= IFF_UP ;
234+ ifr .ifr_flags |= IFF_UP | IFF_NOARP ;
213235 if (ioctl (ioctl_sock , SIOCSIFFLAGS , & ifr ) < 0 ) {
214236 LOG (ERR , "ioctl(SIOCSIFFLAGS): %s" , strerror (errno ));
215237 goto err ;
216238 }
217239
240+ if (ioctl (ioctl_sock , SIOCGIFHWADDR , & ifr ) < 0 ) {
241+ LOG (ERR , "ioctl(SIOCGIFHWADDR) %s" , strerror (errno ));
242+ goto err ;
243+ }
244+ memcpy (& lo -> mac , ifr .ifr_hwaddr .sa_data , sizeof (lo -> mac ));
245+
218246 iface -> flags = GR_IFACE_F_UP ;
219247 iface -> state = GR_IFACE_S_RUNNING ;
220248 lo -> ev = event_new (
@@ -267,6 +295,7 @@ static struct iface_type iface_type_loopback = {
267295 .init = iface_loopback_init ,
268296 .fini = iface_loopback_fini ,
269297 .to_api = iface_loopback_to_api ,
298+ .get_eth_addr = loopback_mac_get ,
270299};
271300
272301static struct gr_module loopback_module = {
0 commit comments