summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/net/bridgectl.c19
-rw-r--r--sys/net/if.h4
-rw-r--r--sys/net/if_bridge.c70
-rw-r--r--sys/net/if_bridge.h22
-rw-r--r--sys/net/if_switch.c41
-rw-r--r--sys/net/if_vlan.c15
-rw-r--r--sys/net/if_vxlan.c96
-rw-r--r--sys/net/if_vxlan.h8
-rw-r--r--sys/netinet/udp_usrreq.c22
9 files changed, 211 insertions, 86 deletions
diff --git a/sys/net/bridgectl.c b/sys/net/bridgectl.c
index 93c638c748e..4e306927bb4 100644
--- a/sys/net/bridgectl.c
+++ b/sys/net/bridgectl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bridgectl.c,v 1.2 2015/12/02 08:04:12 mpi Exp $ */
+/* $OpenBSD: bridgectl.c,v 1.3 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -175,13 +175,13 @@ bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
{
struct bridge_rtnode *p, *q;
- struct sockaddr *sa = NULL;
+ struct bridge_tunneltag *brtag = NULL;
u_int32_t h;
int dir;
if (m != NULL) {
/* Check if the mbuf was tagged with a tunnel endpoint addr */
- sa = bridge_tunnel(m);
+ brtag = bridge_tunnel(m);
}
h = bridge_hash(sc, ea);
@@ -196,7 +196,7 @@ bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
- bridge_copyaddr(sa, (struct sockaddr *)&p->brt_tunnel);
+ bridge_copytag(brtag, &p->brt_tunnel);
if (setflags)
p->brt_flags = flags;
@@ -223,8 +223,7 @@ bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
if (q->brt_if == ifp)
q->brt_age = 1;
ifp = q->brt_if;
- bridge_copyaddr(sa,
- (struct sockaddr *)&q->brt_tunnel);
+ bridge_copytag(brtag, &q->brt_tunnel);
goto want;
}
@@ -239,8 +238,7 @@ bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
+ bridge_copytag(brtag, &p->brt_tunnel);
if (setflags)
p->brt_flags = flags;
@@ -262,8 +260,7 @@ bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
p->brt_if = ifp;
p->brt_age = 1;
- bridge_copyaddr(sa,
- (struct sockaddr *)&p->brt_tunnel);
+ bridge_copytag(brtag, &p->brt_tunnel);
if (setflags)
p->brt_flags = flags;
@@ -490,7 +487,7 @@ bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
sizeof(bareq.ifba_ifsname));
bcopy(&n->brt_addr, &bareq.ifba_dst,
sizeof(bareq.ifba_dst));
- bridge_copyaddr(&n->brt_tunnel.sa,
+ bridge_copyaddr(&n->brt_tunnel.brtag_src.sa,
(struct sockaddr *)&bareq.ifba_dstsa);
bareq.ifba_age = n->brt_age;
bareq.ifba_flags = n->brt_flags;
diff --git a/sys/net/if.h b/sys/net/if.h
index 3022b38482b..29d1cb074d9 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.h,v 1.177 2016/06/10 20:33:29 vgross Exp $ */
+/* $OpenBSD: if.h,v 1.178 2016/09/03 13:46:57 reyk Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
@@ -360,7 +360,7 @@ struct ifreq {
struct sockaddr ifru_broadaddr;
short ifru_flags;
int ifru_metric;
- uint32_t ifru_vnetid;
+ int64_t ifru_vnetid;
uint64_t ifru_media;
caddr_t ifru_data;
unsigned int ifru_index;
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 80c4b7e67ec..1b01b47c295 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.283 2016/09/02 10:01:36 goda Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.284 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -715,6 +715,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
struct bridge_rtnode *dst_p = NULL;
struct ether_addr *dst;
struct bridge_softc *sc;
+ struct bridge_tunneltag *brtag;
int error;
/* ifp must be a member interface of the bridge. */
@@ -811,9 +812,15 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
}
sendunicast:
- if (dst_p != NULL && dst_p->brt_tunnel.sa.sa_family != AF_UNSPEC &&
- (sa = bridge_tunneltag(m, dst_p->brt_tunnel.sa.sa_family)) != NULL)
- memcpy(sa, &dst_p->brt_tunnel.sa, dst_p->brt_tunnel.sa.sa_len);
+ if ((dst_p != NULL) &&
+ (dst_p->brt_tunnel.brtag_dst.sa.sa_family != AF_UNSPEC) &&
+ ((brtag = bridge_tunneltag(m)) != NULL)) {
+ memcpy(&brtag->brtag_src, &dst_p->brt_tunnel.brtag_src.sa,
+ dst_p->brt_tunnel.brtag_src.sa.sa_len);
+ memcpy(&brtag->brtag_dst, &dst_p->brt_tunnel.brtag_dst.sa,
+ dst_p->brt_tunnel.brtag_dst.sa.sa_len);
+ brtag->brtag_id = dst_p->brt_tunnel.brtag_id;
+ }
bridge_span(sc, m);
if ((dst_if->if_flags & IFF_RUNNING) == 0) {
@@ -1942,7 +1949,7 @@ bridge_send_icmp_err(struct bridge_softc *sc, struct ifnet *ifp,
m_freem(n);
}
-struct sockaddr *
+struct bridge_tunneltag *
bridge_tunnel(struct mbuf *m)
{
struct m_tag *mtag;
@@ -1950,41 +1957,24 @@ bridge_tunnel(struct mbuf *m)
if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL)
return (NULL);
- return ((struct sockaddr *)(mtag + 1));
+ return ((struct bridge_tunneltag *)(mtag + 1));
}
-struct sockaddr *
-bridge_tunneltag(struct mbuf *m, int af)
+struct bridge_tunneltag *
+bridge_tunneltag(struct mbuf *m)
{
- struct m_tag *mtag;
- size_t len;
- struct sockaddr *sa;
-
- if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL) {
- sa = (struct sockaddr *)(mtag + 1);
- if (sa->sa_family != af) {
- m_tag_delete(m, mtag);
- mtag = NULL;
- }
- }
- if (mtag == NULL) {
- if (af == AF_INET)
- len = sizeof(struct sockaddr_in);
- else if (af == AF_INET6)
- len = sizeof(struct sockaddr_in6);
- else
- return (NULL);
- mtag = m_tag_get(PACKET_TAG_TUNNEL, len, M_NOWAIT);
+ struct m_tag *mtag;
+
+ if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) {
+ mtag = m_tag_get(PACKET_TAG_TUNNEL,
+ sizeof(struct bridge_tunneltag), M_NOWAIT);
if (mtag == NULL)
return (NULL);
- bzero(mtag + 1, len);
- sa = (struct sockaddr *)(mtag + 1);
- sa->sa_family = af;
- sa->sa_len = len;
+ bzero(mtag + 1, sizeof(struct bridge_tunneltag));
m_tag_prepend(m, mtag);
}
- return ((struct sockaddr *)(mtag + 1));
+ return ((struct bridge_tunneltag *)(mtag + 1));
}
void
@@ -2000,6 +1990,20 @@ bridge_copyaddr(struct sockaddr *src, struct sockaddr *dst)
{
if (src != NULL && src->sa_family != AF_UNSPEC)
memcpy(dst, src, src->sa_len);
- else
+ else {
dst->sa_family = AF_UNSPEC;
+ dst->sa_len = 0;
+ }
+}
+
+void
+bridge_copytag(struct bridge_tunneltag *src, struct bridge_tunneltag *dst)
+{
+ if (src == NULL) {
+ memset(dst, 0, sizeof(*dst));
+ } else {
+ bridge_copyaddr(&src->brtag_src.sa, &dst->brtag_src.sa);
+ bridge_copyaddr(&src->brtag_dst.sa, &dst->brtag_dst.sa);
+ dst->brtag_id = src->brtag_id;
+ }
}
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index df1a3b9f534..95a5144c0ca 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.50 2016/09/02 10:01:36 goda Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.51 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
@@ -406,15 +406,24 @@ struct bridge_iflist {
((struct bridge_iflist *)_bp2)->bridge_sc)
/*
+ * Bridge tunnel tagging
+ */
+struct bridge_tunneltag {
+ union pfsockaddr_union brtag_src;
+ union pfsockaddr_union brtag_dst;
+ u_int32_t brtag_id;
+};
+
+/*
* Bridge route node
*/
struct bridge_rtnode {
LIST_ENTRY(bridge_rtnode) brt_next; /* next in list */
- struct ifnet *brt_if; /* destination ifs */
+ struct ifnet *brt_if; /* destination ifs */
u_int8_t brt_flags; /* address flags */
u_int8_t brt_age; /* age counter */
- struct ether_addr brt_addr; /* dst addr */
- union pfsockaddr_union brt_tunnel; /* tunnel endpoint */
+ struct ether_addr brt_addr; /* dst addr */
+ struct bridge_tunneltag brt_tunnel; /* tunnel endpoint */
};
#ifndef BRIDGE_RTABLE_SIZE
@@ -447,10 +456,11 @@ int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *,
void bridge_update(struct ifnet *, struct ether_addr *, int);
void bridge_rtdelete(struct bridge_softc *, struct ifnet *, int);
void bridge_rtagenode(struct ifnet *, int);
-struct sockaddr *bridge_tunnel(struct mbuf *);
-struct sockaddr *bridge_tunneltag(struct mbuf *, int);
+struct bridge_tunneltag *bridge_tunnel(struct mbuf *);
+struct bridge_tunneltag *bridge_tunneltag(struct mbuf *);
void bridge_tunneluntag(struct mbuf *);
void bridge_copyaddr(struct sockaddr *, struct sockaddr *);
+void bridge_copytag(struct bridge_tunneltag *, struct bridge_tunneltag *);
struct bstp_state *bstp_create(struct ifnet *);
void bstp_destroy(struct bstp_state *);
diff --git a/sys/net/if_switch.c b/sys/net/if_switch.c
index 8f481583981..c0032f93749 100644
--- a/sys/net/if_switch.c
+++ b/sys/net/if_switch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_switch.c,v 1.2 2016/09/02 10:01:36 goda Exp $ */
+/* $OpenBSD: if_switch.c,v 1.3 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
@@ -1376,6 +1376,43 @@ switch_flow_classifier_ether(struct mbuf *m, int *offset,
}
struct mbuf *
+switch_flow_classifier_tunnel(struct mbuf *m, int *offset,
+ struct switch_flow_classify *swfcl)
+{
+ struct bridge_tunneltag *brtag;
+
+ if ((brtag = bridge_tunnel(m)) == NULL)
+ goto out;
+
+ if ((brtag->brtag_dst.sa.sa_family != AF_INET) &&
+ (brtag->brtag_dst.sa.sa_family != AF_INET6))
+ goto out;
+
+ swfcl->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
+ if (swfcl->swfcl_tunnel == NULL) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ swfcl->swfcl_tunnel->tun_af = brtag->brtag_dst.sa.sa_family;
+ swfcl->swfcl_tunnel->tun_key = htobe64(brtag->brtag_id);
+ if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
+ swfcl->swfcl_tunnel->tun_ipv4_src =
+ brtag->brtag_src.sin.sin_addr;
+ swfcl->swfcl_tunnel->tun_ipv4_dst =
+ brtag->brtag_dst.sin.sin_addr;
+ } else {
+ swfcl->swfcl_tunnel->tun_ipv6_src =
+ brtag->brtag_src.sin6.sin6_addr;
+ swfcl->swfcl_tunnel->tun_ipv6_dst =
+ brtag->brtag_dst.sin6.sin6_addr;
+ }
+ bridge_tunneluntag(m);
+ out:
+ return switch_flow_classifier_ether(m, offset, swfcl);
+}
+
+struct mbuf *
switch_flow_classifier(struct mbuf *m, uint32_t in_port,
struct switch_flow_classify *swfcl)
{
@@ -1384,7 +1421,7 @@ switch_flow_classifier(struct mbuf *m, uint32_t in_port,
memset(swfcl, 0, sizeof(*swfcl));
swfcl->swfcl_in_port = in_port;
- return switch_flow_classifier_ether(m, &offset, swfcl);
+ return switch_flow_classifier_tunnel(m, &offset, swfcl);
}
void
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 0aa47d77fb0..7b23bf8dee8 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vlan.c,v 1.165 2016/05/18 03:46:03 dlg Exp $ */
+/* $OpenBSD: if_vlan.c,v 1.166 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright 1998 Massachusetts Institute of Technology
@@ -648,15 +648,16 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCSVNETID:
- tag = ifr->ifr_vnetid;
- if (tag == ifv->ifv_tag)
- break;
-
- if (tag < EVL_VLID_MIN || tag > EVL_VLID_MAX) {
+ if (ifr->ifr_vnetid < EVL_VLID_MIN ||
+ ifr->ifr_vnetid > EVL_VLID_MAX) {
error = EINVAL;
break;
}
+ tag = ifr->ifr_vnetid;
+ if (tag == ifv->ifv_tag)
+ break;
+
error = vlan_set_vnetid(ifv, tag);
break;
@@ -664,7 +665,7 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifv->ifv_tag == EVL_VLID_NULL)
error = EADDRNOTAVAIL;
else
- ifr->ifr_vnetid = (uint32_t)ifv->ifv_tag;
+ ifr->ifr_vnetid = (int64_t)ifv->ifv_tag;
break;
case SIOCDVNETID:
diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c
index 3cd59a79b5b..4050030d9ad 100644
--- a/sys/net/if_vxlan.c
+++ b/sys/net/if_vxlan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vxlan.c,v 1.42 2016/08/07 14:26:26 reyk Exp $ */
+/* $OpenBSD: if_vxlan.c,v 1.43 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
@@ -70,7 +70,7 @@ struct vxlan_softc {
struct sockaddr_storage sc_dst;
in_port_t sc_dstport;
u_int sc_rdomain;
- int sc_vnetid;
+ int64_t sc_vnetid;
u_int8_t sc_ttl;
LIST_ENTRY(vxlan_softc) sc_entry;
@@ -103,15 +103,19 @@ u_long vxlan_tagmask;
#define VXLAN_TAGHASHSIZE 32
#define VXLAN_TAGHASH(tag) ((unsigned int)tag & vxlan_tagmask)
-LIST_HEAD(vxlan_taghash, vxlan_softc) *vxlan_tagh;
+LIST_HEAD(vxlan_taghash, vxlan_softc) *vxlan_tagh, vxlan_any;
void
vxlanattach(int count)
{
+ /* Regular vxlan interfaces with a VNI */
if ((vxlan_tagh = hashinit(VXLAN_TAGHASHSIZE, M_DEVBUF, M_NOWAIT,
&vxlan_tagmask)) == NULL)
panic("vxlanattach: hashinit");
+ /* multipoint-to-multipoint interfaces that accept any VNI */
+ LIST_INIT(&vxlan_any);
+
if_clone_attach(&vxlan_cloner);
}
@@ -316,6 +320,7 @@ vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
int reset = 0, error, af;
socklen_t slen;
in_port_t port;
+ struct vxlan_taghash *tagh;
if (src != NULL && dst != NULL) {
if ((af = src->sa_family) != dst->sa_family)
@@ -354,9 +359,17 @@ vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
memcpy(&sc->sc_dst, dst, dst->sa_len);
}
+ if (sc->sc_vnetid == VXLAN_VNI_ANY) {
+ /*
+ * If the interface accepts any VNI, put it into a separate
+ * list that is not part of the main hash.
+ */
+ tagh = &vxlan_any;
+ } else
+ tagh = &vxlan_tagh[VXLAN_TAGHASH(sc->sc_vnetid)];
+
LIST_REMOVE(sc, sc_entry);
- LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(sc->sc_vnetid)],
- sc, sc_entry);
+ LIST_INSERT_HEAD(tagh, sc, sc_entry);
return (0);
}
@@ -454,10 +467,16 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCSVNETID:
- if (ifr->ifr_vnetid > VXLAN_VNI_MAX) {
+ if (sc->sc_vnetid == ifr->ifr_vnetid)
+ break;
+
+ if ((ifr->ifr_vnetid != VXLAN_VNI_ANY) &&
+ (ifr->ifr_vnetid > VXLAN_VNI_MAX ||
+ ifr->ifr_vnetid < VXLAN_VNI_MIN)) {
error = EINVAL;
break;
}
+
s = splnet();
sc->sc_vnetid = (int)ifr->ifr_vnetid;
(void)vxlan_config(ifp, NULL, NULL);
@@ -465,11 +484,14 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case SIOCGVNETID:
- if (sc->sc_vnetid == VXLAN_VNI_UNSET) {
+ if ((sc->sc_vnetid != VXLAN_VNI_ANY) &&
+ (sc->sc_vnetid > VXLAN_VNI_MAX ||
+ sc->sc_vnetid < VXLAN_VNI_MIN)) {
error = EADDRNOTAVAIL;
break;
}
- ifr->ifr_vnetid = (uint32_t)sc->sc_vnetid;
+
+ ifr->ifr_vnetid = sc->sc_vnetid;
break;
case SIOCDVNETID:
@@ -496,7 +518,6 @@ vxlan_media_change(struct ifnet *ifp)
void
vxlan_media_status(struct ifnet *ifp, struct ifmediareq *imr)
{
- imr->ifm_active = IFM_ETHER | IFM_AUTO;
imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
}
@@ -547,7 +568,7 @@ vxlan_sockaddr_port(struct sockaddr *sa)
int
vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
- struct sockaddr *srcsa)
+ struct sockaddr *srcsa, struct sockaddr *dstsa)
{
struct mbuf_list ml = MBUF_LIST_INITIALIZER();
struct vxlan_softc *sc = NULL, *sc_cand = NULL;
@@ -557,7 +578,7 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
int skip;
struct ether_header *eh;
#if NBRIDGE > 0
- struct sockaddr *sa;
+ struct bridge_tunneltag *brtag;
#endif
/* XXX Should verify the UDP port first before copying the packet */
@@ -579,6 +600,7 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
vni = VXLAN_VNI_UNSET;
}
+ /* First search for a vxlan(4) interface with the packet's VNI */
LIST_FOREACH(sc, &vxlan_tagh[VXLAN_TAGHASH(vni)], sc_entry) {
if ((uh->uh_dport == sc->sc_dstport) &&
vni == sc->sc_vnetid &&
@@ -590,6 +612,21 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
}
}
+ /*
+ * Now loop through all the vxlan(4) interfaces that are configured
+ * to accept any VNI and operating in multipoint-to-multipoint mode
+ * that is used in combination with bridge(4) or switch(4).
+ * If a vxlan(4) interface has been found for the packet's VNI, this
+ * code is not reached as the other interface is more specific.
+ */
+ LIST_FOREACH(sc, &vxlan_any, sc_entry) {
+ if ((uh->uh_dport == sc->sc_dstport) &&
+ (sc->sc_rdomain == rtable_l2(m->m_pkthdr.ph_rtableid))) {
+ sc_cand = sc;
+ goto found;
+ }
+ }
+
if (sc_cand) {
sc = sc_cand;
goto found;
@@ -606,11 +643,14 @@ vxlan_lookup(struct mbuf *m, struct udphdr *uh, int iphlen,
return (EINVAL);
#if NBRIDGE > 0
- /* Store the peer IP address for the bridge */
- if (ifp->if_bridgeport != NULL &&
+ /* Store the tunnel src/dst IP and vni for the bridge or switch */
+ if ((ifp->if_bridgeport != NULL || ifp->if_switchport != NULL) &&
srcsa->sa_family != AF_UNSPEC &&
- (sa = bridge_tunneltag(m, srcsa->sa_family)) != NULL)
- memcpy(sa, srcsa, sa->sa_len);
+ ((brtag = bridge_tunneltag(m)) != NULL)) {
+ memcpy(&brtag->brtag_src.sa, srcsa, srcsa->sa_len);
+ memcpy(&brtag->brtag_dst.sa, dstsa, dstsa->sa_len);
+ brtag->brtag_id = vni;
+ }
#endif
m->m_flags &= ~(M_MCAST|M_BCAST);
@@ -712,9 +752,10 @@ vxlan_output(struct ifnet *ifp, struct mbuf *m)
struct vxlanudphdr *vu;
struct sockaddr *src, *dst;
#if NBRIDGE > 0
- struct sockaddr *brtag;
+ struct bridge_tunneltag *brtag;
#endif
int error, af;
+ uint32_t tag;
/* VXLAN header */
M_PREPEND(m, sizeof(*vu), M_DONTWAIT);
@@ -732,10 +773,18 @@ vxlan_output(struct ifnet *ifp, struct mbuf *m)
vu->vu_u.uh_dport = sc->sc_dstport;
vu->vu_u.uh_ulen = htons(m->m_pkthdr.len);
vu->vu_u.uh_sum = 0;
+ tag = sc->sc_vnetid;
#if NBRIDGE > 0
if ((brtag = bridge_tunnel(m)) != NULL) {
- dst = brtag;
+ dst = &brtag->brtag_dst.sa;
+
+ /* If accepting any VNI, source ip address is from brtag */
+ if (sc->sc_vnetid == VXLAN_VNI_ANY) {
+ src = &brtag->brtag_src.sa;
+ tag = (uint32_t)brtag->brtag_id;
+ af = src->sa_family;
+ }
if (dst->sa_family != af) {
ifp->if_oerrors++;
@@ -750,12 +799,21 @@ vxlan_output(struct ifnet *ifp, struct mbuf *m)
*/
if (ifp->if_flags & IFF_LINK0)
vu->vu_u.uh_dport = vxlan_sockaddr_port(dst);
- }
+ } else
#endif
+ if (sc->sc_vnetid == VXLAN_VNI_ANY) {
+ /*
+ * If accepting any VNI, build the vxlan header only by
+ * bridge_tunneltag or drop packet if the tag does not exist.
+ */
+ ifp->if_oerrors++;
+ m_freem(m);
+ return (ENETUNREACH);
+ }
if (sc->sc_vnetid != VXLAN_VNI_UNSET) {
vu->vu_v.vxlan_flags = htonl(VXLAN_FLAGS_VNI);
- vu->vu_v.vxlan_id = htonl(sc->sc_vnetid << VXLAN_VNI_S);
+ vu->vu_v.vxlan_id = htonl(tag << VXLAN_VNI_S);
} else {
vu->vu_v.vxlan_flags = htonl(0);
vu->vu_v.vxlan_id = htonl(0);
diff --git a/sys/net/if_vxlan.h b/sys/net/if_vxlan.h
index c6ed25b8d66..33968772e4d 100644
--- a/sys/net/if_vxlan.h
+++ b/sys/net/if_vxlan.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_vxlan.h,v 1.10 2016/08/07 13:49:12 reyk Exp $ */
+/* $OpenBSD: if_vxlan.h,v 1.11 2016/09/03 13:46:57 reyk Exp $ */
/*
* Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
@@ -34,7 +34,9 @@ struct vxlan_header {
} __packed;
#define VXLAN_VNI_MAX 0x00ffffff /* 24bit vnetid */
-#define VXLAN_VNI_UNSET 0xffffffff /* -1 */
+#define VXLAN_VNI_MIN 0x00000000 /* 24bit vnetid */
+#define VXLAN_VNI_UNSET 0x01ffffff /* used internally */
+#define VXLAN_VNI_ANY -1ULL /* -1 accept any vnetid */
struct vxlanudphdr {
struct udphdr vu_u;
@@ -45,7 +47,7 @@ struct vxlanudphdr {
extern int vxlan_enable;
int vxlan_lookup(struct mbuf *, struct udphdr *, int,
- struct sockaddr *);
+ struct sockaddr *, struct sockaddr *);
struct sockaddr *vxlan_tag_find(struct mbuf *);
struct sockaddr *vxlan_tag_get(struct mbuf *, int);
void vxlan_tag_delete(struct mbuf *);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 01b6c5b64ef..60a7bdf41bd 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.218 2016/08/16 22:21:17 vgross Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.219 2016/09/03 13:46:57 reyk Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -173,7 +173,7 @@ udp_input(struct mbuf *m, ...)
#ifdef INET6
struct sockaddr_in6 sin6;
#endif /* INET6 */
- } srcsa;
+ } srcsa, dstsa;
#ifdef INET6
struct ip6_hdr *ip6;
#endif /* INET6 */
@@ -353,6 +353,12 @@ udp_input(struct mbuf *m, ...)
srcsa.sin.sin_family = AF_INET;
srcsa.sin.sin_port = uh->uh_sport;
srcsa.sin.sin_addr = ip->ip_src;
+
+ bzero(&dstsa, sizeof(struct sockaddr_in));
+ dstsa.sin.sin_len = sizeof(struct sockaddr_in);
+ dstsa.sin.sin_family = AF_INET;
+ dstsa.sin.sin_port = uh->uh_dport;
+ dstsa.sin.sin_addr = ip->ip_dst;
break;
#ifdef INET6
case AF_INET6:
@@ -365,6 +371,16 @@ udp_input(struct mbuf *m, ...)
#endif
/* KAME hack: recover scopeid */
in6_recoverscope(&srcsa.sin6, &ip6->ip6_src);
+
+ bzero(&dstsa, sizeof(struct sockaddr_in6));
+ dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ dstsa.sin6.sin6_family = AF_INET6;
+ dstsa.sin6.sin6_port = uh->uh_dport;
+#if 0 /*XXX inbound flowinfo */
+ dstsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ip6->ip6_flow;
+#endif
+ /* KAME hack: recover scopeid */
+ in6_recoverscope(&dstsa.sin6, &ip6->ip6_dst);
break;
#endif /* INET6 */
}
@@ -374,7 +390,7 @@ udp_input(struct mbuf *m, ...)
#if NPF > 0
!(m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) &&
#endif
- (error = vxlan_lookup(m, uh, iphlen, &srcsa.sa)) != 0) {
+ (error = vxlan_lookup(m, uh, iphlen, &srcsa.sa, &dstsa.sa)) != 0) {
if (error == -1) {
udpstat.udps_hdrops++;
m_freem(m);