2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-30 22:05:19 +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:
Pravin B Shelar
2016-03-24 09:30:57 -07:00
parent c4bee4cbdb
commit a8704b5027
15 changed files with 366 additions and 200 deletions

View File

@@ -93,7 +93,6 @@ struct netdev_bsd {
struct eth_addr etheraddr;
struct in_addr in4;
struct in_addr netmask;
struct in6_addr in6;
int mtu;
int carrier;
@@ -1245,37 +1244,20 @@ netdev_bsd_set_in4(struct netdev *netdev_, struct in_addr addr,
}
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_);
int error;
if (!(netdev->cache_valid & VALID_IN6)) {
struct ifaddrs *ifa, *head;
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;
netdev_get_addrs_list_flush();
}
*in6 = netdev->in6;
return 0;
error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
if (!error) {
netdev->cache_valid |= VALID_IN6;
}
return error;
}
#if defined(__NetBSD__)
@@ -1597,7 +1579,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
\
netdev_bsd_get_in4, \
netdev_bsd_set_in4, \
netdev_bsd_get_in6, \
netdev_bsd_get_addr_list, \
NULL, /* add_router */ \
netdev_bsd_get_next_hop, \
NULL, /* get_status */ \

View File

@@ -2693,7 +2693,7 @@ static const struct dpdk_qos_ops egress_policer_ops = {
\
NULL, /* get_in4 */ \
NULL, /* set_in4 */ \
NULL, /* get_in6 */ \
NULL, /* get_addr_list */ \
NULL, /* add_router */ \
NULL, /* get_next_hop */ \
GET_STATUS, \

View File

@@ -116,7 +116,7 @@ struct netdev_dummy {
FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
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. */
};
@@ -731,15 +731,50 @@ netdev_dummy_get_in4(const struct netdev *netdev_,
}
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_);
int cnt = 0, i = 0, err = 0;
struct in6_addr *addr, *mask;
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);
return ipv6_addr_is_set(in6) ? 0 : EADDRNOTAVAIL;
return err;
}
static int
@@ -757,12 +792,14 @@ netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
}
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_);
ovs_mutex_lock(&netdev->mutex);
netdev->ipv6 = *in6;
netdev->ipv6_mask = *mask;
ovs_mutex_unlock(&netdev->mutex);
return 0;
@@ -1245,7 +1282,7 @@ static const struct netdev_class dummy_class = {
netdev_dummy_get_in4, /* get_in4 */
NULL, /* set_in4 */
netdev_dummy_get_in6, /* get_in6 */
netdev_dummy_get_addr_list,
NULL, /* add_router */
NULL, /* get_next_hop */
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]);
if (netdev && is_dummy_class(netdev->netdev_class)) {
char ip6_s[IPV6_SCAN_LEN + 1];
struct in6_addr ip6;
char *error;
uint32_t plen;
if (ovs_scan(argv[2], IPV6_SCAN_FMT, ip6_s) &&
inet_pton(AF_INET6, ip6_s, &ip6) == 1) {
netdev_dummy_set_in6(netdev, &ip6);
error = ipv6_parse_cidr(argv[2], &ip6, &plen);
if (!error) {
struct in6_addr mask;
mask = ipv6_create_mask(plen);
netdev_dummy_set_in6(netdev, &ip6, &mask);
unixctl_command_reply(conn, "OK");
} else {
unixctl_command_reply_error(conn, "Invalid parameters");
unixctl_command_reply_error(conn, error);
free(error);
}
netdev_close(netdev);
} else {

View File

@@ -483,7 +483,6 @@ struct netdev_linux {
int ifindex;
struct eth_addr etheraddr;
struct in_addr address, netmask;
struct in6_addr in6;
int mtu;
unsigned int ifi_flags;
long long int carrier_resets;
@@ -727,6 +726,9 @@ netdev_linux_changed(struct netdev_linux *dev,
dev->ifi_flags = ifi_flags;
dev->cache_valid &= mask;
if (!(mask & (VALID_IN4 | VALID_IN6))) {
netdev_get_addrs_list_flush();
}
}
static void
@@ -2535,61 +2537,18 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address,
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.
* Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
* error. */
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_);
int error;
ovs_mutex_lock(&netdev->mutex);
if (!(netdev->cache_valid & VALID_IN6)) {
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;
error = netdev_get_addrs(netdev_get_name(netdev_), addr, mask, n_cnt);
ovs_mutex_unlock(&netdev->mutex);
return error;
@@ -2891,7 +2850,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
\
netdev_linux_get_in4, \
netdev_linux_set_in4, \
netdev_linux_get_in6, \
netdev_linux_get_addr_list, \
netdev_linux_add_router, \
netdev_linux_get_next_hop, \
GET_STATUS, \

View File

@@ -639,7 +639,11 @@ struct netdev_class {
int (*set_in4)(struct netdev *netdev, struct in_addr addr,
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:
*
@@ -647,9 +651,9 @@ struct netdev_class {
*
* - EOPNOTSUPP: No IPv6 network stack attached to 'netdev'.
*
* This function may be set to null if it would always return EOPNOTSUPP
* anyhow. */
int (*get_in6)(const struct netdev *netdev, struct in6_addr *in6);
* 'addr' may be null, in which case the address itself is not reported. */
int (*get_addr_list)(const struct netdev *netdev, struct in6_addr **in,
struct in6_addr **mask, int *n_in6);
/* Adds 'router' as a default IP gateway for the TCP/IP stack that
* corresponds to 'netdev'.

View File

@@ -319,7 +319,7 @@ tunnel_check_status_change__(struct netdev_vport *netdev)
iface[0] = '\0';
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;
if (!netdev_open(iface, "system", &egress_netdev)) {
@@ -1530,7 +1530,7 @@ netdev_vport_range(struct unixctl_conn *conn, int argc,
\
NULL, /* get_in4 */ \
NULL, /* set_in4 */ \
NULL, /* get_in6 */ \
NULL, /* get_addr_list */ \
NULL, /* add_router */ \
NULL, /* get_next_hop */ \
GET_STATUS, \

View File

@@ -24,6 +24,13 @@
#include <string.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 "dpif.h"
#include "dp-packet.h"
@@ -45,6 +52,7 @@
#include "svec.h"
#include "openvswitch/vlog.h"
#include "flow.h"
#include "util.h"
VLOG_DEFINE_THIS_MODULE(netdev);
@@ -1125,9 +1133,11 @@ netdev_get_status(const struct netdev *netdev, struct smap *smap)
: EOPNOTSUPP);
}
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address and
* returns 0. Otherwise, returns a positive errno value and sets '*in6' to
* all-zero-bits (in6addr_any).
/* 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:
*
@@ -1135,20 +1145,21 @@ netdev_get_status(const struct netdev *netdev, struct smap *smap)
*
* - 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
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;
error = (netdev->netdev_class->get_in6
? netdev->netdev_class->get_in6(netdev,
in6 ? in6 : &dummy)
: EOPNOTSUPP);
if (error && in6) {
memset(in6, 0, sizeof *in6);
error = (netdev->netdev_class->get_addr_list
? netdev->netdev_class->get_addr_list(netdev, addr, mask, n_addr): EOPNOTSUPP);
if (error && addr) {
*addr = NULL;
*mask = NULL;
*n_addr = 0;
}
return error;
}
@@ -1851,3 +1862,95 @@ netdev_get_change_seq(const struct netdev *netdev)
{
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

View File

@@ -256,7 +256,9 @@ int netdev_get_in4(const struct netdev *, struct in_addr *address,
struct in_addr *netmask);
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_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_get_next_hop(const struct netdev *, const struct in_addr *host,
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. */
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
}
#endif

View File

@@ -42,6 +42,9 @@
#include "tnl-ports.h"
#include "unixctl.h"
#include "util.h"
#include "unaligned.h"
#include "unixctl.h"
#include "util.h"
static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
static struct classifier cls;
@@ -51,6 +54,7 @@ struct ovs_router_entry {
char output_bridge[IFNAMSIZ];
struct in6_addr gw;
struct in6_addr nw_addr;
struct in6_addr src_addr;
uint8_t plen;
uint8_t priority;
};
@@ -67,7 +71,7 @@ ovs_router_entry_cast(const struct cls_rule *cr)
bool
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;
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);
*gw = p->gw;
if (src) {
*src = p->src_addr;
}
return true;
}
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 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);
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;
}
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,
uint8_t plen, const char output_bridge[],
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;
struct ovs_router_entry *p;
struct match match;
int err;
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->plen = plen;
p->priority = priority;
err = get_src_addr(ip6_dst, output_bridge, &p->src_addr);
if (err) {
return err;
}
/* Longest prefix matches first. */
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);
seq_change(tnl_conf_seq);
return 0;
}
void
@@ -226,6 +280,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
unsigned int plen;
struct in6_addr ip6;
struct in6_addr gw6;
int err;
if (scan_ipv4_route(argv[1], &ip, &plen)) {
ovs_be32 gw = 0;
@@ -246,8 +301,12 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
unixctl_command_reply_error(conn, "Invalid parameters");
return;
}
ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
unixctl_command_reply(conn, "OK");
err = ovs_router_insert__(plen + 32, &ip6, plen, argv[2], &gw6);
if (err) {
unixctl_command_reply(conn, "Error while inserting route.");
} else {
unixctl_command_reply(conn, "OK");
}
}
static void
@@ -298,6 +357,8 @@ ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
ds_put_format(&ds, " GW ");
ipv6_format_mapped(&rt->gw, &ds);
}
ds_put_format(&ds, " SRC ");
ipv6_format_mapped(&rt->src_addr, &ds);
ds_put_format(&ds, "\n");
}
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;
unsigned int plen;
char iface[IFNAMSIZ];
struct in6_addr gw;
struct in6_addr gw, src;
if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
in6_addr_set_mapped_ipv4(&ip6, ip);
@@ -321,10 +382,12 @@ ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,
return;
}
if (ovs_router_lookup(&ip6, iface, &gw)) {
if (ovs_router_lookup(&ip6, iface, &src, &gw)) {
struct ds ds = DS_EMPTY_INITIALIZER;
ds_put_format(&ds, "src ");
ipv6_format_mapped(&src, &ds);
ds_put_format(&ds, "gateway ");
ipv6_format_mapped(&ip6, &ds);
ipv6_format_mapped(&gw, &ds);
ds_put_format(&ds, "\ndev %s\n", iface);
unixctl_command_reply(conn, ds_cstr(&ds));
ds_destroy(&ds);

View File

@@ -26,7 +26,7 @@ extern "C" {
#endif
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);
void ovs_router_init(void);
void ovs_router_insert(const struct in6_addr *ip_dst, uint8_t plen,

View File

@@ -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]);
}
}
} else {
VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
}

