diff options
author | Cong Wang <amwang@redhat.com> | 2013-08-31 01:44:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-31 22:30:01 -0400 |
commit | f564f45c451809aa3b74f577754528520d315ac1 (patch) | |
tree | 6bebdf8d9a149b4d370a5f43ccd86935adbbc273 /drivers/net/vxlan.c | |
parent | f39dc1023d6b9933528638a0c2dd618b4fdf664e (diff) |
vxlan: add ipv6 proxy support
This patch adds the IPv6 version of "arp_reduce", ndisc_send_na()
will be needed.
Cc: David S. Miller <davem@davemloft.net>
Cc: David Stevens <dlstevens@us.ibm.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r-- | drivers/net/vxlan.c | 82 |
1 files changed, 80 insertions, 2 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c833763fe5c4..3ffb22d684a9 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -1196,6 +1196,70 @@ out: | |||
1196 | return NETDEV_TX_OK; | 1196 | return NETDEV_TX_OK; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | #if IS_ENABLED(CONFIG_IPV6) | ||
1200 | static int neigh_reduce(struct net_device *dev, struct sk_buff *skb) | ||
1201 | { | ||
1202 | struct vxlan_dev *vxlan = netdev_priv(dev); | ||
1203 | struct neighbour *n; | ||
1204 | union vxlan_addr ipa; | ||
1205 | const struct ipv6hdr *iphdr; | ||
1206 | const struct in6_addr *saddr, *daddr; | ||
1207 | struct nd_msg *msg; | ||
1208 | struct inet6_dev *in6_dev = NULL; | ||
1209 | |||
1210 | in6_dev = __in6_dev_get(dev); | ||
1211 | if (!in6_dev) | ||
1212 | goto out; | ||
1213 | |||
1214 | if (!pskb_may_pull(skb, skb->len)) | ||
1215 | goto out; | ||
1216 | |||
1217 | iphdr = ipv6_hdr(skb); | ||
1218 | saddr = &iphdr->saddr; | ||
1219 | daddr = &iphdr->daddr; | ||
1220 | |||
1221 | if (ipv6_addr_loopback(daddr) || | ||
1222 | ipv6_addr_is_multicast(daddr)) | ||
1223 | goto out; | ||
1224 | |||
1225 | msg = (struct nd_msg *)skb_transport_header(skb); | ||
1226 | if (msg->icmph.icmp6_code != 0 || | ||
1227 | msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION) | ||
1228 | goto out; | ||
1229 | |||
1230 | n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev); | ||
1231 | |||
1232 | if (n) { | ||
1233 | struct vxlan_fdb *f; | ||
1234 | |||
1235 | if (!(n->nud_state & NUD_CONNECTED)) { | ||
1236 | neigh_release(n); | ||
1237 | goto out; | ||
1238 | } | ||
1239 | |||
1240 | f = vxlan_find_mac(vxlan, n->ha); | ||
1241 | if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) { | ||
1242 | /* bridge-local neighbor */ | ||
1243 | neigh_release(n); | ||
1244 | goto out; | ||
1245 | } | ||
1246 | |||
1247 | ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target, | ||
1248 | !!in6_dev->cnf.forwarding, | ||
1249 | true, false, false); | ||
1250 | neigh_release(n); | ||
1251 | } else if (vxlan->flags & VXLAN_F_L3MISS) { | ||
1252 | ipa.sin6.sin6_addr = *daddr; | ||
1253 | ipa.sa.sa_family = AF_INET6; | ||
1254 | vxlan_ip_miss(dev, &ipa); | ||
1255 | } | ||
1256 | |||
1257 | out: | ||
1258 | consume_skb(skb); | ||
1259 | return NETDEV_TX_OK; | ||
1260 | } | ||
1261 | #endif | ||
1262 | |||
1199 | static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) | 1263 | static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) |
1200 | { | 1264 | { |
1201 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1265 | struct vxlan_dev *vxlan = netdev_priv(dev); |
@@ -1677,8 +1741,22 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1677 | skb_reset_mac_header(skb); | 1741 | skb_reset_mac_header(skb); |
1678 | eth = eth_hdr(skb); | 1742 | eth = eth_hdr(skb); |
1679 | 1743 | ||
1680 | if ((vxlan->flags & VXLAN_F_PROXY) && ntohs(eth->h_proto) == ETH_P_ARP) | 1744 | if ((vxlan->flags & VXLAN_F_PROXY)) { |
1681 | return arp_reduce(dev, skb); | 1745 | if (ntohs(eth->h_proto) == ETH_P_ARP) |
1746 | return arp_reduce(dev, skb); | ||
1747 | #if IS_ENABLED(CONFIG_IPV6) | ||
1748 | else if (ntohs(eth->h_proto) == ETH_P_IPV6 && | ||
1749 | skb->len >= sizeof(struct ipv6hdr) + sizeof(struct nd_msg) && | ||
1750 | ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { | ||
1751 | struct nd_msg *msg; | ||
1752 | |||
1753 | msg = (struct nd_msg *)skb_transport_header(skb); | ||
1754 | if (msg->icmph.icmp6_code == 0 && | ||
1755 | msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) | ||
1756 | return neigh_reduce(dev, skb); | ||
1757 | } | ||
1758 | #endif | ||
1759 | } | ||
1682 | 1760 | ||
1683 | f = vxlan_find_mac(vxlan, eth->h_dest); | 1761 | f = vxlan_find_mac(vxlan, eth->h_dest); |
1684 | did_rsc = false; | 1762 | did_rsc = false; |