aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vxlan.c
diff options
context:
space:
mode:
authorCong Wang <amwang@redhat.com>2013-08-31 01:44:36 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-31 22:30:01 -0400
commitf564f45c451809aa3b74f577754528520d315ac1 (patch)
tree6bebdf8d9a149b4d370a5f43ccd86935adbbc273 /drivers/net/vxlan.c
parentf39dc1023d6b9933528638a0c2dd618b4fdf664e (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.c82
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)
1200static 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
1257out:
1258 consume_skb(skb);
1259 return NETDEV_TX_OK;
1260}
1261#endif
1262
1199static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb) 1263static 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;