2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

Provide method to locate device by IP and add more nodev functions to netdev

In some cases we need to be able to locate a device by its IPv4 address.
There doesn't seem to be an easy way to do this on Linux, so we iterate
through all devices until it's found.  The caller can provide a hint as
to the device, so subsequent checks can be quicker.

This checkin also adds nodev versions of functions to lookup ARP entries
and the IPv4 address of a device.
This commit is contained in:
Justin Pettit
2009-07-06 15:37:19 -07:00
parent ae8871ec5b
commit 79c720a830
2 changed files with 67 additions and 7 deletions

View File

@@ -784,12 +784,14 @@ netdev_set_advertisements(struct netdev *netdev, uint32_t advertise)
/* If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if
* 'in4' is non-null) and returns true. Otherwise, returns false. */
bool
netdev_get_in4(const struct netdev *netdev, struct in_addr *in4)
netdev_nodev_get_in4(const char *netdev_name, struct in_addr *in4)
{
struct ifreq ifr;
struct in_addr ip = { INADDR_ANY };
strncpy(ifr.ifr_name, netdev->name, sizeof ifr.ifr_name);
init_netdev();
strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name);
ifr.ifr_addr.sa_family = AF_INET;
COVERAGE_INC(netdev_get_in4);
if (ioctl(af_inet_sock, SIOCGIFADDR, &ifr) == 0) {
@@ -797,7 +799,7 @@ netdev_get_in4(const struct netdev *netdev, struct in_addr *in4)
ip = sin->sin_addr;
} else {
VLOG_DBG_RL(&rl, "%s: ioctl(SIOCGIFADDR) failed: %s",
netdev->name, strerror(errno));
netdev_name, strerror(errno));
}
if (in4) {
*in4 = ip;
@@ -805,6 +807,12 @@ netdev_get_in4(const struct netdev *netdev, struct in_addr *in4)
return ip.s_addr != INADDR_ANY;
}
bool
netdev_get_in4(const struct netdev *netdev, struct in_addr *in4)
{
return netdev_nodev_get_in4(netdev->name, in4);
}
static void
make_in4_sockaddr(struct sockaddr *sa, struct in_addr addr)
{
@@ -970,13 +978,15 @@ netdev_turn_flags_off(struct netdev *netdev, enum netdev_flags flags,
* returns 0. Otherwise, it returns a positive errno value; in particular,
* ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */
int
netdev_arp_lookup(const struct netdev *netdev,
uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
netdev_nodev_arp_lookup(const char *netdev_name, uint32_t ip,
uint8_t mac[ETH_ADDR_LEN])
{
struct arpreq r;
struct sockaddr_in *pa;
int retval;
init_netdev();
memset(&r, 0, sizeof r);
pa = (struct sockaddr_in *) &r.arp_pa;
pa->sin_family = AF_INET;
@@ -984,18 +994,25 @@ netdev_arp_lookup(const struct netdev *netdev,
pa->sin_port = 0;
r.arp_ha.sa_family = ARPHRD_ETHER;
r.arp_flags = 0;
strncpy(r.arp_dev, netdev->name, sizeof r.arp_dev);
strncpy(r.arp_dev, netdev_name, sizeof r.arp_dev);
COVERAGE_INC(netdev_arp_lookup);
retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0;
if (!retval) {
memcpy(mac, r.arp_ha.sa_data, ETH_ADDR_LEN);
} else if (retval != ENXIO) {
VLOG_WARN_RL(&rl, "%s: could not look up ARP entry for "IP_FMT": %s",
netdev->name, IP_ARGS(&ip), strerror(retval));
netdev_name, IP_ARGS(&ip), strerror(retval));
}
return retval;
}
int
netdev_arp_lookup(const struct netdev *netdev, uint32_t ip,
uint8_t mac[ETH_ADDR_LEN])
{
return netdev_nodev_arp_lookup(netdev->name, ip, mac);
}
static int
get_stats_via_netlink(int ifindex, struct netdev_stats *stats)
{
@@ -1275,6 +1292,45 @@ netdev_enumerate(struct svec *svec)
}
}
/* Attempts to locate a device based on its IPv4 address. The caller
* may provide a hint as to the device by setting 'netdev_name' to a
* likely device name. This string must be malloc'd, since if it is
* not correct then it will be freed. If there is no hint, then
* 'netdev_name' must be the NULL pointer.
*
* If the device is found, the return value will be true and 'netdev_name'
* contains the device's name as a string, which the caller is responsible
* for freeing. If the device is not found, the return value is false. */
bool
netdev_find_dev_by_in4(const struct in_addr *in4, char **netdev_name)
{
int i;
struct in_addr dev_in4;
struct svec dev_list;
/* Check the hint first. */
if (*netdev_name && (netdev_nodev_get_in4(*netdev_name, &dev_in4))
&& (dev_in4.s_addr == in4->s_addr)) {
return true;
}
free(*netdev_name);
*netdev_name = NULL;
netdev_enumerate(&dev_list);
for (i=0; i<dev_list.n; i++) {
if ((netdev_nodev_get_in4(dev_list.names[i], &dev_in4))
&& (dev_in4.s_addr == in4->s_addr)) {
*netdev_name = xstrdup(dev_list.names[i]);
svec_destroy(&dev_list);
return true;
}
}
svec_destroy(&dev_list);
return false;
}
/* Obtains the current flags for the network device named 'netdev_name' and
* stores them into '*flagsp'. Returns 0 if successful, otherwise a positive
* errno value. On error, stores 0 into '*flagsp'.