Skip to content

Commit

Permalink
vxlan: Allow setting destination to unicast address.
Browse files Browse the repository at this point in the history
This patch allows setting VXLAN destination to unicast address.
It allows that VXLAN can be used as peer-to-peer tunnel without
multicast.

v4: generalize struct vxlan_dev, "gaddr" is replaced with vxlan_rdst.
    "GROUP" attribute is replaced with "REMOTE".
    they are based by David Stevens's comments.

v3: move a new attribute REMOTE into the last of an enum list
    based by Stephen Hemminger's comments.

v2: use a new attribute REMOTE instead of GROUP based by
    Cong Wang's comments.

Signed-off-by: Atzm Watanabe <atzm@stratosphere.co.jp>
Acked-by: David L Stevens <dlstevens@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Atzm Watanabe authored and David S. Miller committed Apr 16, 2013
1 parent 184f489 commit c7995c4
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 44 deletions.
73 changes: 30 additions & 43 deletions drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,8 @@ struct vxlan_fdb {
struct vxlan_dev {
struct hlist_node hlist;
struct net_device *dev;
__u32 vni; /* virtual network id */
__be32 gaddr; /* multicast group */
struct vxlan_rdst default_dst; /* default destination */
__be32 saddr; /* source address */
unsigned int link; /* link to multicast over */
__u16 port_min; /* source port range */
__u16 port_max;
__u8 tos; /* TOS override */
Expand Down Expand Up @@ -146,7 +144,7 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id)
struct vxlan_dev *vxlan;

hlist_for_each_entry_rcu(vxlan, vni_head(net, id), hlist) {
if (vxlan->vni == id)
if (vxlan->default_dst.remote_vni == id)
return vxlan;
}

Expand Down Expand Up @@ -194,7 +192,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (rdst->remote_port && rdst->remote_port != vxlan_port &&
nla_put_be16(skb, NDA_PORT, rdst->remote_port))
goto nla_put_failure;
if (rdst->remote_vni != vxlan->vni &&
if (rdst->remote_vni != vxlan->default_dst.remote_vni &&
nla_put_be32(skb, NDA_VNI, rdst->remote_vni))
goto nla_put_failure;
if (rdst->remote_ifindex &&
Expand Down Expand Up @@ -465,7 +463,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return -EINVAL;
vni = nla_get_u32(tb[NDA_VNI]);
} else
vni = vxlan->vni;
vni = vxlan->default_dst.remote_vni;

if (tb[NDA_IFINDEX]) {
struct net_device *tdev;
Expand Down Expand Up @@ -570,7 +568,7 @@ static void vxlan_snoop(struct net_device *dev,
err = vxlan_fdb_create(vxlan, src_mac, src_ip,
NUD_REACHABLE,
NLM_F_EXCL|NLM_F_CREATE,
vxlan_port, vxlan->vni, 0);
vxlan_port, vxlan->default_dst.remote_vni, 0);
spin_unlock(&vxlan->hash_lock);
}
}
Expand All @@ -591,7 +589,7 @@ static bool vxlan_group_used(struct vxlan_net *vn,
if (!netif_running(vxlan->dev))
continue;

if (vxlan->gaddr == this->gaddr)
if (vxlan->default_dst.remote_ip == this->default_dst.remote_ip)
return true;
}

Expand All @@ -605,8 +603,8 @@ static int vxlan_join_group(struct net_device *dev)
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct sock *sk = vn->sock->sk;
struct ip_mreqn mreq = {
.imr_multiaddr.s_addr = vxlan->gaddr,
.imr_ifindex = vxlan->link,
.imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
.imr_ifindex = vxlan->default_dst.remote_ifindex,
};
int err;

Expand All @@ -633,8 +631,8 @@ static int vxlan_leave_group(struct net_device *dev)
int err = 0;
struct sock *sk = vn->sock->sk;
struct ip_mreqn mreq = {
.imr_multiaddr.s_addr = vxlan->gaddr,
.imr_ifindex = vxlan->link,
.imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
.imr_ifindex = vxlan->default_dst.remote_ifindex,
};

/* Only leave group when last vxlan is done. */
Expand Down Expand Up @@ -1091,7 +1089,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
struct ethhdr *eth;
bool did_rsc = false;
struct vxlan_rdst group, *rdst0, *rdst;
struct vxlan_rdst *rdst0, *rdst;
struct vxlan_fdb *f;
int rc1, rc;

Expand All @@ -1106,14 +1104,9 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
f = vxlan_find_mac(vxlan, eth->h_dest);
if (f == NULL) {
did_rsc = false;
group.remote_port = vxlan_port;
group.remote_vni = vxlan->vni;
group.remote_ip = vxlan->gaddr;
group.remote_ifindex = vxlan->link;
group.remote_next = NULL;
rdst0 = &group;

if (group.remote_ip == htonl(INADDR_ANY) &&
rdst0 = &vxlan->default_dst;

if (rdst0->remote_ip == htonl(INADDR_ANY) &&
(vxlan->flags & VXLAN_F_L2MISS) &&
!is_multicast_ether_addr(eth->h_dest))
vxlan_fdb_miss(vxlan, eth->h_dest);
Expand Down Expand Up @@ -1191,7 +1184,7 @@ static int vxlan_open(struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
int err;

if (vxlan->gaddr) {
if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
err = vxlan_join_group(dev);
if (err)
return err;
Expand Down Expand Up @@ -1225,7 +1218,7 @@ static int vxlan_stop(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);

if (vxlan->gaddr)
if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)))
vxlan_leave_group(dev);

del_timer_sync(&vxlan->age_timer);
Expand Down Expand Up @@ -1311,7 +1304,7 @@ static void vxlan_setup(struct net_device *dev)

static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_ID] = { .type = NLA_U32 },
[IFLA_VXLAN_GROUP] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
[IFLA_VXLAN_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
[IFLA_VXLAN_LINK] = { .type = NLA_U32 },
[IFLA_VXLAN_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
[IFLA_VXLAN_TOS] = { .type = NLA_U8 },
Expand Down Expand Up @@ -1349,14 +1342,6 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
return -ERANGE;
}

if (data[IFLA_VXLAN_GROUP]) {
__be32 gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
if (!IN_MULTICAST(ntohl(gaddr))) {
pr_debug("group address is not IPv4 multicast\n");
return -EADDRNOTAVAIL;
}
}

if (data[IFLA_VXLAN_PORT_RANGE]) {
const struct ifla_vxlan_port_range *p
= nla_data(data[IFLA_VXLAN_PORT_RANGE]);
Expand Down Expand Up @@ -1387,6 +1372,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
__u32 vni;
int err;

Expand All @@ -1398,21 +1384,21 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
pr_info("duplicate VNI %u\n", vni);
return -EEXIST;
}
vxlan->vni = vni;
dst->remote_vni = vni;

if (data[IFLA_VXLAN_GROUP])
vxlan->gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
if (data[IFLA_VXLAN_REMOTE])
dst->remote_ip = nla_get_be32(data[IFLA_VXLAN_REMOTE]);

if (data[IFLA_VXLAN_LOCAL])
vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]);

