mirror of
				https://github.com/xdp-project/bpf-examples.git
				synced 2024-05-06 15:54:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			81 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			81 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
 | |
| 
 | |
| #include <net/if.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <linux/ethtool.h>
 | |
| #include <linux/sockios.h>
 | |
| #ifndef SIOCETHTOOL
 | |
| #define SIOCETHTOOL	0x8946		/* Ethtool interface		*/
 | |
| #endif
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <string.h> /* memcpy */
 | |
| #include <unistd.h> /* close */
 | |
| 
 | |
| #ifndef max
 | |
| # define max(x, y) ((x) < (y) ? (y) : (x))
 | |
| #endif
 | |
| 
 | |
| #define GET_CHAN_MAX	1
 | |
| #define GET_CHAN_CURR	2
 | |
| 
 | |
| /* Based on xsk_get_max_queues(), but needed info on max_queues before
 | |
|  * xsk objects are created.
 | |
|  */
 | |
| int __ethtool_get_channels(const char *ifname, int type)
 | |
| {
 | |
| 	struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
 | |
| 	struct ifreq ifr = {};
 | |
| 	int fd, err, ret = -1;
 | |
| 
 | |
| 	fd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
 | |
| 	if (fd < 0)
 | |
| 		return -errno;
 | |
| 
 | |
| 	ifr.ifr_data = (void *)&channels;
 | |
| 	memcpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
 | |
| 	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
 | |
| 	err = ioctl(fd, SIOCETHTOOL, &ifr);
 | |
| 	if (err && errno != EOPNOTSUPP) {
 | |
| 		ret = -errno;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (err) {
 | |
| 		/* If the device says it has no channels, then all traffic
 | |
| 		 * is sent to a single stream, so max queues = 1.
 | |
| 		 */
 | |
| 		ret = 1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (type == GET_CHAN_MAX) {
 | |
| 		/* Take the max of rx, tx, combined. Drivers return
 | |
| 		 * the number of channels in different ways.
 | |
| 		 */
 | |
| 		ret = max(channels.max_rx, channels.max_tx);
 | |
| 		ret = max(ret, (int)channels.max_combined);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	if (type == GET_CHAN_CURR) {
 | |
| 		ret = max(channels.rx_count, channels.tx_count);
 | |
| 		ret = max(ret, (int)channels.combined_count);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| out:
 | |
| 	close(fd);
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| int ethtool_get_max_channels(const char *ifname)
 | |
| {
 | |
| 	return __ethtool_get_channels(ifname, GET_CHAN_MAX);
 | |
| }
 | |
| 
 | |
| int ethtool_get_channels(const char *ifname)
 | |
| {
 | |
| 	return __ethtool_get_channels(ifname, GET_CHAN_CURR);
 | |
| }
 |