Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 334009
b: refs/heads/master
c: 05f47d6
h: refs/heads/master
i:
  334007: 64664e6
v: v3
  • Loading branch information
stephen hemminger authored and David S. Miller committed Oct 11, 2012
1 parent 1ece0ef commit 3399f77
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1cad87156b3e79d25731cdcbfa9e149bf3e08f60
refs/heads/master: 05f47d69c44902c265dc2ad5a960978a97b45e3d
62 changes: 57 additions & 5 deletions trunk/drivers/net/vxlan.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ struct vxlan_dev {
__be32 gaddr; /* multicast group */
__be32 saddr; /* source address */
unsigned int link; /* link to multicast over */
__u16 port_min; /* source port range */
__u16 port_max;
__u8 tos; /* TOS override */
__u8 ttl;
bool learn;
Expand Down Expand Up @@ -654,12 +656,29 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
skb->destructor = vxlan_sock_free;
}

/* Compute source port for outgoing packet
* first choice to use L4 flow hash since it will spread
* better and maybe available from hardware
* secondary choice is to use jhash on the Ethernet header
*/
static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
{
unsigned int range = (vxlan->port_max - vxlan->port_min) + 1;
u32 hash;

hash = skb_get_rxhash(skb);
if (!hash)
hash = jhash(skb->data, 2 * ETH_ALEN,
(__force u32) skb->protocol);

return (((u64) hash * range) >> 32) + vxlan->port_min;
}

/* Transmit local packets over Vxlan
*
* Outer IP header inherits ECN and DF from inner header.
* Outer UDP destination is the VXLAN assigned port.
* source port is based on hash of flow if available
* otherwise use a random value
* source port is based on hash of flow
*/
static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
{
Expand All @@ -671,8 +690,8 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
struct udphdr *uh;
struct flowi4 fl4;
unsigned int pkt_len = skb->len;
u32 hash;
__be32 dst;
__u16 src_port;
__be16 df = 0;
__u8 tos, ttl;
int err;
Expand All @@ -695,7 +714,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
if (tos == 1)
tos = vxlan_get_dsfield(old_iph, skb);

hash = skb_get_rxhash(skb);
src_port = vxlan_src_port(vxlan, skb);

memset(&fl4, 0, sizeof(fl4));
fl4.flowi4_oif = vxlan->link;
Expand Down Expand Up @@ -732,7 +751,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
uh = udp_hdr(skb);

uh->dest = htons(vxlan_port);
uh->source = hash ? :random32();
uh->source = htons(src_port);

uh->len = htons(skb->len);
uh->check = 0;
Expand Down Expand Up @@ -960,6 +979,7 @@ static void vxlan_setup(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
unsigned h;
int low, high;

eth_hw_addr_random(dev);
ether_setup(dev);
Expand All @@ -979,6 +999,10 @@ static void vxlan_setup(struct net_device *dev)
vxlan->age_timer.function = vxlan_cleanup;
vxlan->age_timer.data = (unsigned long) vxlan;

inet_get_local_port_range(&low, &high);
vxlan->port_min = low;
vxlan->port_max = high;

vxlan->dev = dev;

for (h = 0; h < FDB_HASH_SIZE; ++h)
Expand All @@ -995,6 +1019,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
[IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
[IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
[IFLA_VXLAN_PORT_RANGE] = { .len = sizeof(struct ifla_vxlan_port_range) },
};

static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
Expand Down Expand Up @@ -1027,6 +1052,18 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
return -EADDRNOTAVAIL;
}
}

if (data[IFLA_VXLAN_PORT_RANGE]) {
const struct ifla_vxlan_port_range *p
= nla_data(data[IFLA_VXLAN_PORT_RANGE]);

if (ntohs(p->high) < ntohs(p->low)) {
pr_debug("port range %u .. %u not valid\n",
ntohs(p->low), ntohs(p->high));
return -EINVAL;
}
}

return 0;
}

Expand Down Expand Up @@ -1077,6 +1114,13 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
if (data[IFLA_VXLAN_LIMIT])
vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]);

if (data[IFLA_VXLAN_PORT_RANGE]) {
const struct ifla_vxlan_port_range *p
= nla_data(data[IFLA_VXLAN_PORT_RANGE]);
vxlan->port_min = ntohs(p->low);
vxlan->port_max = ntohs(p->high);
}

err = register_netdevice(dev);
if (!err)
hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
Expand Down Expand Up @@ -1105,12 +1149,17 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */
nla_total_size(sizeof(struct ifla_vxlan_port_range)) +
0;
}

static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
const struct vxlan_dev *vxlan = netdev_priv(dev);
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))
goto nla_put_failure;
Expand All @@ -1131,6 +1180,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax))
goto nla_put_failure;

if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
goto nla_put_failure;

return 0;

nla_put_failure:
Expand Down
6 changes: 6 additions & 0 deletions trunk/include/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,16 @@ enum {
IFLA_VXLAN_LEARNING,
IFLA_VXLAN_AGEING,
IFLA_VXLAN_LIMIT,
IFLA_VXLAN_PORT_RANGE,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)

struct ifla_vxlan_port_range {
__be16 low;
__be16 high;
};

/* SR-IOV virtual function management section */

enum {
Expand Down

0 comments on commit 3399f77

Please sign in to comment.