@@ -92,7 +92,6 @@ struct netdev_bsd {
struct eth_addr etheraddr;
struct in_addr in4;
struct in_addr netmask;
- struct in6_addr in6;
int mtu;
int carrier;
@@ -1244,37 +1243,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_);
- 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;
- }
+ int error;
- 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;
+ if (!(netdev->cache_valid & VALID_IN6)) {
+ 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__)
@@ -1595,7 +1577,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 */ \
@@ -2689,7 +2689,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, \
@@ -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;
@@ -1244,7 +1281,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 */
@@ -1537,15 +1574,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 {
@@ -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;
@@ -2890,7 +2849,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, \
@@ -636,7 +636,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:
*
@@ -644,9 +648,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'.
@@ -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, \
@@ -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);
@@ -1128,9 +1136,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:
*
@@ -1138,20 +1148,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;
}
@@ -1854,3 +1865,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
@@ -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
@@ -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);
@@ -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,
@@ -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");
}
@@ -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(const char dev_name[])
+insert_ipdev__(struct netdev *dev,
+ struct in6_addr *addr, int n_addr)
{
struct ip_device *ip_dev;
enum netdev_flags flags;
- struct netdev *dev;
int error;
- int error4, error6;
-
- error = netdev_open(dev_name, NULL, &dev);
- if (error) {
- return;
- }
error = netdev_get_flags(dev, &flags);
if (error || (flags & NETDEV_LOOPBACK)) {
- netdev_close(dev);
- return;
+ goto err;
}
ip_dev = xzalloc(sizeof *ip_dev);
- ip_dev->dev = 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) {
- 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;
+ 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 in6_addr *addr, *mask;
+ struct netdev *dev;
+ int error, n_in6;
+
+ error = netdev_open(dev_name, NULL, &dev);
+ if (error) {
+ return;
+ }
+
+ error = netdev_get_addr_list(dev, &addr, &mask, &n_in6);
+ if (error) {
+ netdev_close(dev);
+ return;
+ }
+ 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);
@@ -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);
@@ -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)
@@ -4916,8 +4916,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 {