View File

@@ -40,8 +40,8 @@ static struct classifier cls; /* Tunnel ports. */
struct ip_device {
struct netdev *dev;
struct eth_addr mac;
ovs_be32 addr4;
struct in6_addr addr6;
struct in6_addr *addr;
int n_addr;
uint64_t change_seq;
struct ovs_list node;
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
tnl_port_map_insert(odp_port_t port,
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_FOR_EACH(ip_dev, node, &addr_list) {
if (ip_dev->addr4 != INADDR_ANY) {
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);
}
map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->udp_port);
}
out:
@@ -210,6 +216,18 @@ map_delete(struct eth_addr mac, struct in6_addr *addr, ovs_be16 udp_port)
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
tnl_port_map_delete(ovs_be16 udp_port)
{
@@ -230,13 +248,7 @@ tnl_port_map_delete(ovs_be16 udp_port)
goto out;
}
LIST_FOR_EACH(ip_dev, node, &addr_list) {
if (ip_dev->addr4 != INADDR_ANY) {
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);
}
ipdev_map_delete(ip_dev, p->udp_port);
}
free(p);
@@ -331,56 +343,64 @@ map_insert_ipdev(struct ip_device *ip_dev)
struct tnl_port *p;
LIST_FOR_EACH(p, node, &port_list) {
if (ip_dev->addr4 != INADDR_ANY) {
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);
}
map_insert_ipdev__(ip_dev, p->dev_name, p->port, p->udp_port);
}
}
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
insert_ipdev(const char dev_name[])
{
struct ip_device *ip_dev;
enum netdev_flags flags;
struct in6_addr *addr, *mask;
struct netdev *dev;
int error;
int error4, error6;
int error, n_in6;
error = netdev_open(dev_name, NULL, &dev);
if (error) {
return;
}
error = netdev_get_flags(dev, &flags);
if (error || (flags & NETDEV_LOOPBACK)) {
error = netdev_get_addr_list(dev, &addr, &mask, &n_in6);
if (error) {
netdev_close(dev);
return;
}
ip_dev = xzalloc(sizeof *ip_dev);
ip_dev->dev = 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);
free(mask);
insert_ipdev__(dev, addr, n_in6);
netdev_close(dev);
}
static void
@@ -389,17 +409,12 @@ delete_ipdev(struct ip_device *ip_dev)
struct tnl_port *p;
LIST_FOR_EACH(p, node, &port_list) {
if (ip_dev->addr4 != INADDR_ANY) {
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);
}
ipdev_map_delete(ip_dev, p->udp_port);
}
list_remove(&ip_dev->node);
netdev_close(ip_dev->dev);
free(ip_dev->addr);
free(ip_dev);
}
@@ -417,7 +432,6 @@ tnl_port_map_insert_ipdev(const char dev_name[])
}
/* Address changed. */
delete_ipdev(ip_dev);
break;
}
}
insert_ipdev(dev_name);

