Page MenuHomeFreeBSD

D14222.1789818788.diff
No OneTemporary

Size
29 KB
Referenced Files
None
Subscribers
None

D14222.1789818788.diff

Index: sbin/ifconfig/ifconfig.8
===================================================================
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -2734,13 +2734,18 @@
When the interface is configured in unicast mode, the listening socket
is bound to this address.
.It Cm vxlanremote Ar address
-The interface can be configured in a unicast, or point-to-point, mode
-to create a tunnel between two hosts.
-This is the IP address of the remote end of the tunnel.
+The interface can be configured in a unicast mode, where frames without a
+learned address are flooded to specific remote hosts. This adds the specified
+address to the list of destination hosts.
+.It Cm -vxlanremote Ar address
+Remove the specified address from the list of destination unicast hosts.
.It Cm vxlangroup Ar address
The interface can be configured in a multicast mode
to create a virtual network of hosts.
This is the IP multicast group address the interface will join.
+The multicast destination will not be used if any unicast destinations are
+specified by
+.Cm vxlanremote .
.It Cm vxlanlocalport Ar port
The port number the interface will listen on.
The default port number is 4789.
Index: sbin/ifconfig/ifvxlan.c
===================================================================
--- sbin/ifconfig/ifvxlan.c
+++ sbin/ifconfig/ifvxlan.c
@@ -98,13 +98,52 @@
}
static void
+vxlan_status_remotes(int s)
+{
+ struct ifvxlanreqremotes rmts;
+ struct ifvxlanreqremote *rmt;
+ struct sockaddr *rsa;
+ char dst[NI_MAXHOST], dstport[NI_MAXSERV];
+ char *inbuf = NULL, *ninbuf;
+ int i, len = 2048, ipv6;
+
+ for (;;) {
+ ninbuf = realloc(inbuf, len);
+ if (ninbuf == NULL)
+ err(1, "unable to allocate remotes buffer");
+ rmts.vxlr_len = len;
+ rmts.vxlr_buf = inbuf = ninbuf;
+ if (do_cmd(s, VXLAN_CMD_GET_REMOTES, &rmts, sizeof(rmts), 0) < 0)
+ err(1, "unable to get list of remotes");
+ if ((rmts.vxlr_len + sizeof(*rmt)) < len)
+ break;
+ len *= 2;
+ }
+
+ for (i = 0; i < (rmts.vxlr_len / sizeof(*rmt)); i++) {
+ rmt = rmts.vxlr_rmt + i;
+ rsa = &rmt->vxlr_sa.sa;
+ ipv6 = rsa->sa_family == AF_INET6;
+
+ if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
+ dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ dst[0] = dstport[0] = '\0';
+
+ printf("\n\t\t\t%s%s%s",
+ ipv6 ? "[" : "", dst, ipv6 ? "]" : "");
+ }
+
+ free(inbuf);
+}
+
+static void
vxlan_status(int s)
{
struct ifvxlancfg cfg;
- char src[NI_MAXHOST], dst[NI_MAXHOST];
+ char src[NI_MAXHOST], group[NI_MAXHOST];
char srcport[NI_MAXSERV], dstport[NI_MAXSERV];
- struct sockaddr *lsa, *rsa;
- int vni, mc, ipv6;
+ struct sockaddr *lsa, *msa;
+ int vni, ipv6;
bzero(&cfg, sizeof(cfg));
@@ -113,8 +152,8 @@
vni = cfg.vxlc_vni;
lsa = &cfg.vxlc_local_sa.sa;
- rsa = &cfg.vxlc_remote_sa.sa;
- ipv6 = rsa->sa_family == AF_INET6;
+ msa = &cfg.vxlc_mcast_sa.sa;
+ ipv6 = lsa->sa_family == AF_INET6;
/* Just report nothing if the network identity isn't set yet. */
if (vni >= VXLAN_VNI_MAX)
@@ -123,33 +162,30 @@
if (getnameinfo(lsa, lsa->sa_len, src, sizeof(src),
srcport, sizeof(srcport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
src[0] = srcport[0] = '\0';
- if (getnameinfo(rsa, rsa->sa_len, dst, sizeof(dst),
+ if (getnameinfo(msa, msa->sa_len, group, sizeof(group),
dstport, sizeof(dstport), NI_NUMERICHOST | NI_NUMERICSERV) != 0)
- dst[0] = dstport[0] = '\0';
+ group[0] = dstport[0] = '\0';
- if (!ipv6) {
- struct sockaddr_in *sin = (struct sockaddr_in *)rsa;
- mc = IN_MULTICAST(ntohl(sin->sin_addr.s_addr));
- } else {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)rsa;
- mc = IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr);
- }
-
printf("\tvxlan vni %d", vni);
printf(" local %s%s%s:%s", ipv6 ? "[" : "", src, ipv6 ? "]" : "",
srcport);
- printf(" %s %s%s%s:%s", mc ? "group" : "remote", ipv6 ? "[" : "",
- dst, ipv6 ? "]" : "", dstport);
+ if (cfg.vxlc_remote_cnt == 0)
+ printf(" group %s%s%s",
+ ipv6 ? "[" : "",
+ group, ipv6 ? "]" : "");
+
if (verbose) {
printf("\n\t\tconfig: ");
- printf("%slearning portrange %d-%d ttl %d",
+ printf("%slearning portrange %d-%d ttl %d rport %d",
cfg.vxlc_learn ? "" : "no", cfg.vxlc_port_min,
- cfg.vxlc_port_max, cfg.vxlc_ttl);
+ cfg.vxlc_port_max, cfg.vxlc_ttl, cfg.vxlc_remote_port);
printf("\n\t\tftable: ");
printf("cnt %d max %d timeout %d",
cfg.vxlc_ftable_cnt, cfg.vxlc_ftable_max,
cfg.vxlc_ftable_timeout);
+ printf("\n\t\tflooding: %d hosts", cfg.vxlc_remote_cnt);
+ vxlan_status_remotes(s);
}
putchar('\n');
@@ -338,6 +374,55 @@
}
static
+DECL_CMD_FUNC(unsetvxlan_remote, addr, d)
+{
+ struct ifvxlancmd cmd;
+ struct addrinfo *ai;
+ struct sockaddr *sa;
+ int error;
+
+ bzero(&cmd, sizeof(cmd));
+
+ if ((error = getaddrinfo(addr, NULL, NULL, &ai)) != 0)
+ errx(1, "error in parsing remote address string: %s",
+ gai_strerror(error));
+
+ sa = ai->ai_addr;
+
+ switch (ai->ai_family) {
+#ifdef INET
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
+ errx(1, "remote address cannot be multicast");
+
+ cmd.vxlcmd_sa.in4 = *sin;
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ errx(1, "remote address cannot be multicast");
+
+ cmd.vxlcmd_sa.in6 = *sin6;
+ break;
+ }
+#endif
+ default:
+ errx(1, "remote address %s not supported", addr);
+ }
+
+ freeaddrinfo(ai);
+
+ if (do_cmd(s, VXLAN_CMD_UNSET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_UNSET_REMOTE_ADDR");
+}
+
+static
DECL_CMD_FUNC(setvxlan_group, addr, d)
{
struct ifvxlancmd cmd;
@@ -384,17 +469,17 @@
if (!vxlan_exists(s)) {
if (cmd.vxlcmd_sa.sa.sa_family == AF_INET) {
- params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR4;
- params.vxlp_remote_sa.in4 = cmd.vxlcmd_sa.in4;
+ params.vxlp_with |= VXLAN_PARAM_WITH_MCAST_GROUP4;
+ params.vxlp_mcast_group4 = cmd.vxlcmd_sa.in4.sin_addr;
} else {
- params.vxlp_with |= VXLAN_PARAM_WITH_REMOTE_ADDR6;
- params.vxlp_remote_sa.in6 = cmd.vxlcmd_sa.in6;
+ params.vxlp_with |= VXLAN_PARAM_WITH_MCAST_GROUP6;
+ params.vxlp_mcast_group6 = cmd.vxlcmd_sa.in6.sin6_addr;
}
return;
}
- if (do_cmd(s, VXLAN_CMD_SET_REMOTE_ADDR, &cmd, sizeof(cmd), 1) < 0)
- err(1, "VXLAN_CMD_SET_REMOTE_ADDR");
+ if (do_cmd(s, VXLAN_CMD_SET_MULTICAST_GROUP, &cmd, sizeof(cmd), 1) < 0)
+ err(1, "VXLAN_CMD_SET_MULTICAST_GROUP");
}
static
@@ -607,6 +692,7 @@
DEF_CMD_ARG("vxlanid", setvxlan_vni),
DEF_CMD_ARG("vxlanlocal", setvxlan_local),
DEF_CMD_ARG("vxlanremote", setvxlan_remote),
+ DEF_CMD_ARG("-vxlanremote", unsetvxlan_remote),
DEF_CMD_ARG("vxlangroup", setvxlan_group),
DEF_CMD_ARG("vxlanlocalport", setvxlan_local_port),
DEF_CMD_ARG("vxlanremoteport", setvxlan_remote_port),
Index: sys/net/if_vxlan.h
===================================================================
--- sys/net/if_vxlan.h
+++ sys/net/if_vxlan.h
@@ -73,9 +73,11 @@
#define VXLAN_PARAM_WITH_PORT_RANGE 0x0080
#define VXLAN_PARAM_WITH_FTABLE_TIMEOUT 0x0100
#define VXLAN_PARAM_WITH_FTABLE_MAX 0x0200
-#define VXLAN_PARAM_WITH_MULTICAST_IF 0x0400
-#define VXLAN_PARAM_WITH_TTL 0x0800
-#define VXLAN_PARAM_WITH_LEARN 0x1000
+#define VXLAN_PARAM_WITH_MCAST_GROUP4 0x0400
+#define VXLAN_PARAM_WITH_MCAST_GROUP6 0x0800
+#define VXLAN_PARAM_WITH_MULTICAST_IF 0x1000
+#define VXLAN_PARAM_WITH_TTL 0x2000
+#define VXLAN_PARAM_WITH_LEARN 0x4000
uint32_t vxlp_vni;
union vxlan_sockaddr vxlp_local_sa;
@@ -85,6 +87,8 @@
uint16_t vxlp_min_port;
uint16_t vxlp_max_port;
char vxlp_mc_ifname[IFNAMSIZ];
+ struct in_addr vxlp_mcast_group4;
+ struct in6_addr vxlp_mcast_group6;
uint32_t vxlp_ftable_timeout;
uint32_t vxlp_ftable_max;
uint8_t vxlp_ttl;
@@ -99,31 +103,50 @@
#define VXLAN_CMD_GET_CONFIG 0
#define VXLAN_CMD_SET_VNI 1
#define VXLAN_CMD_SET_LOCAL_ADDR 2
-#define VXLAN_CMD_SET_REMOTE_ADDR 4
-#define VXLAN_CMD_SET_LOCAL_PORT 5
-#define VXLAN_CMD_SET_REMOTE_PORT 6
-#define VXLAN_CMD_SET_PORT_RANGE 7
-#define VXLAN_CMD_SET_FTABLE_TIMEOUT 8
-#define VXLAN_CMD_SET_FTABLE_MAX 9
-#define VXLAN_CMD_SET_MULTICAST_IF 10
-#define VXLAN_CMD_SET_TTL 11
-#define VXLAN_CMD_SET_LEARN 12
-#define VXLAN_CMD_FTABLE_ENTRY_ADD 13
-#define VXLAN_CMD_FTABLE_ENTRY_REM 14
-#define VXLAN_CMD_FLUSH 15
+#define VXLAN_CMD_SET_REMOTE_ADDR 3
+#define VXLAN_CMD_UNSET_REMOTE_ADDR 4
+#define VXLAN_CMD_GET_REMOTES 5
+#define VXLAN_CMD_SET_LOCAL_PORT 6
+#define VXLAN_CMD_SET_REMOTE_PORT 7
+#define VXLAN_CMD_SET_PORT_RANGE 8
+#define VXLAN_CMD_SET_FTABLE_TIMEOUT 9
+#define VXLAN_CMD_SET_FTABLE_MAX 10
+#define VXLAN_CMD_SET_MULTICAST_GROUP 11
+#define VXLAN_CMD_SET_MULTICAST_IF 12
+#define VXLAN_CMD_SET_TTL 13
+#define VXLAN_CMD_SET_LEARN 14
+#define VXLAN_CMD_FTABLE_ENTRY_ADD 15
+#define VXLAN_CMD_FTABLE_ENTRY_REM 16
+#define VXLAN_CMD_FLUSH 17
struct ifvxlancfg {
uint32_t vxlc_vni;
union vxlan_sockaddr vxlc_local_sa;
- union vxlan_sockaddr vxlc_remote_sa;
+ union vxlan_sockaddr vxlc_mcast_sa;
uint32_t vxlc_mc_ifindex;
uint32_t vxlc_ftable_cnt;
uint32_t vxlc_ftable_max;
uint32_t vxlc_ftable_timeout;
+ uint32_t vxlc_remote_cnt;
+ uint16_t vxlc_remote_port;
uint16_t vxlc_port_min;
uint16_t vxlc_port_max;
uint8_t vxlc_learn;
uint8_t vxlc_ttl;
+};
+
+struct ifvxlanreqremote {
+ union vxlan_sockaddr vxlr_sa;
+};
+
+struct ifvxlanreqremotes {
+ uint32_t vxlr_len;
+ union {
+ caddr_t vxlru_buf;
+ struct ifvxlanreqremote *vxlru_rmt;
+ } vxlr_u;
+#define vxlr_buf vxlr_u.vxlru_buf
+#define vxlr_rmt vxlr_u.vxlru_rmt
};
struct ifvxlancmd {
Index: sys/net/if_vxlan.c
===================================================================
--- sys/net/if_vxlan.c
+++ sys/net/if_vxlan.c
@@ -139,18 +139,27 @@
uint32_t ftable_lock_upgrade_failed;
};
+struct vxlan_rmtlist_entry {
+ LIST_ENTRY(vxlan_rmtlist_entry) vxlre_next;
+ union vxlan_sockaddr vxlre_raddr;
+};
+
+#define VXLAN_REMOTES_MAX 64
+
struct vxlan_softc {
struct ifnet *vxl_ifp;
struct vxlan_socket *vxl_sock;
uint32_t vxl_vni;
union vxlan_sockaddr vxl_src_addr;
- union vxlan_sockaddr vxl_dst_addr;
+ LIST_HEAD(, vxlan_rmtlist_entry) vxl_rmtlist;
+ uint32_t vxl_rmtlist_cnt;
uint32_t vxl_flags;
#define VXLAN_FLAG_INIT 0x0001
#define VXLAN_FLAG_TEARDOWN 0x0002
#define VXLAN_FLAG_LEARN 0x0004
uint32_t vxl_port_hash_key;
+ uint16_t vxl_dst_port;
uint16_t vxl_min_port;
uint16_t vxl_max_port;
uint8_t vxl_ttl;
@@ -162,9 +171,7 @@
uint32_t vxl_ftable_hash_key;
struct vxlan_ftable_head *vxl_ftable;
- /* Derived from vxl_dst_addr. */
- struct vxlan_ftable_entry vxl_default_fe;
-
+ union vxlan_sockaddr vxl_mcast_addr;
struct ip_moptions *vxl_im4o;
struct ip6_moptions *vxl_im6o;
@@ -239,6 +246,12 @@
static void vxlan_ftable_entry_dump(struct vxlan_ftable_entry *,
struct sbuf *);
+static int vxlan_rmtlist_entry_add(struct vxlan_softc *,
+ struct vxlan_rmtlist_entry *);
+static int vxlan_rmtlist_entry_remove(struct vxlan_softc *,
+ union vxlan_sockaddr *);
+static void vxlan_rmtlist_flush(struct vxlan_softc *);
+
static struct vxlan_socket *
vxlan_socket_alloc(const union vxlan_sockaddr *);
static void vxlan_socket_destroy(struct vxlan_socket *);
@@ -306,11 +319,14 @@
static int vxlan_ctrl_set_vni(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_local_addr(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_remote_addr(struct vxlan_softc *, void *);
+static int vxlan_ctrl_unset_remote_addr(struct vxlan_softc *, void *);
+static int vxlan_ctrl_get_remotes(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_local_port(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_remote_port(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_port_range(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_ftable_timeout(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_ftable_max(struct vxlan_softc *, void *);
+static int vxlan_ctrl_set_multicast_group(struct vxlan_softc * , void *);
static int vxlan_ctrl_set_multicast_if(struct vxlan_softc * , void *);
static int vxlan_ctrl_set_ttl(struct vxlan_softc *, void *);
static int vxlan_ctrl_set_learn(struct vxlan_softc *, void *);
@@ -454,6 +470,16 @@
VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
},
+ [VXLAN_CMD_UNSET_REMOTE_ADDR] =
+ { vxlan_ctrl_unset_remote_addr, sizeof(struct ifvxlancmd),
+ VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
+ },
+
+ [VXLAN_CMD_GET_REMOTES] =
+ { vxlan_ctrl_get_remotes, sizeof(struct ifvxlanreqremotes),
+ VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_COPYOUT,
+ },
+
[VXLAN_CMD_SET_LOCAL_PORT] =
{ vxlan_ctrl_set_local_port, sizeof(struct ifvxlancmd),
VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
@@ -479,6 +505,11 @@
VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
},
+ [VXLAN_CMD_SET_MULTICAST_GROUP] =
+ { vxlan_ctrl_set_multicast_group, sizeof(struct ifvxlancmd),
+ VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
+ },
+
[VXLAN_CMD_SET_MULTICAST_IF] =
{ vxlan_ctrl_set_multicast_if, sizeof(struct ifvxlancmd),
VXLAN_CTRL_FLAG_COPYIN | VXLAN_CTRL_FLAG_SUSER,
@@ -648,12 +679,8 @@
union vxlan_sockaddr vxlsa;
int error;
- /*
- * The source port may be randomly selected by the remote host, so
- * use the port of the default destination address.
- */
vxlan_sockaddr_copy(&vxlsa, sa);
- vxlsa.in4.sin_port = sc->vxl_dst_addr.in4.sin_port;
+ vxlsa.in4.sin_port = sc->vxl_dst_port;
if (VXLAN_SOCKADDR_IS_IPV6(&vxlsa)) {
error = vxlan_sockaddr_in6_embedscope(&vxlsa);
@@ -843,6 +870,80 @@
sbuf_setpos(sb, len);
}
+static int
+vxlan_rmtlist_entry_add(struct vxlan_softc *sc,
+ struct vxlan_rmtlist_entry *re)
+{
+ struct vxlan_rmtlist_entry *lre;
+ int found;
+
+ VXLAN_LOCK_WASSERT(sc);
+
+ if (sc->vxl_rmtlist_cnt == VXLAN_REMOTES_MAX)
+ return (ENOSPC);
+
+ found = 0;
+ LIST_FOREACH(lre, &sc->vxl_rmtlist, vxlre_next) {
+ if (bcmp(&re->vxlre_raddr.sa, &lre->vxlre_raddr.sa,
+ re->vxlre_raddr.sa.sa_len) == 0) {
+ found++;
+ break;
+ }
+ }
+
+ if (found)
+ return (EEXIST);
+
+ LIST_INSERT_HEAD(&sc->vxl_rmtlist, re, vxlre_next);
+ sc->vxl_rmtlist_cnt++;
+
+ return (0);
+}
+
+static int
+vxlan_rmtlist_entry_remove(struct vxlan_softc *sc,
+ union vxlan_sockaddr *vxlsa)
+{
+ struct vxlan_rmtlist_entry *lre, *tre;
+ int found;
+
+ VXLAN_LOCK_WASSERT(sc);
+
+ if (LIST_EMPTY(&sc->vxl_rmtlist))
+ return (ENOENT);
+
+ found = 0;
+ LIST_FOREACH_SAFE(lre, &sc->vxl_rmtlist, vxlre_next, tre) {
+ if (bcmp(&vxlsa->sa, &lre->vxlre_raddr.sa,
+ vxlsa->sa.sa_len) == 0) {
+ LIST_REMOVE(lre, vxlre_next);
+ free(lre, M_VXLAN);
+ sc->vxl_rmtlist_cnt--;
+ found++;
+ break;
+ }
+ }
+
+ if (!found)
+ return (ENOENT);
+
+ return (0);
+}
+
+static void
+vxlan_rmtlist_flush(struct vxlan_softc *sc)
+{
+ struct vxlan_rmtlist_entry *lre, *tre;
+
+ VXLAN_LOCK_WASSERT(sc);
+
+ LIST_FOREACH_SAFE(lre, &sc->vxl_rmtlist, vxlre_next, tre) {
+ LIST_REMOVE(lre, vxlre_next);
+ free(lre, M_VXLAN);
+ sc->vxl_rmtlist_cnt--;
+ }
+}
+
static struct vxlan_socket *
vxlan_socket_alloc(const union vxlan_sockaddr *sa)
{
@@ -1443,7 +1544,7 @@
const union vxlan_sockaddr *group;
int error;
- group = &sc->vxl_dst_addr;
+ group = &sc->vxl_mcast_addr;
error = 0;
if (sc->vxl_mc_ifname[0] != '\0') {
@@ -1479,16 +1580,16 @@
{
struct vxlan_socket *vso;
struct ifnet *ifp;
- union vxlan_sockaddr *saddr, *daddr;
- int multicast, error;
+ union vxlan_sockaddr *saddr, *gaddr;
+ int multicast = 0, error;
vso = NULL;
ifp = sc->vxl_ifp;
saddr = &sc->vxl_src_addr;
- daddr = &sc->vxl_dst_addr;
+ gaddr = &sc->vxl_mcast_addr;
- multicast = vxlan_sockaddr_in_multicast(daddr);
- MPASS(multicast != -1);
+ if (gaddr->sa.sa_len != 0)
+ multicast = 1;
sc->vxl_vso_mc_index = -1;
/*
@@ -1514,7 +1615,7 @@
if (error)
goto out;
- error = vxlan_socket_mc_add_group(vso, daddr, saddr,
+ error = vxlan_socket_mc_add_group(vso, gaddr, saddr,
sc->vxl_mc_ifindex, &sc->vxl_vso_mc_index);
if (error)
goto out;
@@ -1554,9 +1655,9 @@
ifp = sc->vxl_ifp;
ifp->if_hdrlen = ETHER_HDR_LEN + sizeof(struct vxlanudphdr);
- if (VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_dst_addr) != 0)
+ if (VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_src_addr) != 0)
ifp->if_hdrlen += sizeof(struct ip);
- else if (VXLAN_SOCKADDR_IS_IPV6(&sc->vxl_dst_addr) != 0)
+ else if (VXLAN_SOCKADDR_IS_IPV6(&sc->vxl_src_addr) != 0)
ifp->if_hdrlen += sizeof(struct ip6_hdr);
}
@@ -1575,37 +1676,18 @@
goto fail;
}
- if (vxlan_sockaddr_supported(&sc->vxl_dst_addr, 0) == 0) {
- reason = "destination address type is not supported";
- goto fail;
- }
-
- if (vxlan_sockaddr_in_any(&sc->vxl_dst_addr) != 0) {
- reason = "no valid destination address specified";
- goto fail;
- }
-
- if (vxlan_sockaddr_in_multicast(&sc->vxl_dst_addr) == 0 &&
+ if (vxlan_sockaddr_in_any(&sc->vxl_mcast_addr) != 0 &&
sc->vxl_mc_ifname[0] != '\0') {
reason = "can only specify interface with a group address";
goto fail;
}
- if (vxlan_sockaddr_in_any(&sc->vxl_src_addr) == 0) {
- if (VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_src_addr) ^
- VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_dst_addr)) {
- reason = "source and destination address must both "
- "be either IPv4 or IPv6";
- goto fail;
- }
- }
-
if (sc->vxl_src_addr.in4.sin_port == 0) {
reason = "local port not specified";
goto fail;
}
- if (sc->vxl_dst_addr.in4.sin_port == 0) {
+ if (sc->vxl_dst_port == 0) {
reason = "remote port not specified";
goto fail;
}
@@ -1639,7 +1721,6 @@
static void
vxlan_init(void *xsc)
{
- static const uint8_t empty_mac[ETHER_ADDR_LEN];
struct vxlan_softc *sc;
struct ifnet *ifp;
@@ -1662,10 +1743,6 @@
if (vxlan_setup_socket(sc) != 0)
goto out;
- /* Initialize the default forwarding entry. */
- vxlan_ftable_entry_init(sc, &sc->vxl_default_fe, empty_mac,
- &sc->vxl_dst_addr.sa, VXLAN_FE_FLAG_STATIC);
-
VXLAN_WLOCK(sc);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
callout_reset(&sc->vxl_callout, vxlan_ftable_prune_period * hz,
@@ -1831,12 +1908,14 @@
cfg->vxlc_vni = sc->vxl_vni;
memcpy(&cfg->vxlc_local_sa, &sc->vxl_src_addr,
sizeof(union vxlan_sockaddr));
- memcpy(&cfg->vxlc_remote_sa, &sc->vxl_dst_addr,
+ memcpy(&cfg->vxlc_mcast_sa, &sc->vxl_mcast_addr,
sizeof(union vxlan_sockaddr));
cfg->vxlc_mc_ifindex = sc->vxl_mc_ifindex;
cfg->vxlc_ftable_cnt = sc->vxl_ftable_cnt;
cfg->vxlc_ftable_max = sc->vxl_ftable_max;
cfg->vxlc_ftable_timeout = sc->vxl_ftable_timeout;
+ cfg->vxlc_remote_cnt = sc->vxl_rmtlist_cnt;
+ cfg->vxlc_remote_port = sc->vxl_dst_port;
cfg->vxlc_port_min = sc->vxl_min_port;
cfg->vxlc_port_max = sc->vxl_max_port;
cfg->vxlc_learn = (sc->vxl_flags & VXLAN_FLAG_LEARN) != 0;
@@ -1846,8 +1925,6 @@
#ifdef INET6
if (VXLAN_SOCKADDR_IS_IPV6(&cfg->vxlc_local_sa))
sa6_recoverscope(&cfg->vxlc_local_sa.in6);
- if (VXLAN_SOCKADDR_IS_IPV6(&cfg->vxlc_remote_sa))
- sa6_recoverscope(&cfg->vxlc_remote_sa.in6);
#endif
return (0);
@@ -1895,6 +1972,12 @@
return (error);
}
+ if (sc->vxl_rmtlist_cnt != 0 &&
+ vxlsa->sa.sa_family != sc->vxl_src_addr.sa.sa_family) {
+ if_printf(sc->vxl_ifp, "removed all remote hosts because source address family changed\n");
+ vxlan_rmtlist_flush(sc);
+ }
+
VXLAN_WLOCK(sc);
if (vxlan_can_change_config(sc)) {
vxlan_sockaddr_in_copy(&sc->vxl_src_addr, &vxlsa->sa);
@@ -1911,11 +1994,56 @@
{
struct ifvxlancmd *cmd;
union vxlan_sockaddr *vxlsa;
+ struct vxlan_rmtlist_entry *re;
int error;
+ const char *reason;
cmd = arg;
vxlsa = &cmd->vxlcmd_sa;
+ if (vxlan_sockaddr_supported(vxlsa, 0) == 0) {
+ reason = "destination address type is not supported";
+ goto fail;
+ }
+
+ if (vxlan_sockaddr_in_any(vxlsa) != 0) {
+ reason = "no valid destination address specified";
+ goto fail;
+ }
+
+ if (vxlan_sockaddr_in_any(&sc->vxl_src_addr) == 0) {
+ if (VXLAN_SOCKADDR_IS_IPV4(&sc->vxl_src_addr) ^
+ VXLAN_SOCKADDR_IS_IPV4(vxlsa)) {
+ reason = "source and destination address must both "
+ "be either IPv4 or IPv6";
+ goto fail;
+ }
+ }
+
+ re = malloc(sizeof(struct vxlan_rmtlist_entry), M_VXLAN, M_WAITOK | M_ZERO);
+
+ VXLAN_WLOCK(sc);
+ vxlan_sockaddr_in_copy(&re->vxlre_raddr, &vxlsa->sa);
+ error = vxlan_rmtlist_entry_add(sc, re);
+ VXLAN_WUNLOCK(sc);
+
+ return (error);
+
+fail:
+ if_printf(sc->vxl_ifp, "cannot add remote: %s\n", reason);
+ return (EINVAL);
+}
+
+static int
+vxlan_ctrl_unset_remote_addr(struct vxlan_softc *sc, void *arg)
+{
+ struct ifvxlancmd *cmd;
+ union vxlan_sockaddr *vxlsa;
+ int error;
+
+ cmd = arg;
+ vxlsa = &cmd->vxlcmd_sa;
+
if (!VXLAN_SOCKADDR_IS_IPV46(vxlsa))
return (EINVAL);
if (VXLAN_SOCKADDR_IS_IPV6(vxlsa)) {
@@ -1925,17 +2053,70 @@
}
VXLAN_WLOCK(sc);
- if (vxlan_can_change_config(sc)) {
- vxlan_sockaddr_in_copy(&sc->vxl_dst_addr, &vxlsa->sa);
- error = 0;
- } else
- error = EBUSY;
+ error = vxlan_rmtlist_entry_remove(sc, vxlsa);
VXLAN_WUNLOCK(sc);
return (error);
}
static int
+vxlan_ctrl_get_remotes(struct vxlan_softc *sc, void *arg)
+{
+ struct rm_priotracker tracker;
+ struct vxlan_rmtlist_entry *re;
+ struct ifvxlanreqremotes *rmts;
+ struct ifvxlanreqremote rmt;
+ int count, buflen, len, error;
+ char *buf, *outbuf;
+
+ rmts = arg;
+
+ VXLAN_RLOCK(sc, &tracker);
+ count = 0;
+ LIST_FOREACH(re, &sc->vxl_rmtlist, vxlre_next)
+ count++;
+ VXLAN_RUNLOCK(sc, &tracker);
+
+ buflen = sizeof(rmt) * count;
+ if (rmts->vxlr_len == 0) {
+ rmts->vxlr_len = buflen;
+ return (0);
+ }
+
+ outbuf = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
+
+ count = 0;
+ buf = outbuf;
+ len = min(rmts->vxlr_len, buflen);
+
+ VXLAN_RLOCK(sc, &tracker);
+ LIST_FOREACH(re, &sc->vxl_rmtlist, vxlre_next) {
+ bzero(&rmt, sizeof(rmt));
+ if (len < sizeof(rmt))
+ break;
+
+ memcpy(&rmt.vxlr_sa, &re->vxlre_raddr.sa,
+ sizeof(union vxlan_sockaddr));
+
+#ifdef INET6
+ if (VXLAN_SOCKADDR_IS_IPV6(&rmt.vxlr_sa))
+ sa6_recoverscope(&rmt.vxlr_sa.in6);
+#endif
+
+ memcpy(buf, &rmt, sizeof(rmt));
+ count++;
+ buf += sizeof(rmt);
+ len -= sizeof(rmt);
+ }
+ VXLAN_RUNLOCK(sc, &tracker);
+
+ rmts->vxlr_len = sizeof(rmt) * count;
+ error = copyout(outbuf, rmts->vxlr_buf, rmts->vxlr_len);
+ free(outbuf, M_TEMP);
+ return (error);
+}
+
+static int
vxlan_ctrl_set_local_port(struct vxlan_softc *sc, void *arg)
{
struct ifvxlancmd *cmd;
@@ -1970,7 +2151,7 @@
VXLAN_WLOCK(sc);
if (vxlan_can_change_config(sc)) {
- sc->vxl_dst_addr.in4.sin_port = htons(cmd->vxlcmd_port);
+ sc->vxl_dst_port = cmd->vxlcmd_port;
error = 0;
} else
error = EBUSY;
@@ -2044,6 +2225,34 @@
}
static int
+vxlan_ctrl_set_multicast_group(struct vxlan_softc *sc, void *arg)
+{
+ struct ifvxlancmd *cmd;
+ union vxlan_sockaddr *vxlsa;
+ int error;
+
+ cmd = arg;
+ vxlsa = &cmd->vxlcmd_sa;
+
+ if (!VXLAN_SOCKADDR_IS_IPV46(vxlsa))
+ return (EINVAL);
+ if (vxlan_sockaddr_in_any(vxlsa) != 0)
+ return (EINVAL);
+ if (vxlan_sockaddr_in_multicast(vxlsa) == 0)
+ return (EINVAL);
+
+ VXLAN_WLOCK(sc);
+ if (vxlan_can_change_config(sc)) {
+ vxlan_sockaddr_in_copy(&sc->vxl_mcast_addr, &vxlsa->sa);
+ error = 0;
+ } else
+ error = EBUSY;
+ VXLAN_WUNLOCK(sc);
+
+ return (error);
+}
+
+static int
vxlan_ctrl_set_multicast_if(struct vxlan_softc * sc, void *arg)
{
struct ifvxlancmd *cmd;
@@ -2120,7 +2329,7 @@
if (vxlan_sockaddr_in_multicast(&vxlsa) != 0)
return (EINVAL);
/* BMV: We could support both IPv4 and IPv6 later. */
- if (vxlsa.sa.sa_family != sc->vxl_dst_addr.sa.sa_family)
+ if (vxlsa.sa.sa_family != sc->vxl_src_addr.sa.sa_family)
return (EAFNOSUPPORT);
if (VXLAN_SOCKADDR_IS_IPV6(&vxlsa)) {
@@ -2133,9 +2342,6 @@
if (fe == NULL)
return (ENOMEM);
- if (vxlsa.in4.sin_port == 0)
- vxlsa.in4.sin_port = sc->vxl_dst_addr.in4.sin_port;
-
vxlan_ftable_entry_init(sc, fe, cmd->vxlcmd_mac, &vxlsa.sa,
VXLAN_FE_FLAG_STATIC);
@@ -2333,7 +2539,7 @@
srcaddr = sc->vxl_src_addr.in4.sin_addr;
srcport = vxlan_pick_source_port(sc, m);
dstaddr = fvxlsa->in4.sin_addr;
- dstport = fvxlsa->in4.sin_port;
+ dstport = htons(sc->vxl_dst_port);
M_PREPEND(m, sizeof(struct ip) + sizeof(struct vxlanudphdr),
M_NOWAIT);
@@ -2390,7 +2596,7 @@
srcaddr = &sc->vxl_src_addr.in6.sin6_addr;
srcport = vxlan_pick_source_port(sc, m);
dstaddr = &fvxlsa->in6.sin6_addr;
- dstport = fvxlsa->in6.sin6_port;
+ dstport = htons(sc->vxl_dst_port);
M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct vxlanudphdr),
M_NOWAIT);
@@ -2450,9 +2656,11 @@
union vxlan_sockaddr vxlsa;
struct vxlan_softc *sc;
struct vxlan_ftable_entry *fe;
+ struct vxlan_rmtlist_entry *re;
struct ifnet *mcifp;
struct ether_header *eh;
int ipv4, error;
+ struct mbuf *nm;
sc = ifp->if_softc;
eh = mtod(m, struct ether_header *);
@@ -2470,22 +2678,52 @@
if ((m->m_flags & (M_BCAST | M_MCAST)) == 0)
fe = vxlan_ftable_entry_lookup(sc, eh->ether_dhost);
- if (fe == NULL)
- fe = &sc->vxl_default_fe;
- vxlan_sockaddr_copy(&vxlsa, &fe->vxlfe_raddr.sa);
- ipv4 = VXLAN_SOCKADDR_IS_IPV4(&vxlsa) != 0;
- if (vxlan_sockaddr_in_multicast(&vxlsa) != 0)
- mcifp = vxlan_multicast_if_ref(sc, ipv4);
-
VXLAN_ACQUIRE(sc);
VXLAN_RUNLOCK(sc, &tracker);
- if (ipv4 != 0)
- error = vxlan_encap4(sc, &vxlsa, m);
- else
- error = vxlan_encap6(sc, &vxlsa, m);
+ if (fe != NULL) {
+ vxlan_sockaddr_copy(&vxlsa, &fe->vxlfe_raddr.sa);
+ ipv4 = VXLAN_SOCKADDR_IS_IPV4(&vxlsa) != 0;
+
+ if (ipv4 != 0)
+ error = vxlan_encap4(sc, &vxlsa, m);
+ else
+ error = vxlan_encap6(sc, &vxlsa, m);
+ } else if (sc->vxl_rmtlist_cnt != 0) {
+ LIST_FOREACH(re, &sc->vxl_rmtlist, vxlre_next) {
+ nm = m_dup(m, M_NOWAIT);
+ if (nm == NULL) {
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ continue;
+ }
+
+ vxlan_sockaddr_copy(&vxlsa, &re->vxlre_raddr.sa);
+
+ ipv4 = VXLAN_SOCKADDR_IS_IPV4(&vxlsa) != 0;
+
+ if (ipv4 != 0)
+ error = vxlan_encap4(sc, &vxlsa, nm);
+ else
+ error = vxlan_encap6(sc, &vxlsa, nm);
+ }
+
+ m_freem(m);
+ } else if (vxlan_sockaddr_in_multicast(&sc->vxl_mcast_addr) != 0) {
+ vxlan_sockaddr_copy(&vxlsa, &sc->vxl_mcast_addr.sa);
+
+ ipv4 = VXLAN_SOCKADDR_IS_IPV4(&vxlsa) != 0;
+ mcifp = vxlan_multicast_if_ref(sc, ipv4);
+
+ if (ipv4 != 0)
+ error = vxlan_encap4(sc, &vxlsa, m);
+ else
+ error = vxlan_encap6(sc, &vxlsa, m);
+ } else {
+ error = ENETDOWN;
+ }
+
vxlan_release(sc);
if (mcifp != NULL)
if_rele(mcifp);
@@ -2596,10 +2834,10 @@
if (!vxlan_tunable_int(sc, "legacy_port", vxlan_legacy_port)) {
sc->vxl_src_addr.in4.sin_port = htons(VXLAN_PORT);
- sc->vxl_dst_addr.in4.sin_port = htons(VXLAN_PORT);
+ sc->vxl_dst_port = VXLAN_PORT;
} else {
sc->vxl_src_addr.in4.sin_port = htons(VXLAN_LEGACY_PORT);
- sc->vxl_dst_addr.in4.sin_port = htons(VXLAN_LEGACY_PORT);
+ sc->vxl_dst_port = VXLAN_LEGACY_PORT;
}
sc->vxl_min_port = V_ipport_firstauto;
@@ -2612,6 +2850,7 @@
static int
vxlan_set_user_config(struct vxlan_softc *sc, struct ifvxlanparam *vxlp)
{
+ struct vxlan_rmtlist_entry *re;
#ifndef INET
if (vxlp->vxlp_with & (VXLAN_PARAM_WITH_LOCAL_ADDR4 |
@@ -2655,21 +2894,25 @@
}
if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR4) {
- sc->vxl_dst_addr.in4.sin_len = sizeof(struct sockaddr_in);
- sc->vxl_dst_addr.in4.sin_family = AF_INET;
- sc->vxl_dst_addr.in4.sin_addr =
+ re = malloc(sizeof(struct vxlan_rmtlist_entry), M_VXLAN, M_WAITOK | M_ZERO);
+ re->vxlre_raddr.in4.sin_len = sizeof(struct sockaddr_in);
+ re->vxlre_raddr.in4.sin_family = AF_INET;
+ re->vxlre_raddr.in4.sin_addr =
vxlp->vxlp_remote_sa.in4.sin_addr;
+ vxlan_rmtlist_entry_add(sc, re);
} else if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_ADDR6) {
- sc->vxl_dst_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
- sc->vxl_dst_addr.in6.sin6_family = AF_INET6;
- sc->vxl_dst_addr.in6.sin6_addr =
+ re = malloc(sizeof(struct vxlan_rmtlist_entry), M_VXLAN, M_WAITOK | M_ZERO);
+ re->vxlre_raddr.in6.sin6_len = sizeof(struct sockaddr_in6);
+ re->vxlre_raddr.in6.sin6_family = AF_INET6;
+ re->vxlre_raddr.in6.sin6_addr =
vxlp->vxlp_remote_sa.in6.sin6_addr;
+ vxlan_rmtlist_entry_add(sc, re);
}
if (vxlp->vxlp_with & VXLAN_PARAM_WITH_LOCAL_PORT)
sc->vxl_src_addr.in4.sin_port = htons(vxlp->vxlp_local_port);
if (vxlp->vxlp_with & VXLAN_PARAM_WITH_REMOTE_PORT)
- sc->vxl_dst_addr.in4.sin_port = htons(vxlp->vxlp_remote_port);
+ sc->vxl_dst_port = vxlp->vxlp_remote_port;
if (vxlp->vxlp_with & VXLAN_PARAM_WITH_PORT_RANGE) {
if (vxlp->vxlp_min_port <= vxlp->vxlp_max_port) {
@@ -2678,6 +2921,16 @@
}
}
+ if (vxlp->vxlp_with & VXLAN_PARAM_WITH_MCAST_GROUP4) {
+ sc->vxl_mcast_addr.in4.sin_len = sizeof(struct sockaddr_in);
+ sc->vxl_mcast_addr.in4.sin_family = AF_INET;
+ sc->vxl_mcast_addr.in4.sin_addr = vxlp->vxlp_mcast_group4;
+ } else if (vxlp->vxlp_with & VXLAN_PARAM_WITH_MCAST_GROUP6) {
+ sc->vxl_mcast_addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+ sc->vxl_mcast_addr.in6.sin6_family = AF_INET6;
+ sc->vxl_mcast_addr.in6.sin6_addr = vxlp->vxlp_mcast_group6;
+ }
+
if (vxlp->vxlp_with & VXLAN_PARAM_WITH_MULTICAST_IF)
strlcpy(sc->vxl_mc_ifname, vxlp->vxlp_mc_ifname, IFNAMSIZ);
@@ -2715,6 +2968,7 @@
sc = malloc(sizeof(struct vxlan_softc), M_VXLAN, M_WAITOK | M_ZERO);
sc->vxl_unit = unit;
vxlan_set_default_config(sc);
+ LIST_INIT(&sc->vxl_rmtlist);
if (params != 0) {
error = copyin(params, &vxlp, sizeof(vxlp));
@@ -2777,6 +3031,8 @@
vxlan_teardown(sc);
vxlan_ftable_flush(sc, 1);
+
+ vxlan_rmtlist_flush(sc);
ether_ifdetach(ifp);
if_free(ifp);

File Metadata

Mime Type
text/plain
Expires
Sat, Sep 19, 11:53 AM (19 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29779560
Default Alt Text
D14222.1789818788.diff (29 KB)

Event Timeline