From f53adae4eae5ad9f7343ff4a0fc68b468c981138 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 8 Apr 2013 04:01:30 +0000 Subject: net: ipv6: add tokenized interface identifier support This patch adds support for IPv6 tokenized IIDs, that allow for administrators to assign well-known host-part addresses to nodes whilst still obtaining global network prefix from Router Advertisements. It is currently in draft status. The primary target for such support is server platforms where addresses are usually manually configured, rather than using DHCPv6 or SLAAC. By using tokenised identifiers, hosts can still determine their network prefix by use of SLAAC, but more readily be automatically renumbered should their network prefix change. [...] The disadvantage with static addresses is that they are likely to require manual editing should the network prefix in use change. If instead there were a method to only manually configure the static identifier part of the IPv6 address, then the address could be automatically updated when a new prefix was introduced, as described in [RFC4192] for example. In such cases a DNS server might be configured with such a tokenised interface identifier of ::53, and SLAAC would use the token in constructing the interface address, using the advertised prefix. [...] http://tools.ietf.org/html/draft-chown-6man-tokenised-ipv6-identifiers-02 The implementation is partially based on top of Mark K. Thompson's proof of concept. However, it uses the Netlink interface for configuration resp. data retrival, so that it can be easily extended in future. Successfully tested by myself. Cc: Hannes Frederic Sowa Cc: YOSHIFUJI Hideaki Cc: Thomas Graf Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/uapi/linux/if_link.h') diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index c4edfe11f1f7..6b35c4211f65 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -201,6 +201,7 @@ enum { IFLA_INET6_MCAST, /* MC things. What of them? */ IFLA_INET6_CACHEINFO, /* time values and max reasm size */ IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ + IFLA_INET6_TOKEN, /* device token */ __IFLA_INET6_MAX }; -- cgit v1.2.3 From c7995c43facc6e5dea4de63fa9d283a337aabeb1 Mon Sep 17 00:00:00 2001 From: Atzm Watanabe Date: Tue, 16 Apr 2013 02:50:52 +0000 Subject: vxlan: Allow setting destination to unicast address. 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 Acked-by: David L Stevens Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 73 ++++++++++++++++++-------------------------- include/uapi/linux/if_link.h | 2 +- 2 files changed, 31 insertions(+), 44 deletions(-) (limited to 'include/uapi/linux/if_link.h') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 97a306c9e65d..916a62149a12 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -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 */ @@ -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; } @@ -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 && @@ -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; @@ -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); } } @@ -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; } @@ -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; @@ -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. */ @@ -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; @@ -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); @@ -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; @@ -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); @@ -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 }, @@ -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]); @@ -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; @@ -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; } @@ -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; } @@ -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 */ @@ -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)) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 6b35c4211f65..9922704f08af 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -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, -- cgit v1.2.3 From 8ad227ff89a7e6f05d07cd0acfd95ed3a24450ca Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 19 Apr 2013 02:04:31 +0000 Subject: net: vlan: add 802.1ad support Add support for 802.1ad VLAN devices. This mainly consists of checking for ETH_P_8021AD in addition to ETH_P_8021Q in a couple of places and check offloading capabilities based on the used protocol. Configuration is done using "ip link": # ip link add link eth0 eth0.1000 \ type vlan proto 802.1ad id 1000 # ip link add link eth0.1000 eth0.1000.1000 \ type vlan proto 802.1q id 1000 52:54:00:12:34:56 > 92:b1:54:28:e4:8c, ethertype 802.1Q (0x8100), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) 20.1.0.2 > 20.1.0.1: ICMP echo request, id 3003, seq 8, length 64 92:b1:54:28:e4:8c > 52:54:00:12:34:56, ethertype 802.1Q-QinQ (0x88a8), length 106: vlan 1000, p 0, ethertype 802.1Q, vlan 1000, p 0, ethertype IPv4, (tos 0x0, ttl 64, id 47944, offset 0, flags [none], proto ICMP (1), length 84) 20.1.0.1 > 20.1.0.2: ICMP echo reply, id 3003, seq 8, length 64 Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 6 ++++-- include/linux/netdev_features.h | 6 ++++++ include/uapi/linux/if_link.h | 1 + net/8021q/Kconfig | 2 +- net/8021q/vlan.h | 3 +++ net/8021q/vlan_core.c | 18 ++++++++++++++---- net/8021q/vlan_netlink.c | 25 ++++++++++++++++++++++--- net/core/dev.c | 16 ++++++++++------ 8 files changed, 61 insertions(+), 16 deletions(-) (limited to 'include/uapi/linux/if_link.h') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 8086ff9988b1..a78f9390da87 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -162,6 +162,8 @@ static inline bool vlan_hw_offload_capable(netdev_features_t features, { if (proto == htons(ETH_P_8021Q) && features & NETIF_F_HW_VLAN_CTAG_TX) return true; + if (proto == htons(ETH_P_8021AD) && features & NETIF_F_HW_VLAN_STAG_TX) + return true; return false; } @@ -271,9 +273,9 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) { struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; - if (veth->h_vlan_proto != htons(ETH_P_8021Q)) { + if (veth->h_vlan_proto != htons(ETH_P_8021Q) && + veth->h_vlan_proto != htons(ETH_P_8021AD)) return -EINVAL; - } *vlan_tci = ntohs(veth->h_vlan_TCI); return 0; diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index 785913b8983d..cbaa027ef5a7 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h @@ -25,6 +25,9 @@ enum { NETIF_F_HW_VLAN_CTAG_TX_BIT, /* Transmit VLAN CTAG HW acceleration */ NETIF_F_HW_VLAN_CTAG_RX_BIT, /* Receive VLAN CTAG HW acceleration */ NETIF_F_HW_VLAN_CTAG_FILTER_BIT,/* Receive filtering on VLAN CTAGs */ + NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */ + NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */ + NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */ NETIF_F_VLAN_CHALLENGED_BIT, /* Device cannot handle VLAN packets */ NETIF_F_GSO_BIT, /* Enable software GSO. */ NETIF_F_LLTX_BIT, /* LockLess TX - deprecated. Please */ @@ -83,6 +86,9 @@ enum { #define NETIF_F_HW_VLAN_CTAG_FILTER __NETIF_F(HW_VLAN_CTAG_FILTER) #define NETIF_F_HW_VLAN_CTAG_RX __NETIF_F(HW_VLAN_CTAG_RX) #define NETIF_F_HW_VLAN_CTAG_TX __NETIF_F(HW_VLAN_CTAG_TX) +#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) +#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) +#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) #define NETIF_F_IP_CSUM __NETIF_F(IP_CSUM) #define NETIF_F_IPV6_CSUM __NETIF_F(IPV6_CSUM) #define NETIF_F_LLTX __NETIF_F(LLTX) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 9922704f08af..e3163544f339 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -250,6 +250,7 @@ enum { IFLA_VLAN_FLAGS, IFLA_VLAN_EGRESS_QOS, IFLA_VLAN_INGRESS_QOS, + IFLA_VLAN_PROTOCOL, __IFLA_VLAN_MAX, }; diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig index 8f7517df41a5..b85a91fa61f1 100644 --- a/net/8021q/Kconfig +++ b/net/8021q/Kconfig @@ -3,7 +3,7 @@ # config VLAN_8021Q - tristate "802.1Q VLAN Support" + tristate "802.1Q/802.1ad VLAN Support" ---help--- Select this and you will be able to create 802.1Q VLAN interfaces on your ethernet interfaces. 802.1Q VLAN supports almost diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 245de9653db0..abc9cb631c47 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -91,6 +91,7 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) enum vlan_protos { VLAN_PROTO_8021Q = 0, + VLAN_PROTO_8021AD, VLAN_PROTO_NUM, }; @@ -116,6 +117,8 @@ static inline unsigned int vlan_proto_idx(__be16 proto) switch (proto) { case __constant_htons(ETH_P_8021Q): return VLAN_PROTO_8021Q; + case __constant_htons(ETH_P_8021AD): + return VLAN_PROTO_8021AD; default: BUG(); } diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index bdb0b9d2e9cf..ebfa2fceb88b 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -194,6 +194,18 @@ struct vlan_vid_info { int refcount; }; +static bool vlan_hw_filter_capable(const struct net_device *dev, + const struct vlan_vid_info *vid_info) +{ + if (vid_info->proto == htons(ETH_P_8021Q) && + dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) + return true; + if (vid_info->proto == htons(ETH_P_8021AD) && + dev->features & NETIF_F_HW_VLAN_STAG_FILTER) + return true; + return false; +} + static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info, __be16 proto, u16 vid) { @@ -231,8 +243,7 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, __be16 proto, u16 vid, if (!vid_info) return -ENOMEM; - if (proto == htons(ETH_P_8021Q) && - dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { + if (vlan_hw_filter_capable(dev, vid_info)) { err = ops->ndo_vlan_rx_add_vid(dev, proto, vid); if (err) { kfree(vid_info); @@ -290,8 +301,7 @@ static void __vlan_vid_del(struct vlan_info *vlan_info, u16 vid = vid_info->vid; int err; - if (proto == htons(ETH_P_8021Q) && - dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { + if (vlan_hw_filter_capable(dev, vid_info)) { err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid); if (err) { pr_warn("failed to kill vid %04x/%d for device %s\n", diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index a1a956ab39a5..309129732285 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -23,6 +23,7 @@ static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = { [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) }, [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, + [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, }; static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = { @@ -53,6 +54,16 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[]) if (!data) return -EINVAL; + if (data[IFLA_VLAN_PROTOCOL]) { + switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) { + case __constant_htons(ETH_P_8021Q): + case __constant_htons(ETH_P_8021AD): + break; + default: + return -EPROTONOSUPPORT; + } + } + if (data[IFLA_VLAN_ID]) { id = nla_get_u16(data[IFLA_VLAN_ID]); if (id >= VLAN_VID_MASK) @@ -107,6 +118,7 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct net_device *real_dev; + __be16 proto; int err; if (!data[IFLA_VLAN_ID]) @@ -118,7 +130,12 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, if (!real_dev) return -ENODEV; - vlan->vlan_proto = htons(ETH_P_8021Q); + if (data[IFLA_VLAN_PROTOCOL]) + proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]); + else + proto = htons(ETH_P_8021Q); + + vlan->vlan_proto = proto; vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]); vlan->real_dev = real_dev; vlan->flags = VLAN_FLAG_REORDER_HDR; @@ -152,7 +169,8 @@ static size_t vlan_get_size(const struct net_device *dev) { struct vlan_dev_priv *vlan = vlan_dev_priv(dev); - return nla_total_size(2) + /* IFLA_VLAN_ID */ + return nla_total_size(2) + /* IFLA_VLAN_PROTOCOL */ + nla_total_size(2) + /* IFLA_VLAN_ID */ sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */ vlan_qos_map_size(vlan->nr_ingress_mappings) + vlan_qos_map_size(vlan->nr_egress_mappings); @@ -167,7 +185,8 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev) struct nlattr *nest; unsigned int i; - if (nla_put_u16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id)) + if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) || + nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id)) goto nla_put_failure; if (vlan->flags) { f.flags = vlan->flags; diff --git a/net/core/dev.c b/net/core/dev.c index 3a12ee132b59..fad4c385f7a1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2212,7 +2212,7 @@ __be16 skb_network_protocol(struct sk_buff *skb) __be16 type = skb->protocol; int vlan_depth = ETH_HLEN; - while (type == htons(ETH_P_8021Q)) { + while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { struct vlan_hdr *vh; if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) @@ -2428,20 +2428,22 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) features &= ~NETIF_F_GSO_MASK; - if (protocol == htons(ETH_P_8021Q)) { + if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; } else if (!vlan_tx_tag_present(skb)) { return harmonize_features(skb, protocol, features); } - features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX); + features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); - if (protocol != htons(ETH_P_8021Q)) { + if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) { return harmonize_features(skb, protocol, features); } else { features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | - NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX; return harmonize_features(skb, protocol, features); } } @@ -3360,6 +3362,7 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb) case __constant_htons(ETH_P_IP): case __constant_htons(ETH_P_IPV6): case __constant_htons(ETH_P_8021Q): + case __constant_htons(ETH_P_8021AD): return true; default: return false; @@ -3400,7 +3403,8 @@ another_round: __this_cpu_inc(softnet_data.processed); - if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) { + if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || + skb->protocol == cpu_to_be16(ETH_P_8021AD)) { skb = vlan_untag(skb); if (unlikely(!skb)) goto unlock; -- cgit v1.2.3 From 5d174dd80ce94b7ed0950e31fc9a0122c689523b Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sat, 27 Apr 2013 11:31:55 +0000 Subject: vxlan: source compatiablity with IFLA_VXLAN_GROUP (v2) Source compatiability for build iproute2 was broken by: commit c7995c43facc6e5dea4de63fa9d283a337aabeb1 Author: Atzm Watanabe vxlan: Allow setting destination to unicast address. Since this commit has not made it upstream (still net-next), and better to avoid gratitious changes to exported API's; go back to original definition, and add a comment. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 +++++----- include/uapi/linux/if_link.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/uapi/linux/if_link.h') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e6ac16cd9ba2..d8de8a1303eb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1324,7 +1324,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_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, + [IFLA_VXLAN_GROUP] = { .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 }, @@ -1406,8 +1406,8 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, } dst->remote_vni = vni; - if (data[IFLA_VXLAN_REMOTE]) - dst->remote_ip = nla_get_be32(data[IFLA_VXLAN_REMOTE]); + if (data[IFLA_VXLAN_GROUP]) + dst->remote_ip = nla_get_be32(data[IFLA_VXLAN_GROUP]); if (data[IFLA_VXLAN_LOCAL]) vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]); @@ -1488,7 +1488,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_REMOTE */ + nla_total_size(sizeof(__be32)) +/* IFLA_VXLAN_GROUP */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LINK */ nla_total_size(sizeof(__be32))+ /* IFLA_VXLAN_LOCAL */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL */ @@ -1516,7 +1516,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni)) goto nla_put_failure; - if (dst->remote_ip && nla_put_be32(skb, IFLA_VXLAN_REMOTE, dst->remote_ip)) + if (dst->remote_ip && nla_put_be32(skb, IFLA_VXLAN_GROUP, dst->remote_ip)) goto nla_put_failure; if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex)) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index e3163544f339..5346131524e4 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -297,7 +297,7 @@ enum macvlan_mode { enum { IFLA_VXLAN_UNSPEC, IFLA_VXLAN_ID, - IFLA_VXLAN_REMOTE, + IFLA_VXLAN_GROUP, /* group or remote address */ IFLA_VXLAN_LINK, IFLA_VXLAN_LOCAL, IFLA_VXLAN_TTL, -- cgit v1.2.3 From 823aa873bc782f1c51b1ce8ec6da7cfcaf93836e Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sat, 27 Apr 2013 11:31:57 +0000 Subject: vxlan: allow choosing destination port per vxlan Allow configuring the default destination port on a per-device basis. Adds new netlink paramater IFLA_VXLAN_PORT to allow setting destination port when creating new vxlan. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 18 +++++++++++++----- include/uapi/linux/if_link.h | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'include/uapi/linux/if_link.h') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 66fd7bef0a4d..f1d9e981e541 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -110,6 +110,7 @@ struct vxlan_dev { struct net_device *dev; struct vxlan_rdst default_dst; /* default destination */ __be32 saddr; /* source address */ + __be16 dst_port; __u16 port_min; /* source port range */ __u16 port_max; __u8 tos; /* TOS override */ @@ -192,7 +193,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan, if (send_ip && nla_put_be32(skb, NDA_DST, rdst->remote_ip)) goto nla_put_failure; - if (rdst->remote_port && rdst->remote_port != htons(vxlan_port) && + if (rdst->remote_port && rdst->remote_port != vxlan->dst_port && nla_put_be16(skb, NDA_PORT, rdst->remote_port)) goto nla_put_failure; if (rdst->remote_vni != vxlan->default_dst.remote_vni && @@ -467,7 +468,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EINVAL; port = nla_get_be16(tb[NDA_PORT]); } else - port = htons(vxlan_port); + port = vxlan->dst_port; if (tb[NDA_VNI]) { if (nla_len(tb[NDA_VNI]) != sizeof(u32)) @@ -579,7 +580,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->dst_port, vxlan->default_dst.remote_vni, 0, NTF_SELF); spin_unlock(&vxlan->hash_lock); @@ -970,7 +971,7 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, __be16 df = 0; __u8 tos, ttl; - dst_port = rdst->remote_port ? rdst->remote_port : htons(vxlan_port); + dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; vni = rdst->remote_vni; dst = rdst->remote_ip; @@ -1314,6 +1315,7 @@ static void vxlan_setup(struct net_device *dev) inet_get_local_port_range(&low, &high); vxlan->port_min = low; vxlan->port_max = high; + vxlan->dst_port = htons(vxlan_port); vxlan->dev = dev; @@ -1336,6 +1338,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -1465,6 +1468,9 @@ static int vxlan_newlink(struct net *net, struct net_device *dev, vxlan->port_max = ntohs(p->high); } + if (data[IFLA_VXLAN_PORT]) + vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); + SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops); err = register_netdevice(dev); @@ -1500,6 +1506,7 @@ static size_t vxlan_get_size(const struct net_device *dev) 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)) + + nla_total_size(sizeof(__be16))+ /* IFLA_VXLAN_PORT */ 0; } @@ -1536,7 +1543,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_L3MISS, !!(vxlan->flags & VXLAN_F_L3MISS)) || nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || - nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax)) + nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || + nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port)) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 5346131524e4..b05823cae784 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -305,11 +305,12 @@ enum { IFLA_VXLAN_LEARNING, IFLA_VXLAN_AGEING, IFLA_VXLAN_LIMIT, - IFLA_VXLAN_PORT_RANGE, + IFLA_VXLAN_PORT_RANGE, /* source port */ IFLA_VXLAN_PROXY, IFLA_VXLAN_RSC, IFLA_VXLAN_L2MISS, IFLA_VXLAN_L3MISS, + IFLA_VXLAN_PORT, /* destination port */ __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) -- cgit v1.2.3