aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/vxlan.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-03-25 20:29:20 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-25 20:29:20 -0400
commit04f58c88542b6b351efb4eea01134eb672e22e6e (patch)
tree47bb617212f8c8951f35730e324bdc43487a01ca /drivers/net/vxlan.c
parent0fc31966035d7a540c011b6c967ce8eae1db121b (diff)
parent632b06aa2842b12c6d6a510ec080fb6ebdb38ea5 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts: Documentation/devicetree/bindings/net/micrel-ks8851.txt net/core/netpoll.c The net/core/netpoll.c conflict is a bug fix in 'net' happening to code which is completely removed in 'net-next'. In micrel-ks8851.txt we simply have overlapping changes. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxlan.c')
-rw-r--r--drivers/net/vxlan.c130
1 files changed, 116 insertions, 14 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index eb59b14d5ee0..0d862a5077ab 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1315,6 +1315,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
1315 1315
1316 neigh_release(n); 1316 neigh_release(n);
1317 1317
1318 if (reply == NULL)
1319 goto out;
1320
1318 skb_reset_mac_header(reply); 1321 skb_reset_mac_header(reply);
1319 __skb_pull(reply, skb_network_offset(reply)); 1322 __skb_pull(reply, skb_network_offset(reply));
1320 reply->ip_summed = CHECKSUM_UNNECESSARY; 1323 reply->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1336,15 +1339,103 @@ out:
1336} 1339}
1337 1340
1338#if IS_ENABLED(CONFIG_IPV6) 1341#if IS_ENABLED(CONFIG_IPV6)
1342
1343static struct sk_buff *vxlan_na_create(struct sk_buff *request,
1344 struct neighbour *n, bool isrouter)
1345{
1346 struct net_device *dev = request->dev;
1347 struct sk_buff *reply;
1348 struct nd_msg *ns, *na;
1349 struct ipv6hdr *pip6;
1350 u8 *daddr;
1351 int na_olen = 8; /* opt hdr + ETH_ALEN for target */
1352 int ns_olen;
1353 int i, len;
1354
1355 if (dev == NULL)
1356 return NULL;
1357
1358 len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
1359 sizeof(*na) + na_olen + dev->needed_tailroom;
1360 reply = alloc_skb(len, GFP_ATOMIC);
1361 if (reply == NULL)
1362 return NULL;
1363
1364 reply->protocol = htons(ETH_P_IPV6);
1365 reply->dev = dev;
1366 skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
1367 skb_push(reply, sizeof(struct ethhdr));
1368 skb_set_mac_header(reply, 0);
1369
1370 ns = (struct nd_msg *)skb_transport_header(request);
1371
1372 daddr = eth_hdr(request)->h_source;
1373 ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
1374 for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
1375 if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
1376 daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
1377 break;
1378 }
1379 }
1380
1381 /* Ethernet header */
1382 ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
1383 ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
1384 eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
1385 reply->protocol = htons(ETH_P_IPV6);
1386
1387 skb_pull(reply, sizeof(struct ethhdr));
1388 skb_set_network_header(reply, 0);
1389 skb_put(reply, sizeof(struct ipv6hdr));
1390
1391 /* IPv6 header */
1392
1393 pip6 = ipv6_hdr(reply);
1394 memset(pip6, 0, sizeof(struct ipv6hdr));
1395 pip6->version = 6;
1396 pip6->priority = ipv6_hdr(request)->priority;
1397 pip6->nexthdr = IPPROTO_ICMPV6;
1398 pip6->hop_limit = 255;
1399 pip6->daddr = ipv6_hdr(request)->saddr;
1400 pip6->saddr = *(struct in6_addr *)n->primary_key;
1401
1402 skb_pull(reply, sizeof(struct ipv6hdr));
1403 skb_set_transport_header(reply, 0);
1404
1405 na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
1406
1407 /* Neighbor Advertisement */
1408 memset(na, 0, sizeof(*na)+na_olen);
1409 na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
1410 na->icmph.icmp6_router = isrouter;
1411 na->icmph.icmp6_override = 1;
1412 na->icmph.icmp6_solicited = 1;
1413 na->target = ns->target;
1414 ether_addr_copy(&na->opt[2], n->ha);
1415 na->opt[0] = ND_OPT_TARGET_LL_ADDR;
1416 na->opt[1] = na_olen >> 3;
1417
1418 na->icmph.icmp6_cksum = csum_ipv6_magic(&pip6->saddr,
1419 &pip6->daddr, sizeof(*na)+na_olen, IPPROTO_ICMPV6,
1420 csum_partial(na, sizeof(*na)+na_olen, 0));
1421
1422 pip6->payload_len = htons(sizeof(*na)+na_olen);
1423
1424 skb_push(reply, sizeof(struct ipv6hdr));
1425
1426 reply->ip_summed = CHECKSUM_UNNECESSARY;
1427
1428 return reply;
1429}
1430
1339static int neigh_reduce(struct net_device *dev, struct sk_buff *skb) 1431static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
1340{ 1432{
1341 struct vxlan_dev *vxlan = netdev_priv(dev); 1433 struct vxlan_dev *vxlan = netdev_priv(dev);
1342 struct neighbour *n; 1434 struct nd_msg *msg;
1343 union vxlan_addr ipa;
1344 const struct ipv6hdr *iphdr; 1435 const struct ipv6hdr *iphdr;
1345 const struct in6_addr *saddr, *daddr; 1436 const struct in6_addr *saddr, *daddr;
1346 struct nd_msg *msg; 1437 struct neighbour *n;
1347 struct inet6_dev *in6_dev = NULL; 1438 struct inet6_dev *in6_dev;
1348 1439
1349 in6_dev = __in6_dev_get(dev); 1440 in6_dev = __in6_dev_get(dev);
1350 if (!in6_dev) 1441 if (!in6_dev)
@@ -1357,19 +1448,20 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
1357 saddr = &iphdr->saddr; 1448 saddr = &iphdr->saddr;
1358 daddr = &iphdr->daddr; 1449 daddr = &iphdr->daddr;
1359 1450
1360 if (ipv6_addr_loopback(daddr) ||
1361 ipv6_addr_is_multicast(daddr))
1362 goto out;
1363
1364 msg = (struct nd_msg *)skb_transport_header(skb); 1451 msg = (struct nd_msg *)skb_transport_header(skb);
1365 if (msg->icmph.icmp6_code != 0 || 1452 if (msg->icmph.icmp6_code != 0 ||
1366 msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION) 1453 msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
1367 goto out; 1454 goto out;
1368 1455
1369 n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev); 1456 if (ipv6_addr_loopback(daddr) ||
1457 ipv6_addr_is_multicast(&msg->target))
1458 goto out;
1459
1460 n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev);
1370 1461
1371 if (n) { 1462 if (n) {
1372 struct vxlan_fdb *f; 1463 struct vxlan_fdb *f;
1464 struct sk_buff *reply;
1373 1465
1374 if (!(n->nud_state & NUD_CONNECTED)) { 1466 if (!(n->nud_state & NUD_CONNECTED)) {
1375 neigh_release(n); 1467 neigh_release(n);
@@ -1383,13 +1475,23 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
1383 goto out; 1475 goto out;
1384 } 1476 }
1385 1477
1386 ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target, 1478 reply = vxlan_na_create(skb, n,
1387 !!in6_dev->cnf.forwarding, 1479 !!(f ? f->flags & NTF_ROUTER : 0));
1388 true, false, false); 1480
1389 neigh_release(n); 1481 neigh_release(n);
1482
1483 if (reply == NULL)
1484 goto out;
1485
1486 if (netif_rx_ni(reply) == NET_RX_DROP)
1487 dev->stats.rx_dropped++;
1488
1390 } else if (vxlan->flags & VXLAN_F_L3MISS) { 1489 } else if (vxlan->flags & VXLAN_F_L3MISS) {
1391 ipa.sin6.sin6_addr = *daddr; 1490 union vxlan_addr ipa = {
1392 ipa.sa.sa_family = AF_INET6; 1491 .sin6.sin6_addr = msg->target,
1492 .sa.sa_family = AF_INET6,
1493 };
1494
1393 vxlan_ip_miss(dev, &ipa); 1495 vxlan_ip_miss(dev, &ipa);
1394 } 1496 }
1395 1497