View File

@@ -2750,7 +2750,8 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport)
static int
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];
struct xbridge *xbridge;
@@ -2759,7 +2760,7 @@ tnl_route_lookup_flow(const struct flow *oflow,
struct in6_addr dst;
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;
}
@@ -2850,7 +2851,7 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport,
char buf_sip6[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) {
xlate_report(ctx, "native tunnel routing failed");
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);
if (d_ip) {
err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL);
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;
}
s_ip = in6_addr_get_mapped_ipv4(&s_ip6);
}
err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);

View File

@@ -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
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 ovs/route/add 1.1.2.92/24 br0], [0], [OK
])
AT_CHECK([ovs-ofctl add-flow br0 action=normal])
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\" \
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 for this port so the sFlow output will just report that it went to
dnl 1 output (out_format=2, out_ifindex=1)

View File

@@ -4963,8 +4963,7 @@ collect_splinter_vlans(const struct ovsrec_open_vswitch *ovs_cfg)
struct netdev *netdev;
if (!netdev_open(vlan_dev->name, "system", &netdev)) {
if (!netdev_get_in4(netdev, NULL, NULL) ||
!netdev_get_in6(netdev, NULL)) {
if (!netdev_get_addr_list(netdev, NULL, NULL, NULL)) {
/* It has an IP address configured, so we don't own
* it. Don't delete it. */
} else {