2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

Merge citrix branch into master.

This commit is contained in:
Ben Pfaff
2009-09-02 10:14:53 -07:00
19 changed files with 910 additions and 315 deletions

View File

@@ -96,7 +96,7 @@ struct netdev_linux_cache {
int ifindex;
uint8_t etheraddr[ETH_ADDR_LEN];
struct in_addr in4;
struct in_addr address, netmask;
struct in6_addr in6;
int mtu;
int carrier;
@@ -125,6 +125,8 @@ static int netdev_linux_do_ethtool(struct netdev *, struct ethtool_cmd *,
int cmd, const char *cmd_name);
static int netdev_linux_do_ioctl(const struct netdev *, struct ifreq *,
int cmd, const char *cmd_name);
static int netdev_linux_get_ipv4(const struct netdev *, struct in_addr *,
int cmd, const char *cmd_name);
static int get_flags(const struct netdev *, int *flagsp);
static int set_flags(struct netdev *, int flags);
static int do_get_ifindex(const char *netdev_name);
@@ -935,49 +937,48 @@ netdev_linux_set_policing(struct netdev *netdev,
return 0;
}
/* If 'netdev' has an assigned IPv4 address, sets '*in4' to that address (if
* 'in4' is non-null) and returns true. Otherwise, returns false. */
static int
netdev_linux_get_in4(const struct netdev *netdev_, struct in_addr *in4)
netdev_linux_get_in4(const struct netdev *netdev_,
struct in_addr *address, struct in_addr *netmask)
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
if (!(netdev->cache->valid & VALID_IN4)) {
const struct sockaddr_in *sin;
struct ifreq ifr;
int error;
ifr.ifr_addr.sa_family = AF_INET;
error = netdev_linux_do_ioctl(netdev_, &ifr,
error = netdev_linux_get_ipv4(netdev_, &netdev->cache->address,
SIOCGIFADDR, "SIOCGIFADDR");
if (error) {
return error;
}
sin = (struct sockaddr_in *) &ifr.ifr_addr;
netdev->cache->in4 = sin->sin_addr;
error = netdev_linux_get_ipv4(netdev_, &netdev->cache->netmask,
SIOCGIFNETMASK, "SIOCGIFNETMASK");
if (error) {
return error;
}
netdev->cache->valid |= VALID_IN4;
}
*in4 = netdev->cache->in4;
return in4->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0;
*address = netdev->cache->address;
*netmask = netdev->cache->netmask;
return address->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0;
}
/* Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If
* 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a
* positive errno value. */
static int
netdev_linux_set_in4(struct netdev *netdev_, struct in_addr addr,
struct in_addr mask)
netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
struct in_addr netmask)
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
int error;
error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", addr);
error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address);
if (!error) {
netdev->cache->valid |= VALID_IN4;
netdev->cache->in4 = addr;
if (addr.s_addr != INADDR_ANY) {
netdev->cache->address = address;
netdev->cache->netmask = netmask;
if (address.s_addr != INADDR_ANY) {
error = do_set_addr(netdev_, SIOCSIFNETMASK,
"SIOCSIFNETMASK", mask);
"SIOCSIFNETMASK", netmask);
}
}
return error;
@@ -1076,6 +1077,67 @@ netdev_linux_add_router(struct netdev *netdev UNUSED, struct in_addr router)
return error;
}
static int
netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop,
char **netdev_name)
{
static const char fn[] = "/proc/net/route";
FILE *stream;
char line[256];
int ln;
*netdev_name = NULL;
stream = fopen(fn, "r");
if (stream == NULL) {
VLOG_WARN_RL(&rl, "%s: open failed: %s", fn, strerror(errno));
return errno;
}
ln = 0;
while (fgets(line, sizeof line, stream)) {
if (++ln >= 2) {
char iface[17];
uint32_t dest, gateway, mask;
int refcnt, metric, mtu;
unsigned int flags, use, window, irtt;
if (sscanf(line,
"%16s %"SCNx32" %"SCNx32" %04X %d %u %d %"SCNx32
" %d %u %u\n",
iface, &dest, &gateway, &flags, &refcnt,
&use, &metric, &mask, &mtu, &window, &irtt) != 11) {
VLOG_WARN_RL(&rl, "%s: could not parse line %d: %s",
fn, ln, line);
continue;
}
if (!(flags & RTF_UP)) {
/* Skip routes that aren't up. */
continue;
}
/* The output of 'dest', 'mask', and 'gateway' were given in
* network byte order, so we don't need need any endian
* conversions here. */
if ((dest & mask) == (host->s_addr & mask)) {
if (!gateway) {
/* The host is directly reachable. */
next_hop->s_addr = 0;
} else {
/* To reach the host, we must go through a gateway. */
next_hop->s_addr = gateway;
}
*netdev_name = xstrdup(iface);
fclose(stream);
return 0;
}
}
}
fclose(stream);
return ENXIO;
}
/* Looks up the ARP table entry for 'ip' on 'netdev'. If one exists and can be
* successfully retrieved, it stores the corresponding MAC address in 'mac' and
* returns 0. Otherwise, it returns a positive errno value; in particular,
@@ -1269,6 +1331,7 @@ const struct netdev_class netdev_linux_class = {
netdev_linux_set_in4,
netdev_linux_get_in6,
netdev_linux_add_router,
netdev_linux_get_next_hop,
netdev_linux_arp_lookup,
netdev_linux_update_flags,
@@ -1312,6 +1375,7 @@ const struct netdev_class netdev_tap_class = {
netdev_linux_set_in4,
netdev_linux_get_in6,
netdev_linux_add_router,
netdev_linux_get_next_hop,
netdev_linux_arp_lookup,
netdev_linux_update_flags,
@@ -1591,3 +1655,19 @@ netdev_linux_do_ioctl(const struct netdev *netdev, struct ifreq *ifr,
}
return 0;
}
static int
netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip,
int cmd, const char *cmd_name)
{
struct ifreq ifr;
int error;
ifr.ifr_addr.sa_family = AF_INET;
error = netdev_linux_do_ioctl(netdev, &ifr, cmd, cmd_name);
if (!error) {
const struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;
*ip = sin->sin_addr;
}
return error;
}