if (data[IFLA_VXLAN_LINK] &&
(vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
(dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
struct net_device *lowerdev
= __dev_get_by_index(net, vxlan->link);
= __dev_get_by_index(net, dst->remote_ifindex);

if (!lowerdev) {
pr_info("ifindex %d does not exist\n", vxlan->link);
pr_info("ifindex %d does not exist\n", dst->remote_ifindex);
return -ENODEV;
}

Expand Down Expand Up @@ -1464,7 +1450,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,

err = register_netdevice(dev);
if (!err)
hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
hlist_add_head_rcu(&vxlan->hlist, vni_head(net, dst->remote_vni));

return err;
}
Expand All @@ -1482,7 +1468,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
{

return nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_ID */
nla_total_size(sizeof(__be32)) +/* IFLA_VXLAN_GROUP */
nla_total_size(sizeof(__be32)) +/* IFLA_VXLAN_REMOTE */
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LINK */
nla_total_size(sizeof(__be32))+ /* IFLA_VXLAN_LOCAL */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL */
Expand All @@ -1501,18 +1487,19 @@ static size_t vxlan_get_size(const struct net_device *dev)
static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
const struct vxlan_dev *vxlan = netdev_priv(dev);
const struct vxlan_rdst *dst = &vxlan->default_dst;
struct ifla_vxlan_port_range ports = {
.low = htons(vxlan->port_min),
.high = htons(vxlan->port_max),
};

if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni))
if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni))
goto nla_put_failure;

if (vxlan->gaddr && nla_put_be32(skb, IFLA_VXLAN_GROUP, vxlan->gaddr))
if (dst->remote_ip && nla_put_be32(skb, IFLA_VXLAN_REMOTE, dst->remote_ip))
goto nla_put_failure;

if (vxlan->link && nla_put_u32(skb, IFLA_VXLAN_LINK, vxlan->link))
if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
goto nla_put_failure;

if (vxlan->saddr && nla_put_be32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
Expand Down
2 changes: 1 addition & 1 deletion include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ enum macvlan_mode {
enum {
IFLA_VXLAN_UNSPEC,
IFLA_VXLAN_ID,
IFLA_VXLAN_GROUP,
IFLA_VXLAN_REMOTE,
IFLA_VXLAN_LINK,
IFLA_VXLAN_LOCAL,
IFLA_VXLAN_TTL,
Expand Down

0 comments on commit c7995c4

Please sign in to comment.