mirror of
https://github.com/openvswitch/ovs
synced 2025-09-01 14:55:18 +00:00
tunneling: Handle multiple ip address for given device.
Device can have multiple IP address but netdev_get_in4/6() returns only one configured IPv6 address. Following patch fixes it. OVS router is also updated to return source ip address for given destination, This is required when interface has multiple IP address configured. Signed-off-by: Pravin B Shelar <pshelar@ovn.org> Acked-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
@@ -93,7 +93,6 @@ struct netdev_bsd {
|
|||||||
struct eth_addr etheraddr;
|
struct eth_addr etheraddr;
|
||||||
struct in_addr in4;
|
struct in_addr in4;
|
||||||
struct in_addr netmask;
|
struct in_addr netmask;
|
||||||
struct in6_addr in6;
|
|
||||||
int mtu;
|
int mtu;
|
||||||
int carrier;
|
int carrier;
|
||||||
|
|
||||||
@@ -1245,37 +1244,20 @@ netdev_bsd_set_in4(struct netdev *netdev_, struct in_addr addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
netdev_bsd_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
|
netdev_bsd_get_addr_list(const struct netdev *netdev_,
|
||||||
|
struct in6_addr **addr, struct in6_addr **mask, int *n_cnt)
|
||||||
{
|
{
|
||||||
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
|
||||||
|
int error;
|
||||||
|
|
||||||
if (!(netdev->cache_valid & VALID_IN6)) {
|
if (!(netdev->cache_valid & VALID_IN6)) {
|
||||||
struct ifaddrs *ifa, *head;
|
netdev_get_addrs_list_flush();
|
||||||
struct sockaddr_in6 *sin6;
|
|
||||||
const char *netdev_name = netdev_get_name(netdev_);
|
|
||||||
|
|
||||||
if (getifaddrs(&head) != 0) {
|
|
||||||
VLOG_ERR("getifaddrs on %s device failed: %s", netdev_name,
|
|
||||||
ovs_strerror(errno));
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ifa = head; ifa; ifa = ifa->ifa_next) {
|
|
||||||
if (ifa->ifa_addr->sa_family == AF_INET6 &&
|
|
||||||
!strcmp(ifa->ifa_name, netdev_name)) {
|
|
||||||
sin6 = ALIGNED_CAST(struct sockaddr_in6 *, ifa->ifa_addr);
|
|
||||||
if (sin6) {
|
|
||||||
memcpy(&netdev->in6, &sin6->sin6_addr, sin6->sin6_len);
|
|
||||||
netdev->cache_valid |= VALID_IN6;
|
|
||||||
*in6 = netdev->in6;
|
|
||||||
freeifaddrs(head);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EADDRNOTAVAIL;
|
|
||||||
}
|
}
|
||||||
*in6 = netdev->in6;
|
error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
|
||||||
return 0;
|
if (!error) {
|
||||||
|
netdev->cache_valid |= VALID_IN6;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__NetBSD__)
|
#if defined(__NetBSD__)
|
||||||
@@ -1597,7 +1579,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
|
|||||||
\
|
\
|
||||||
netdev_bsd_get_in4, \
|
netdev_bsd_get_in4, \
|
||||||
netdev_bsd_set_in4, \
|
netdev_bsd_set_in4, \
|
||||||
netdev_bsd_get_in6, \
|
netdev_bsd_get_addr_list, \
|
||||||
NULL, /* add_router */ \
|
NULL, /* add_router */ \
|
||||||
netdev_bsd_get_next_hop, \
|
netdev_bsd_get_next_hop, \
|
||||||
NULL, /* get_status */ \
|
NULL, /* get_status */ \
|
||||||
|
@@ -2693,7 +2693,7 @@ static const struct dpdk_qos_ops egress_policer_ops = {
|
|||||||
\
|
\
|
||||||
NULL, /* get_in4 */ \
|
NULL, /* get_in4 */ \
|
||||||
NULL, /* set_in4 */ \
|
NULL, /* set_in4 */ \
|
||||||
NULL, /* get_in6 */ \
|
NULL, /* get_addr_list */ \
|
||||||
NULL, /* add_router */ \
|
NULL, /* add_router */ \
|
||||||
NULL, /* get_next_hop */ \
|
NULL, /* get_next_hop */ \
|
||||||
GET_STATUS, \
|
GET_STATUS, \
|
||||||
|
@@ -116,7 +116,7 @@ struct netdev_dummy {
|
|||||||
FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
|
FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
|
||||||
|
|
||||||
struct in_addr address, netmask;
|
struct in_addr address, netmask;
|
||||||
struct in6_addr ipv6;
|
struct in6_addr ipv6, ipv6_mask;
|
||||||
struct ovs_list rxes OVS_GUARDED; /* List of child "netdev_rxq_dummy"s. */
|
struct ovs_list rxes OVS_GUARDED; /* List of child "netdev_rxq_dummy"s. */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -731,15 +731,50 @@ netdev_dummy_get_in4(const struct netdev *netdev_,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
netdev_dummy_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
|
netdev_dummy_get_addr_list(const struct netdev *netdev_, struct in6_addr **paddr,
|
||||||
|
struct in6_addr **pmask, int *n_addr)
|
||||||
{
|
{
|
||||||
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
||||||
|
int cnt = 0, i = 0, err = 0;
|
||||||
|
struct in6_addr *addr, *mask;
|
||||||
|
|
||||||
ovs_mutex_lock(&netdev->mutex);
|
ovs_mutex_lock(&netdev->mutex);
|
||||||
*in6 = netdev->ipv6;
|
if (netdev->address.s_addr != INADDR_ANY) {
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv6_addr_is_set(&netdev->ipv6)) {
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
if (!cnt) {
|
||||||
|
err = EADDRNOTAVAIL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
addr = xmalloc(sizeof *addr * cnt);
|
||||||
|
mask = xmalloc(sizeof *mask * cnt);
|
||||||
|
if (netdev->address.s_addr != INADDR_ANY) {
|
||||||
|
in6_addr_set_mapped_ipv4(&addr[i], netdev->address.s_addr);
|
||||||
|
in6_addr_set_mapped_ipv4(&mask[i], netdev->netmask.s_addr);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv6_addr_is_set(&netdev->ipv6)) {
|
||||||
|
memcpy(&addr[i], &netdev->ipv6, sizeof *addr);
|
||||||
|
memcpy(&mask[i], &netdev->ipv6_mask, sizeof *mask);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (paddr) {
|
||||||
|
*paddr = addr;
|
||||||
|
*pmask = mask;
|
||||||
|
*n_addr = cnt;
|
||||||
|
} else {
|
||||||
|
free(addr);
|
||||||
|
free(mask);
|
||||||
|
}
|
||||||
|
out:
|
||||||
ovs_mutex_unlock(&netdev->mutex);
|
ovs_mutex_unlock(&netdev->mutex);
|
||||||
|
|
||||||
return ipv6_addr_is_set(in6) ? 0 : EADDRNOTAVAIL;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -757,12 +792,14 @@ netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
netdev_dummy_set_in6(struct netdev *netdev_, struct in6_addr *in6)
|
netdev_dummy_set_in6(struct netdev *netdev_, struct in6_addr *in6,
|
||||||
|
struct in6_addr *mask)
|
||||||
{
|
{
|
||||||
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
||||||
|
|
||||||
ovs_mutex_lock(&netdev->mutex);
|
ovs_mutex_lock(&netdev->mutex);
|
||||||
netdev->ipv6 = *in6;
|
netdev->ipv6 = *in6;
|
||||||
|
netdev->ipv6_mask = *mask;
|
||||||
ovs_mutex_unlock(&netdev->mutex);
|
ovs_mutex_unlock(&netdev->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1245,7 +1282,7 @@ static const struct netdev_class dummy_class = {
|
|||||||
|
|
||||||
netdev_dummy_get_in4, /* get_in4 */
|
netdev_dummy_get_in4, /* get_in4 */
|
||||||
NULL, /* set_in4 */
|
NULL, /* set_in4 */
|
||||||
netdev_dummy_get_in6, /* get_in6 */
|
netdev_dummy_get_addr_list,
|
||||||
NULL, /* add_router */
|
NULL, /* add_router */
|
||||||
NULL, /* get_next_hop */
|
NULL, /* get_next_hop */
|
||||||
NULL, /* get_status */
|
NULL, /* get_status */
|
||||||
@@ -1538,15 +1575,20 @@ netdev_dummy_ip6addr(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|||||||
struct netdev *netdev = netdev_from_name(argv[1]);
|
struct netdev *netdev = netdev_from_name(argv[1]);
|
||||||
|
|
||||||
if (netdev && is_dummy_class(netdev->netdev_class)) {
|
if (netdev && is_dummy_class(netdev->netdev_class)) {
|
||||||
char ip6_s[IPV6_SCAN_LEN + 1];
|
|
||||||
struct in6_addr ip6;
|
struct in6_addr ip6;
|
||||||
|
char *error;
|
||||||
|
uint32_t plen;
|
||||||
|
|
||||||
if (ovs_scan(argv[2], IPV6_SCAN_FMT, ip6_s) &&
|
error = ipv6_parse_cidr(argv[2], &ip6, &plen);
|
||||||
inet_pton(AF_INET6, ip6_s, &ip6) == 1) {
|
if (!error) {
|
||||||
netdev_dummy_set_in6(netdev, &ip6);
|
struct in6_addr mask;
|
||||||
|
|
||||||
|
mask = ipv6_create_mask(plen);
|
||||||
|
netdev_dummy_set_in6(netdev, &ip6, &mask);
|
||||||
unixctl_command_reply(conn, "OK");
|
unixctl_command_reply(conn, "OK");
|
||||||
} else {
|
} else {
|
||||||
unixctl_command_reply_error(conn, "Invalid parameters");
|
unixctl_command_reply_error(conn, error);
|
||||||
|
free(error);
|
||||||
}
|
}
|
||||||
netdev_close(netdev);
|
netdev_close(netdev);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -483,7 +483,6 @@ struct netdev_linux {
|
|||||||
int ifindex;
|
int ifindex;
|
||||||
struct eth_addr etheraddr;
|
struct eth_addr etheraddr;
|
||||||
struct in_addr address, netmask;
|
struct in_addr address, netmask;
|
||||||
struct in6_addr in6;
|
|
||||||
int mtu;
|
int mtu;
|
||||||
unsigned int ifi_flags;
|
unsigned int ifi_flags;
|
||||||
long long int carrier_resets;
|
long long int carrier_resets;
|
||||||
@@ -727,6 +726,9 @@ netdev_linux_changed(struct netdev_linux *dev,
|
|||||||
dev->ifi_flags = ifi_flags;
|
dev->ifi_flags = ifi_flags;
|
||||||
|
|
||||||
dev->cache_valid &= mask;
|
dev->cache_valid &= mask;
|
||||||
|
if (!(mask & (VALID_IN4 | VALID_IN6))) {
|
||||||
|
netdev_get_addrs_list_flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2535,61 +2537,18 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
parse_if_inet6_line(const char *line,
|
|
||||||
struct in6_addr *in6, char ifname[16 + 1])
|
|
||||||
{
|
|
||||||
uint8_t *s6 = in6->s6_addr;
|
|
||||||
#define X8 "%2"SCNx8
|
|
||||||
return ovs_scan(line,
|
|
||||||
" "X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8
|
|
||||||
"%*x %*x %*x %*x %16s\n",
|
|
||||||
&s6[0], &s6[1], &s6[2], &s6[3],
|
|
||||||
&s6[4], &s6[5], &s6[6], &s6[7],
|
|
||||||
&s6[8], &s6[9], &s6[10], &s6[11],
|
|
||||||
&s6[12], &s6[13], &s6[14], &s6[15],
|
|
||||||
ifname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
|
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
|
||||||
* Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
|
* Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
|
||||||
* error. */
|
* error. */
|
||||||
static int
|
static int
|
||||||
netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
|
netdev_linux_get_addr_list(const struct netdev *netdev_,
|
||||||
|
struct in6_addr **addr, struct in6_addr **mask, int *n_cnt)
|
||||||
{
|
{
|
||||||
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
ovs_mutex_lock(&netdev->mutex);
|
ovs_mutex_lock(&netdev->mutex);
|
||||||
if (!(netdev->cache_valid & VALID_IN6)) {
|
error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
|
||||||
FILE *file;
|
|
||||||
char line[128];
|
|
||||||
|
|
||||||
netdev->in6 = in6addr_any;
|
|
||||||
netdev->in6_error = EADDRNOTAVAIL;
|
|
||||||
|
|
||||||
file = fopen("/proc/net/if_inet6", "r");
|
|
||||||
if (file != NULL) {
|
|
||||||
const char *name = netdev_get_name(netdev_);
|
|
||||||
while (fgets(line, sizeof line, file)) {
|
|
||||||
struct in6_addr in6_tmp;
|
|
||||||
char ifname[16 + 1];
|
|
||||||
if (parse_if_inet6_line(line, &in6_tmp, ifname)
|
|
||||||
&& !strcmp(name, ifname))
|
|
||||||
{
|
|
||||||
netdev->in6 = in6_tmp;
|
|
||||||
netdev->in6_error = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(file);
|
|
||||||
} else {
|
|
||||||
netdev->in6_error = EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
netdev->cache_valid |= VALID_IN6;
|
|
||||||
}
|
|
||||||
*in6 = netdev->in6;
|
|
||||||
error = netdev->in6_error;
|
|
||||||
ovs_mutex_unlock(&netdev->mutex);
|
ovs_mutex_unlock(&netdev->mutex);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
@@ -2891,7 +2850,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
|
|||||||
\
|
\
|
||||||
netdev_linux_get_in4, \
|
netdev_linux_get_in4, \
|
||||||
netdev_linux_set_in4, \
|
netdev_linux_set_in4, \
|
||||||
netdev_linux_get_in6, \
|
netdev_linux_get_addr_list, \
|
||||||
netdev_linux_add_router, \
|
netdev_linux_add_router, \
|
||||||
netdev_linux_get_next_hop, \
|
netdev_linux_get_next_hop, \
|
||||||
GET_STATUS, \
|
GET_STATUS, \
|
||||||
|
@@ -639,7 +639,11 @@ struct netdev_class {
|
|||||||
int (*set_in4)(struct netdev *netdev, struct in_addr addr,
|
int (*set_in4)(struct netdev *netdev, struct in_addr addr,
|
||||||
struct in_addr mask);
|
struct in_addr mask);
|
||||||
|
|
||||||
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
|
/* Returns all assigned IP address to 'netdev' and returns 0.
|
||||||
|
* API allocates array of address and masks and set it to
|
||||||
|
* '*addr' and '*mask'.
|
||||||
|
* Otherwise, returns a positive errno value and sets '*addr', '*mask
|
||||||
|
* and '*n_addr' to NULL.
|
||||||
*
|
*
|
||||||
* The following error values have well-defined meanings:
|
* The following error values have well-defined meanings:
|
||||||
*
|
*
|
||||||
@@ -647,9 +651,9 @@ struct netdev_class {
|
|||||||
*
|
*
|
||||||
* - EOPNOTSUPP: No IPv6 network stack attached to 'netdev'.
|
* - EOPNOTSUPP: No IPv6 network stack attached to 'netdev'.
|
||||||
*
|
*
|
||||||
* This function may be set to null if it would always return EOPNOTSUPP
|
* 'addr' may be null, in which case the address itself is not reported. */
|
||||||
* anyhow. */
|
int (*get_addr_list)(const struct netdev *netdev, struct in6_addr **in,
|
||||||
int (*get_in6)(const struct netdev *netdev, struct in6_addr *in6);
|
struct in6_addr **mask, int *n_in6);
|
||||||
|
|
||||||
/* Adds 'router' as a default IP gateway for the TCP/IP stack that
|
/* Adds 'router' as a default IP gateway for the TCP/IP stack that
|
||||||
* corresponds to 'netdev'.
|
* corresponds to 'netdev'.
|
||||||
|
@@ -319,7 +319,7 @@ tunnel_check_status_change__(struct netdev_vport *netdev)
|
|||||||
|
|
||||||
iface[0] = '\0';
|
iface[0] = '\0';
|
||||||
route = &netdev->tnl_cfg.ipv6_dst;
|
route = &netdev->tnl_cfg.ipv6_dst;
|
||||||
if (ovs_router_lookup(route, iface, &gw)) {
|
if (ovs_router_lookup(route, iface, NULL, &gw)) {
|
||||||
struct netdev *egress_netdev;
|
struct netdev *egress_netdev;
|
||||||
|
|
||||||
if (!netdev_open(iface, "system", &egress_netdev)) {
|
if (!netdev_open(iface, "system", &egress_netdev)) {
|
||||||
@@ -1530,7 +1530,7 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
|
|||||||
\
|
\
|
||||||
NULL, /* get_in4 */ \
|
NULL, /* get_in4 */ \
|
||||||
NULL, /* set_in4 */ \
|
NULL, /* set_in4 */ \
|
||||||
NULL, /* get_in6 */ \
|
NULL, /* get_addr_list */ \
|
||||||
NULL, /* add_router */ \
|
NULL, /* add_router */ \
|
||||||
NULL, /* get_next_hop */ \
|
NULL, /* get_next_hop */ \
|
||||||
GET_STATUS, \
|
GET_STATUS, \
|
||||||
|
127
lib/netdev.c
127
lib/netdev.c
@@ -24,6 +24,13 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "coverage.h"
|
#include "coverage.h"
|
||||||
#include "dpif.h"
|
#include "dpif.h"
|
||||||
#include "dp-packet.h"
|
#include "dp-packet.h"
|
||||||
@@ -45,6 +52,7 @@
|
|||||||
#include "svec.h"
|
#include "svec.h"
|
||||||
#include "openvswitch/vlog.h"
|
#include "openvswitch/vlog.h"
|
||||||
#include "flow.h"
|
#include "flow.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
VLOG_DEFINE_THIS_MODULE(netdev);
|
VLOG_DEFINE_THIS_MODULE(netdev);
|
||||||
|
|
||||||
@@ -1125,9 +1133,11 @@ netdev_get_status(const struct netdev *netdev, struct smap *smap)
|
|||||||
: EOPNOTSUPP);
|
: EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address and
|
/* Returns all assigned IP address to 'netdev' and returns 0.
|
||||||
* returns 0. Otherwise, returns a positive errno value and sets '*in6' to
|
* API allocates array of address and masks and set it to
|
||||||
* all-zero-bits (in6addr_any).
|
* '*addr' and '*mask'.
|
||||||
|
* Otherwise, returns a positive errno value and sets '*addr', '*mask
|
||||||
|
* and '*n_addr' to NULL.
|
||||||
*
|
*
|
||||||
* The following error values have well-defined meanings:
|
* The following error values have well-defined meanings:
|
||||||
*
|
*
|
||||||
@@ -1135,20 +1145,21 @@ netdev_get_status(const struct netdev *netdev, struct smap *smap)
|
|||||||
*
|
*
|
||||||
* - EOPNOTSUPP: No IPv6 network stack attached to 'netdev'.
|
* - EOPNOTSUPP: No IPv6 network stack attached to 'netdev'.
|
||||||
*
|
*
|
||||||
* 'in6' may be null, in which case the address itself is not reported. */
|
* 'addr' may be null, in which case the address itself is not reported. */
|
||||||
int
|
int
|
||||||
netdev_get_in6(const struct netdev *netdev, struct in6_addr *in6)
|
netdev_get_addr_list(const struct netdev *netdev, struct in6_addr **addr,
|
||||||
|
struct in6_addr **mask, int *n_addr)
|
||||||
{
|
{
|
||||||
struct in6_addr dummy;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = (netdev->netdev_class->get_in6
|
error = (netdev->netdev_class->get_addr_list
|
||||||
? netdev->netdev_class->get_in6(netdev,
|
? netdev->netdev_class->get_addr_list(netdev, addr, mask, n_addr): EOPNOTSUPP);
|
||||||
in6 ? in6 : &dummy)
|
if (error && addr) {
|
||||||
: EOPNOTSUPP);
|
*addr = NULL;
|
||||||
if (error && in6) {
|
*mask = NULL;
|
||||||
memset(in6, 0, sizeof *in6);
|
*n_addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1851,3 +1862,95 @@ netdev_get_change_seq(const struct netdev *netdev)
|
|||||||
{
|
{
|
||||||
return netdev->change_seq;
|
return netdev->change_seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* This implementation is shared by Linux and BSD. */
|
||||||
|
|
||||||
|
static struct ifaddrs *if_addr_list;
|
||||||
|
static struct ovs_mutex if_addr_list_lock = OVS_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void
|
||||||
|
netdev_get_addrs_list_flush(void)
|
||||||
|
{
|
||||||
|
ovs_mutex_lock(&if_addr_list_lock);
|
||||||
|
if (if_addr_list) {
|
||||||
|
freeifaddrs(if_addr_list);
|
||||||
|
if_addr_list = NULL;
|
||||||
|
}
|
||||||
|
ovs_mutex_unlock(&if_addr_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
netdev_get_addrs(const char dev[], struct in6_addr **paddr,
|
||||||
|
struct in6_addr **pmask, int *n_in)
|
||||||
|
{
|
||||||
|
struct in6_addr *addr_array, *mask_array;
|
||||||
|
const struct ifaddrs *ifa;
|
||||||
|
int cnt = 0, i = 0;
|
||||||
|
|
||||||
|
ovs_mutex_lock(&if_addr_list_lock);
|
||||||
|
if (!if_addr_list) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = getifaddrs(&if_addr_list);
|
||||||
|
if (err) {
|
||||||
|
ovs_mutex_unlock(&if_addr_list_lock);
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ifa = if_addr_list; ifa; ifa = ifa->ifa_next) {
|
||||||
|
int family;
|
||||||
|
|
||||||
|
family = ifa->ifa_addr->sa_family;
|
||||||
|
if (family == AF_INET || family == AF_INET6) {
|
||||||
|
if (!strncmp(ifa->ifa_name, dev, IFNAMSIZ)) {
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cnt) {
|
||||||
|
ovs_mutex_unlock(&if_addr_list_lock);
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
}
|
||||||
|
addr_array = xzalloc(sizeof *addr_array * cnt);
|
||||||
|
mask_array = xzalloc(sizeof *mask_array * cnt);
|
||||||
|
for (ifa = if_addr_list; ifa; ifa = ifa->ifa_next) {
|
||||||
|
int family;
|
||||||
|
|
||||||
|
if (strncmp(ifa->ifa_name, dev, IFNAMSIZ)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
family = ifa->ifa_addr->sa_family;
|
||||||
|
if (family == AF_INET) {
|
||||||
|
const struct sockaddr_in *sin;
|
||||||
|
|
||||||
|
sin = ALIGNED_CAST(const struct sockaddr_in *, ifa->ifa_addr);
|
||||||
|
in6_addr_set_mapped_ipv4(&addr_array[i], sin->sin_addr.s_addr);
|
||||||
|
sin = (struct sockaddr_in *) &ifa->ifa_netmask;
|
||||||
|
in6_addr_set_mapped_ipv4(&mask_array[i], sin->sin_addr.s_addr);
|
||||||
|
i++;
|
||||||
|
} else if (family == AF_INET6) {
|
||||||
|
const struct sockaddr_in6 *sin6;
|
||||||
|
|
||||||
|
sin6 = ALIGNED_CAST(const struct sockaddr_in6 *, ifa->ifa_addr);
|
||||||
|
memcpy(&addr_array[i], &sin6->sin6_addr, sizeof *addr_array);
|
||||||
|
sin6 = (struct sockaddr_in6 *) &ifa->ifa_netmask;
|
||||||
|
memcpy(&mask_array[i], &sin6->sin6_addr, sizeof *mask_array);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ovs_mutex_unlock(&if_addr_list_lock);
|
||||||
|
if (paddr) {
|
||||||
|
*n_in = cnt;
|
||||||
|
*paddr = addr_array;
|
||||||
|
*pmask = mask_array;
|
||||||
|
} else {
|
||||||
|
free(addr_array);
|
||||||
|
free(mask_array);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
10
lib/netdev.h
10
lib/netdev.h
@@ -256,7 +256,9 @@ int netdev_get_in4(const struct netdev *, struct in_addr *address,
|
|||||||
struct in_addr *netmask);
|
struct in_addr *netmask);
|
||||||
int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask);
|
int netdev_set_in4(struct netdev *, struct in_addr addr, struct in_addr mask);
|
||||||
int netdev_get_in4_by_name(const char *device_name, struct in_addr *in4);
|
int netdev_get_in4_by_name(const char *device_name, struct in_addr *in4);
|
||||||
int netdev_get_in6(const struct netdev *, struct in6_addr *);
|
int netdev_get_addr_list(const struct netdev *netdev, struct in6_addr **addr,
|
||||||
|
struct in6_addr **mask, int *n_in6);
|
||||||
|
|
||||||
int netdev_add_router(struct netdev *, struct in_addr router);
|
int netdev_add_router(struct netdev *, struct in_addr router);
|
||||||
int netdev_get_next_hop(const struct netdev *, const struct in_addr *host,
|
int netdev_get_next_hop(const struct netdev *, const struct in_addr *host,
|
||||||
struct in_addr *next_hop, char **);
|
struct in_addr *next_hop, char **);
|
||||||
@@ -343,6 +345,12 @@ int netdev_dump_queue_stats(const struct netdev *,
|
|||||||
enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */
|
enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */
|
||||||
extern struct seq *tnl_conf_seq;
|
extern struct seq *tnl_conf_seq;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
void netdev_get_addrs_list_flush(void);
|
||||||
|
int netdev_get_addrs(const char dev[], struct in6_addr **paddr,
|
||||||
|
struct in6_addr **pmask, int *n_in6);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -42,6 +42,9 @@
|
|||||||
#include "tnl-ports.h"
|
#include "tnl-ports.h"
|
||||||
#include "unixctl.h"
|
#include "unixctl.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "unaligned.h"
|
||||||
|
#include "unixctl.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
|
static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
|
||||||
static struct classifier cls;
|
static struct classifier cls;
|
||||||
@@ -51,6 +54,7 @@ struct ovs_router_entry {
|
|||||||
char output_bridge[IFNAMSIZ];
|
char output_bridge[IFNAMSIZ];
|
||||||
struct in6_addr gw;
|
struct in6_addr gw;
|
||||||
struct in6_addr nw_addr;
|
struct in6_addr nw_addr;
|
||||||
|
struct in6_addr src_addr;
|
||||||
uint8_t plen;
|
uint8_t plen;
|
||||||
uint8_t priority;
|
uint8_t priority;
|
||||||
};
|
};
|
||||||
@@ -67,7 +71,7 @@ ovs_router_entry_cast(const struct cls_rule *cr)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
|
ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
|
||||||
struct in6_addr *gw)
|
struct in6_addr *src, struct in6_addr *gw)
|
||||||
{
|
{
|
||||||
const struct cls_rule *cr;
|
const struct cls_rule *cr;
|
||||||
struct flow flow = {.ipv6_dst = *ip6_dst};
|
struct flow flow = {.ipv6_dst = *ip6_dst};
|
||||||
@@ -78,6 +82,9 @@ ovs_router_lookup(const struct in6_addr *ip6_dst, char output_bridge[],
|
|||||||
|
|
||||||
ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
|
ovs_strlcpy(output_bridge, p->output_bridge, IFNAMSIZ);
|
||||||
*gw = p->gw;
|
*gw = p->gw;
|
||||||
|
if (src) {
|
||||||
|
*src = p->src_addr;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -89,7 +96,7 @@ ovs_router_lookup4(ovs_be32 ip_dst, char output_bridge[], ovs_be32 *gw)
|
|||||||
struct in6_addr ip6_dst = in6_addr_mapped_ipv4(ip_dst);
|
struct in6_addr ip6_dst = in6_addr_mapped_ipv4(ip_dst);
|
||||||
struct in6_addr gw6;
|
struct in6_addr gw6;
|
||||||
|
|
||||||
if (ovs_router_lookup(&ip6_dst, output_bridge, &gw6)) {
|
if (ovs_router_lookup(&ip6_dst, output_bridge, NULL, &gw6)) {
|
||||||
*gw = in6_addr_get_mapped_ipv4(&gw6);
|
*gw = in6_addr_get_mapped_ipv4(&gw6);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -117,7 +124,48 @@ static void rt_init_match(struct match *match, const struct in6_addr *ip6_dst,
|
|||||||
match->wc.masks.ipv6_dst = mask;
|
match->wc.masks.ipv6_dst = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
|
get_src_addr(const struct in6_addr *ip6_dst,
|
||||||
|
const char output_bridge[], struct in6_addr *psrc)
|
||||||
|
{
|
||||||
|
struct in6_addr *mask, *addr6;
|
||||||
|
int err, n_in6, i, max_plen = -1;
|
||||||
|
struct netdev *dev;
|
||||||
|
|
||||||
|
err = netdev_open(output_bridge, NULL, &dev);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = netdev_get_addr_list(dev, &addr6, &mask, &n_in6);
|
||||||
|
if (err) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n_in6; i++) {
|
||||||
|
struct in6_addr a1, a2;
|
||||||
|
int mask_bits;
|
||||||
|
|
||||||
|
a1 = ipv6_addr_bitand(ip6_dst, &mask[i]);
|
||||||
|
a2 = ipv6_addr_bitand(&addr6[i], &mask[i]);
|
||||||
|
mask_bits = bitmap_count1(ALIGNED_CAST(const unsigned long *, &mask[i]), 128);
|
||||||
|
|
||||||
|
if (!memcmp(&a1, &a2, sizeof (a1)) && mask_bits > max_plen) {
|
||||||
|
*psrc = addr6[i];
|
||||||
|
max_plen = mask_bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (max_plen == -1) {
|
||||||
|
err = ENOENT;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
free(addr6);
|
||||||
|
free(mask);
|
||||||
|
netdev_close(dev);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
|
ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
|
||||||
uint8_t plen, const char output_bridge[],
|
uint8_t plen, const char output_bridge[],
|
||||||
const struct in6_addr *gw)
|
const struct in6_addr *gw)
|
||||||
@@ -125,6 +173,7 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
|
|||||||
const struct cls_rule *cr;
|
const struct cls_rule *cr;
|
||||||
struct ovs_router_entry *p;
|
struct ovs_router_entry *p;
|
||||||
struct match match;
|
struct match match;
|
||||||
|
int err;
|
||||||
|
|
||||||
rt_init_match(&match, ip6_dst, plen);
|
rt_init_match(&match, ip6_dst, plen);
|
||||||
|
|
||||||
@@ -136,6 +185,10 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
|
|||||||
p->nw_addr = match.flow.ipv6_dst;
|
p->nw_addr = match.flow.ipv6_dst;
|
||||||
p->plen = plen;
|
p->plen = plen;
|
||||||
p->priority = priority;
|
p->priority = priority;
|
||||||
|
err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
/* Longest prefix matches first. */
|
/* Longest prefix matches first. */
|
||||||
cls_rule_init(&p->cr, &match, priority);
|
cls_rule_init(&p->cr, &match, priority);
|
||||||
|
|
||||||
@@ -149,6 +202,7 @@ ovs_router_insert__(uint8_t priority, const struct in6_addr *ip6_dst,
|
|||||||
}
|
}
|
||||||
tnl_port_map_insert_ipdev(output_bridge);
|
tnl_port_map_insert_ipdev(output_bridge);
|
||||||
seq_change(tnl_conf_seq);
|
seq_change(tnl_conf_seq);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -226,6 +280,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
|
|||||||
unsigned int plen;
|
unsigned int plen;
|
||||||
struct in6_addr ip6;
|
struct in6_addr ip6;
|
||||||
struct in6_addr gw6;
|
struct in6_addr gw6;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (scan_ipv4_route(argv[1], &ip, &plen)) {
|
if (scan_ipv4_route(argv[1], &ip, &plen)) {
|
||||||
ovs_be32 gw = 0;
|
ovs_be32 gw = 0;
|
||||||
@@ -246,8 +301,12 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
|
|||||||
unixctl_command_reply_error(conn, "Invalid parameters");
|
unixctl_command_reply_error(conn, "Invalid parameters");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
|
err = ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
|
||||||
unixctl_command_reply(conn, "OK");
|
if (err) {
|
||||||
|
unixctl_command_reply(conn, "Error while inserting route.");
|
||||||
|
} else {
|
||||||
|
unixctl_command_reply(conn, "OK");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -298,6 +357,8 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|||||||
ds_put_format(&ds, " GW ");
|
ds_put_format(&ds, " GW ");
|
||||||
ipv6_format_mapped(&rt->gw, &ds);
|
ipv6_format_mapped(&rt->gw, &ds);
|
||||||
}
|
}
|
||||||
|
ds_put_format(&ds, " SRC ");
|
||||||
|
ipv6_format_mapped(&rt->src_addr, &ds);
|
||||||
ds_put_format(&ds, "\n");
|
ds_put_format(&ds, "\n");
|
||||||
}
|
}
|
||||||
unixctl_command_reply(conn, ds_cstr(&ds));
|
unixctl_command_reply(conn, ds_cstr(&ds));
|
||||||
@@ -312,7 +373,7 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|||||||
struct in6_addr ip6;
|
struct in6_addr ip6;
|
||||||
unsigned int plen;
|
unsigned int plen;
|
||||||
char iface[IFNAMSIZ];
|
char iface[IFNAMSIZ];
|
||||||
struct in6_addr gw;
|
struct in6_addr gw, src;
|
||||||
|
|
||||||
if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
|
if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
|
||||||
in6_addr_set_mapped_ipv4(&ip6, ip);
|
in6_addr_set_mapped_ipv4(&ip6, ip);
|
||||||
@@ -321,10 +382,12 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ovs_router_lookup(&ip6, iface, &gw)) {
|
if (ovs_router_lookup(&ip6, iface, &src, &gw)) {
|
||||||
struct ds ds = DS_EMPTY_INITIALIZER;
|
struct ds ds = DS_EMPTY_INITIALIZER;
|
||||||
|
ds_put_format(&ds, "src ");
|
||||||
|
ipv6_format_mapped(&src, &ds);
|
||||||
ds_put_format(&ds, "gateway ");
|
ds_put_format(&ds, "gateway ");
|
||||||
ipv6_format_mapped(&ip6, &ds);
|
ipv6_format_mapped(&gw, &ds);
|
||||||
ds_put_format(&ds, "\ndev %s\n", iface);
|
ds_put_format(&ds, "\ndev %s\n", iface);
|
||||||
unixctl_command_reply(conn, ds_cstr(&ds));
|
unixctl_command_reply(conn, ds_cstr(&ds));
|
||||||
ds_destroy(&ds);
|
ds_destroy(&ds);
|
||||||
|
@@ -26,7 +26,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool ovs_router_lookup(const struct in6_addr *ip_dst, char out_dev[],
|
bool ovs_router_lookup(const struct in6_addr *ip_dst, char out_dev[],
|
||||||
struct in6_addr *gw);
|
struct in6_addr *src, struct in6_addr *gw);
|
||||||
bool ovs_router_lookup4(ovs_be32 ip_dst, char out_dev[], ovs_be32 *gw);
|
bool ovs_router_lookup4(ovs_be32 ip_dst, char out_dev[], ovs_be32 *gw);
|
||||||
void ovs_router_init(void);
|
void ovs_router_init(void);
|
||||||
void ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,
|
void ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,
|
||||||
|
@@ -276,8 +276,6 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
|
|||||||
change->rd.rta_gw = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
|
change->rd.rta_gw = nl_attr_get_in6_addr(attrs[RTA_GATEWAY]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
|
VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
|
||||||
}
|
}
|
||||||
|
134
lib/tnl-ports.c
134
lib/tnl-ports.c
@@ -40,8 +40,8 @@ static struct classifier cls; /* Tunnel ports. */
|
|||||||
struct ip_device {
|
struct ip_device {
|
||||||
struct netdev *dev;
|
struct netdev *dev;
|
||||||
struct eth_addr mac;
|
struct eth_addr mac;
|
||||||
ovs_be32 addr4;
|
struct in6_addr *addr;
|
||||||
struct in6_addr addr6;
|
int n_addr;
|
||||||
uint64_t change_seq;
|
uint64_t change_seq;
|
||||||
struct ovs_list node;
|
struct ovs_list node;
|
||||||
char dev_name[IFNAMSIZ];
|
char dev_name[IFNAMSIZ];
|
||||||
@@ -150,6 +150,20 @@ map_insert(odp_port_t port, struct eth_addr mac, struct in6_addr *addr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
map_insert_ipdev__(struct ip_device *ip_dev, char dev_name[],
|
||||||
|
odp_port_t port, ovs_be16 udp_port)
|
||||||
|
{
|
||||||
|
if (ip_dev->n_addr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ip_dev->n_addr; i++) {
|
||||||
|
map_insert(port, ip_dev->mac, &ip_dev->addr[i],
|
||||||
|
udp_port, dev_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tnl_port_map_insert(odp_port_t port,
|
tnl_port_map_insert(odp_port_t port,
|
||||||
ovs_be16 udp_port, const char dev_name[])
|
ovs_be16 udp_port, const char dev_name[])
|
||||||
@@ -171,15 +185,7 @@ tnl_port_map_insert(odp_port_t port,
|
|||||||
list_insert(&port_list, &p->node);
|
list_insert(&port_list, &p->node);
|
||||||
|
|
||||||
LIST_FOR_EACH(ip_dev, node, &addr_list) {
|
LIST_FOR_EACH(ip_dev, node, &addr_list) {
|
||||||
if (ip_dev->addr4 != INADDR_ANY) {
|
map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->udp_port);
|
||||||
struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
|
|
||||||
map_insert(p->port, ip_dev->mac, &addr4,
|
|
||||||
p->udp_port, p->dev_name);
|
|
||||||
}
|
|
||||||
if (ipv6_addr_is_set(&ip_dev->addr6)) {
|
|
||||||
map_insert(p->port, ip_dev->mac, &ip_dev->addr6,
|
|
||||||
p->udp_port, p->dev_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -210,6 +216,18 @@ map_delete(struct eth_addr mac, struct in6_addr *addr, ovs_be16 udp_port)
|
|||||||
tnl_port_unref(cr);
|
tnl_port_unref(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ipdev_map_delete(struct ip_device *ip_dev, ovs_be16 udp_port)
|
||||||
|
{
|
||||||
|
if (ip_dev->n_addr) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ip_dev->n_addr; i++) {
|
||||||
|
map_delete(ip_dev->mac, &ip_dev->addr[i], udp_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tnl_port_map_delete(ovs_be16 udp_port)
|
tnl_port_map_delete(ovs_be16 udp_port)
|
||||||
{
|
{
|
||||||
@@ -230,13 +248,7 @@ tnl_port_map_delete(ovs_be16 udp_port)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
LIST_FOR_EACH(ip_dev, node, &addr_list) {
|
LIST_FOR_EACH(ip_dev, node, &addr_list) {
|
||||||
if (ip_dev->addr4 != INADDR_ANY) {
|
ipdev_map_delete(ip_dev, p->udp_port);
|
||||||
struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
|
|
||||||
map_delete(ip_dev->mac, &addr4, udp_port);
|
|
||||||
}
|
|
||||||
if (ipv6_addr_is_set(&ip_dev->addr6)) {
|
|
||||||
map_delete(ip_dev->mac, &ip_dev->addr6, udp_port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(p);
|
free(p);
|
||||||
@@ -331,56 +343,64 @@ map_insert_ipdev(struct ip_device *ip_dev)
|
|||||||
struct tnl_port *p;
|
struct tnl_port *p;
|
||||||
|
|
||||||
LIST_FOR_EACH(p, node, &port_list) {
|
LIST_FOR_EACH(p, node, &port_list) {
|
||||||
if (ip_dev->addr4 != INADDR_ANY) {
|
map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->udp_port);
|
||||||
struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
|
|
||||||
map_insert(p->port, ip_dev->mac, &addr4,
|
|
||||||
p->udp_port, p->dev_name);
|
|
||||||
}
|
|
||||||
if (ipv6_addr_is_set(&ip_dev->addr6)) {
|
|
||||||
map_insert(p->port, ip_dev->mac, &ip_dev->addr6,
|
|
||||||
p->udp_port, p->dev_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_ipdev__(struct netdev *dev,
|
||||||
|
struct in6_addr *addr, int n_addr)
|
||||||
|
{
|
||||||
|
struct ip_device *ip_dev;
|
||||||
|
enum netdev_flags flags;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = netdev_get_flags(dev, &flags);
|
||||||
|
if (error || (flags & NETDEV_LOOPBACK)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_dev = xzalloc(sizeof *ip_dev);
|
||||||
|
ip_dev->dev = netdev_ref(dev);
|
||||||
|
ip_dev->change_seq = netdev_get_change_seq(dev);
|
||||||
|
error = netdev_get_etheraddr(ip_dev->dev, &ip_dev->mac);
|
||||||
|
if (error) {
|
||||||
|
goto err_free_ipdev;
|
||||||
|
}
|
||||||
|
ip_dev->addr = addr;
|
||||||
|
ip_dev->n_addr = n_addr;
|
||||||
|
ovs_strlcpy(ip_dev->dev_name, netdev_get_name(dev), sizeof ip_dev->dev_name);
|
||||||
|
list_insert(&addr_list, &ip_dev->node);
|
||||||
|
map_insert_ipdev(ip_dev);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_free_ipdev:
|
||||||
|
netdev_close(ip_dev->dev);
|
||||||
|
free(ip_dev);
|
||||||
|
err:
|
||||||
|
free(addr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
insert_ipdev(const char dev_name[])
|
insert_ipdev(const char dev_name[])
|
||||||
{
|
{
|
||||||
struct ip_device *ip_dev;
|
struct in6_addr *addr, *mask;
|
||||||
enum netdev_flags flags;
|
|
||||||
struct netdev *dev;
|
struct netdev *dev;
|
||||||
int error;
|
int error, n_in6;
|
||||||
int error4, error6;
|
|
||||||
|
|
||||||
error = netdev_open(dev_name, NULL, &dev);
|
error = netdev_open(dev_name, NULL, &dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = netdev_get_flags(dev, &flags);
|
error = netdev_get_addr_list(dev, &addr, &mask, &n_in6);
|
||||||
if (error || (flags & NETDEV_LOOPBACK)) {
|
if (error) {
|
||||||
netdev_close(dev);
|
netdev_close(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
free(mask);
|
||||||
ip_dev = xzalloc(sizeof *ip_dev);
|
insert_ipdev__(dev, addr, n_in6);
|
||||||
ip_dev->dev = dev;
|
netdev_close(dev);
|
||||||
ip_dev->change_seq = netdev_get_change_seq(dev);
|
|
||||||
error = netdev_get_etheraddr(ip_dev->dev, &ip_dev->mac);
|
|
||||||
if (error) {
|
|
||||||
free(ip_dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
error4 = netdev_get_in4(ip_dev->dev, (struct in_addr *)&ip_dev->addr4, NULL);
|
|
||||||
error6 = netdev_get_in6(ip_dev->dev, &ip_dev->addr6);
|
|
||||||
if (error4 && error6) {
|
|
||||||
free(ip_dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ovs_strlcpy(ip_dev->dev_name, netdev_get_name(dev), sizeof ip_dev->dev_name);
|
|
||||||
|
|
||||||
list_insert(&addr_list, &ip_dev->node);
|
|
||||||
map_insert_ipdev(ip_dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -389,17 +409,12 @@ delete_ipdev(struct ip_device *ip_dev)
|
|||||||
struct tnl_port *p;
|
struct tnl_port *p;
|
||||||
|
|
||||||
LIST_FOR_EACH(p, node, &port_list) {
|
LIST_FOR_EACH(p, node, &port_list) {
|
||||||
if (ip_dev->addr4 != INADDR_ANY) {
|
ipdev_map_delete(ip_dev, p->udp_port);
|
||||||
struct in6_addr addr4 = in6_addr_mapped_ipv4(ip_dev->addr4);
|
|
||||||
map_delete(ip_dev->mac, &addr4, p->udp_port);
|
|
||||||
}
|
|
||||||
if (ipv6_addr_is_set(&ip_dev->addr6)) {
|
|
||||||
map_delete(ip_dev->mac, &ip_dev->addr6, p->udp_port);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list_remove(&ip_dev->node);
|
list_remove(&ip_dev->node);
|
||||||
netdev_close(ip_dev->dev);
|
netdev_close(ip_dev->dev);
|
||||||
|
free(ip_dev->addr);
|
||||||
free(ip_dev);
|
free(ip_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +432,6 @@ tnl_port_map_insert_ipdev(const char dev_name[])
|
|||||||
}
|
}
|
||||||
/* Address changed. */
|
/* Address changed. */
|
||||||
delete_ipdev(ip_dev);
|
delete_ipdev(ip_dev);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insert_ipdev(dev_name);
|
insert_ipdev(dev_name);
|
||||||
|
@@ -2750,7 +2750,8 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
tnl_route_lookup_flow(const struct flow *oflow,
|
tnl_route_lookup_flow(const struct flow *oflow,
|
||||||
struct in6_addr *ip, struct xport **out_port)
|
struct in6_addr *ip, struct in6_addr *src,
|
||||||
|
struct xport **out_port)
|
||||||
{
|
{
|
||||||
char out_dev[IFNAMSIZ];
|
char out_dev[IFNAMSIZ];
|
||||||
struct xbridge *xbridge;
|
struct xbridge *xbridge;
|
||||||
@@ -2759,7 +2760,7 @@ tnl_route_lookup_flow(const struct flow *oflow,
|
|||||||
struct in6_addr dst;
|
struct in6_addr dst;
|
||||||
|
|
||||||
dst = flow_tnl_dst(&oflow->tunnel);
|
dst = flow_tnl_dst(&oflow->tunnel);
|
||||||
if (!ovs_router_lookup(&dst, out_dev, &gw)) {
|
if (!ovs_router_lookup(&dst, out_dev, src, &gw)) {
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2850,7 +2851,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
|
|||||||
char buf_sip6[INET6_ADDRSTRLEN];
|
char buf_sip6[INET6_ADDRSTRLEN];
|
||||||
char buf_dip6[INET6_ADDRSTRLEN];
|
char buf_dip6[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
err = tnl_route_lookup_flow(flow, &d_ip6, &out_dev);
|
err = tnl_route_lookup_flow(flow, &d_ip6, &s_ip6, &out_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
xlate_report(ctx, "native tunnel routing failed");
|
xlate_report(ctx, "native tunnel routing failed");
|
||||||
return err;
|
return err;
|
||||||
@@ -2869,18 +2870,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
|
|||||||
|
|
||||||
d_ip = in6_addr_get_mapped_ipv4(&d_ip6);
|
d_ip = in6_addr_get_mapped_ipv4(&d_ip6);
|
||||||
if (d_ip) {
|
if (d_ip) {
|
||||||
err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL);
|
s_ip = in6_addr_get_mapped_ipv4(&s_ip6);
|
||||||
if (err) {
|
|
||||||
xlate_report(ctx, "tunnel output device lacks IPv4 address");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
in6_addr_set_mapped_ipv4(&s_ip6, s_ip);
|
|
||||||
} else {
|
|
||||||
err = netdev_get_in6(out_dev->netdev, &s_ip6);
|
|
||||||
if (err) {
|
|
||||||
xlate_report(ctx, "tunnel output device lacks IPv6 address");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
|
err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
|
||||||
|
@@ -5476,12 +5476,10 @@ dummy@ovs-dummy: hit:0 missed:0
|
|||||||
])
|
])
|
||||||
|
|
||||||
dnl set up route to 1.1.2.92 via br0 and action=normal
|
dnl set up route to 1.1.2.92 via br0 and action=normal
|
||||||
AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK
|
|
||||||
])
|
|
||||||
AT_CHECK([ovs-appctl ovs/route/add 192.168.0.0/16 br0], [0], [OK
|
|
||||||
])
|
|
||||||
AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK
|
AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK
|
||||||
])
|
])
|
||||||
|
AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK
|
||||||
|
])
|
||||||
AT_CHECK([ovs-ofctl add-flow br0 action=normal])
|
AT_CHECK([ovs-ofctl add-flow br0 action=normal])
|
||||||
|
|
||||||
dnl Prime ARP Cache for 1.1.2.92
|
dnl Prime ARP Cache for 1.1.2.92
|
||||||
@@ -5493,6 +5491,12 @@ ovs-vsctl \
|
|||||||
--id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
|
--id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
|
||||||
header=128 sampling=1 polling=0
|
header=128 sampling=1 polling=0
|
||||||
|
|
||||||
|
dnl set up route to 192.168.1.2 via br0
|
||||||
|
AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.168.1.1/16], [0], [OK
|
||||||
|
])
|
||||||
|
AT_CHECK([ovs-appctl ovs/route/add 192.168.0.0/16 br0], [0], [OK
|
||||||
|
])
|
||||||
|
|
||||||
dnl add rule for int-br to force packet onto tunnel. There is no ifindex
|
dnl add rule for int-br to force packet onto tunnel. There is no ifindex
|
||||||
dnl for this port so the sFlow output will just report that it went to
|
dnl for this port so the sFlow output will just report that it went to
|
||||||
dnl 1 output (out_format=2, out_ifindex=1)
|
dnl 1 output (out_format=2, out_ifindex=1)
|
||||||
|
@@ -4963,8 +4963,7 @@ collect_splinter_vlans(const struct ovsrec_open_vswitch *ovs_cfg)
|
|||||||
struct netdev *netdev;
|
struct netdev *netdev;
|
||||||
|
|
||||||
if (!netdev_open(vlan_dev->name, "system", &netdev)) {
|
if (!netdev_open(vlan_dev->name, "system", &netdev)) {
|
||||||
if (!netdev_get_in4(netdev, NULL, NULL) ||
|
if (!netdev_get_addr_list(netdev, NULL, NULL, NULL)) {
|
||||||
!netdev_get_in6(netdev, NULL)) {
|
|
||||||
/* It has an IP address configured, so we don't own
|
/* It has an IP address configured, so we don't own
|
||||||
* it. Don't delete it. */
|
* it. Don't delete it. */
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user