| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com> |
|---|
| 2 | | - * |
|---|
| 3 | | - * This program is free software; you can redistribute it and/or |
|---|
| 4 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 5 | | - * published by the Free Software Foundation; either version 2 of |
|---|
| 6 | | - * the License, or (at your option) any later version. |
|---|
| 7 | | - * |
|---|
| 8 | 3 | */ |
|---|
| 9 | 4 | |
|---|
| 10 | 5 | #include "ipvlan.h" |
|---|
| .. | .. |
|---|
| 138 | 133 | return ret; |
|---|
| 139 | 134 | } |
|---|
| 140 | 135 | |
|---|
| 141 | | -static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type) |
|---|
| 136 | +void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type) |
|---|
| 142 | 137 | { |
|---|
| 143 | 138 | void *lyr3h = NULL; |
|---|
| 144 | 139 | |
|---|
| .. | .. |
|---|
| 356 | 351 | return ret; |
|---|
| 357 | 352 | } |
|---|
| 358 | 353 | |
|---|
| 359 | | -static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, |
|---|
| 360 | | - void *lyr3h, int addr_type, |
|---|
| 361 | | - bool use_dest) |
|---|
| 354 | +struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h, |
|---|
| 355 | + int addr_type, bool use_dest) |
|---|
| 362 | 356 | { |
|---|
| 363 | 357 | struct ipvl_addr *addr = NULL; |
|---|
| 364 | 358 | |
|---|
| .. | .. |
|---|
| 443 | 437 | goto err; |
|---|
| 444 | 438 | } |
|---|
| 445 | 439 | skb_dst_set(skb, &rt->dst); |
|---|
| 440 | + |
|---|
| 441 | + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
|---|
| 442 | + |
|---|
| 446 | 443 | err = ip_local_out(net, skb->sk, skb); |
|---|
| 447 | 444 | if (unlikely(net_xmit_eval(err))) |
|---|
| 448 | 445 | dev->stats.tx_errors++; |
|---|
| .. | .. |
|---|
| 481 | 478 | goto err; |
|---|
| 482 | 479 | } |
|---|
| 483 | 480 | skb_dst_set(skb, dst); |
|---|
| 481 | + |
|---|
| 482 | + memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); |
|---|
| 483 | + |
|---|
| 484 | 484 | err = ip6_local_out(net, skb->sk, skb); |
|---|
| 485 | 485 | if (unlikely(net_xmit_eval(err))) |
|---|
| 486 | 486 | dev->stats.tx_errors++; |
|---|
| .. | .. |
|---|
| 502 | 502 | |
|---|
| 503 | 503 | static int ipvlan_process_outbound(struct sk_buff *skb) |
|---|
| 504 | 504 | { |
|---|
| 505 | | - struct ethhdr *ethh = eth_hdr(skb); |
|---|
| 506 | 505 | int ret = NET_XMIT_DROP; |
|---|
| 507 | 506 | |
|---|
| 508 | 507 | /* The ipvlan is a pseudo-L2 device, so the packets that we receive |
|---|
| .. | .. |
|---|
| 512 | 511 | if (skb_mac_header_was_set(skb)) { |
|---|
| 513 | 512 | /* In this mode we dont care about |
|---|
| 514 | 513 | * multicast and broadcast traffic */ |
|---|
| 514 | + struct ethhdr *ethh = eth_hdr(skb); |
|---|
| 515 | + |
|---|
| 515 | 516 | if (is_multicast_ether_addr(ethh->h_dest)) { |
|---|
| 516 | 517 | pr_debug_ratelimited( |
|---|
| 517 | 518 | "Dropped {multi|broad}cast of type=[%x]\n", |
|---|
| .. | .. |
|---|
| 585 | 586 | consume_skb(skb); |
|---|
| 586 | 587 | return NET_XMIT_DROP; |
|---|
| 587 | 588 | } |
|---|
| 588 | | - return ipvlan_rcv_frame(addr, &skb, true); |
|---|
| 589 | + ipvlan_rcv_frame(addr, &skb, true); |
|---|
| 590 | + return NET_XMIT_SUCCESS; |
|---|
| 589 | 591 | } |
|---|
| 590 | 592 | } |
|---|
| 591 | 593 | out: |
|---|
| .. | .. |
|---|
| 596 | 598 | static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) |
|---|
| 597 | 599 | { |
|---|
| 598 | 600 | const struct ipvl_dev *ipvlan = netdev_priv(dev); |
|---|
| 599 | | - struct ethhdr *eth = eth_hdr(skb); |
|---|
| 601 | + struct ethhdr *eth = skb_eth_hdr(skb); |
|---|
| 600 | 602 | struct ipvl_addr *addr; |
|---|
| 601 | 603 | void *lyr3h; |
|---|
| 602 | 604 | int addr_type; |
|---|
| .. | .. |
|---|
| 611 | 613 | consume_skb(skb); |
|---|
| 612 | 614 | return NET_XMIT_DROP; |
|---|
| 613 | 615 | } |
|---|
| 614 | | - return ipvlan_rcv_frame(addr, &skb, true); |
|---|
| 616 | + ipvlan_rcv_frame(addr, &skb, true); |
|---|
| 617 | + return NET_XMIT_SUCCESS; |
|---|
| 615 | 618 | } |
|---|
| 616 | 619 | } |
|---|
| 617 | 620 | skb = skb_share_check(skb, GFP_ATOMIC); |
|---|
| .. | .. |
|---|
| 623 | 626 | * the skb for the main-dev. At the RX side we just return |
|---|
| 624 | 627 | * RX_PASS for it to be processed further on the stack. |
|---|
| 625 | 628 | */ |
|---|
| 626 | | - return dev_forward_skb(ipvlan->phy_dev, skb); |
|---|
| 629 | + dev_forward_skb(ipvlan->phy_dev, skb); |
|---|
| 630 | + return NET_XMIT_SUCCESS; |
|---|
| 627 | 631 | |
|---|
| 628 | 632 | } else if (is_multicast_ether_addr(eth->h_dest)) { |
|---|
| 633 | + skb_reset_mac_header(skb); |
|---|
| 629 | 634 | ipvlan_skb_crossing_ns(skb, NULL); |
|---|
| 630 | 635 | ipvlan_multicast_enqueue(ipvlan->port, skb, true); |
|---|
| 631 | 636 | return NET_XMIT_SUCCESS; |
|---|
| .. | .. |
|---|
| 650 | 655 | case IPVLAN_MODE_L2: |
|---|
| 651 | 656 | return ipvlan_xmit_mode_l2(skb, dev); |
|---|
| 652 | 657 | case IPVLAN_MODE_L3: |
|---|
| 658 | +#ifdef CONFIG_IPVLAN_L3S |
|---|
| 653 | 659 | case IPVLAN_MODE_L3S: |
|---|
| 660 | +#endif |
|---|
| 654 | 661 | return ipvlan_xmit_mode_l3(skb, dev); |
|---|
| 655 | 662 | } |
|---|
| 656 | 663 | |
|---|
| .. | .. |
|---|
| 746 | 753 | return ipvlan_handle_mode_l2(pskb, port); |
|---|
| 747 | 754 | case IPVLAN_MODE_L3: |
|---|
| 748 | 755 | return ipvlan_handle_mode_l3(pskb, port); |
|---|
| 756 | +#ifdef CONFIG_IPVLAN_L3S |
|---|
| 749 | 757 | case IPVLAN_MODE_L3S: |
|---|
| 750 | 758 | return RX_HANDLER_PASS; |
|---|
| 759 | +#endif |
|---|
| 751 | 760 | } |
|---|
| 752 | 761 | |
|---|
| 753 | 762 | /* Should not reach here */ |
|---|
| .. | .. |
|---|
| 755 | 764 | port->mode); |
|---|
| 756 | 765 | kfree_skb(skb); |
|---|
| 757 | 766 | return RX_HANDLER_CONSUMED; |
|---|
| 758 | | -} |
|---|
| 759 | | - |
|---|
| 760 | | -static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb, |
|---|
| 761 | | - struct net_device *dev) |
|---|
| 762 | | -{ |
|---|
| 763 | | - struct ipvl_addr *addr = NULL; |
|---|
| 764 | | - struct ipvl_port *port; |
|---|
| 765 | | - void *lyr3h; |
|---|
| 766 | | - int addr_type; |
|---|
| 767 | | - |
|---|
| 768 | | - if (!dev || !netif_is_ipvlan_port(dev)) |
|---|
| 769 | | - goto out; |
|---|
| 770 | | - |
|---|
| 771 | | - port = ipvlan_port_get_rcu(dev); |
|---|
| 772 | | - if (!port || port->mode != IPVLAN_MODE_L3S) |
|---|
| 773 | | - goto out; |
|---|
| 774 | | - |
|---|
| 775 | | - lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type); |
|---|
| 776 | | - if (!lyr3h) |
|---|
| 777 | | - goto out; |
|---|
| 778 | | - |
|---|
| 779 | | - addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true); |
|---|
| 780 | | -out: |
|---|
| 781 | | - return addr; |
|---|
| 782 | | -} |
|---|
| 783 | | - |
|---|
| 784 | | -struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb, |
|---|
| 785 | | - u16 proto) |
|---|
| 786 | | -{ |
|---|
| 787 | | - struct ipvl_addr *addr; |
|---|
| 788 | | - struct net_device *sdev; |
|---|
| 789 | | - |
|---|
| 790 | | - addr = ipvlan_skb_to_addr(skb, dev); |
|---|
| 791 | | - if (!addr) |
|---|
| 792 | | - goto out; |
|---|
| 793 | | - |
|---|
| 794 | | - sdev = addr->master->dev; |
|---|
| 795 | | - switch (proto) { |
|---|
| 796 | | - case AF_INET: |
|---|
| 797 | | - { |
|---|
| 798 | | - int err; |
|---|
| 799 | | - struct iphdr *ip4h = ip_hdr(skb); |
|---|
| 800 | | - |
|---|
| 801 | | - err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr, |
|---|
| 802 | | - ip4h->tos, sdev); |
|---|
| 803 | | - if (unlikely(err)) |
|---|
| 804 | | - goto out; |
|---|
| 805 | | - break; |
|---|
| 806 | | - } |
|---|
| 807 | | -#if IS_ENABLED(CONFIG_IPV6) |
|---|
| 808 | | - case AF_INET6: |
|---|
| 809 | | - { |
|---|
| 810 | | - struct dst_entry *dst; |
|---|
| 811 | | - struct ipv6hdr *ip6h = ipv6_hdr(skb); |
|---|
| 812 | | - int flags = RT6_LOOKUP_F_HAS_SADDR; |
|---|
| 813 | | - struct flowi6 fl6 = { |
|---|
| 814 | | - .flowi6_iif = sdev->ifindex, |
|---|
| 815 | | - .daddr = ip6h->daddr, |
|---|
| 816 | | - .saddr = ip6h->saddr, |
|---|
| 817 | | - .flowlabel = ip6_flowinfo(ip6h), |
|---|
| 818 | | - .flowi6_mark = skb->mark, |
|---|
| 819 | | - .flowi6_proto = ip6h->nexthdr, |
|---|
| 820 | | - }; |
|---|
| 821 | | - |
|---|
| 822 | | - skb_dst_drop(skb); |
|---|
| 823 | | - dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6, |
|---|
| 824 | | - skb, flags); |
|---|
| 825 | | - skb_dst_set(skb, dst); |
|---|
| 826 | | - break; |
|---|
| 827 | | - } |
|---|
| 828 | | -#endif |
|---|
| 829 | | - default: |
|---|
| 830 | | - break; |
|---|
| 831 | | - } |
|---|
| 832 | | - |
|---|
| 833 | | -out: |
|---|
| 834 | | - return skb; |
|---|
| 835 | | -} |
|---|
| 836 | | - |
|---|
| 837 | | -unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb, |
|---|
| 838 | | - const struct nf_hook_state *state) |
|---|
| 839 | | -{ |
|---|
| 840 | | - struct ipvl_addr *addr; |
|---|
| 841 | | - unsigned int len; |
|---|
| 842 | | - |
|---|
| 843 | | - addr = ipvlan_skb_to_addr(skb, skb->dev); |
|---|
| 844 | | - if (!addr) |
|---|
| 845 | | - goto out; |
|---|
| 846 | | - |
|---|
| 847 | | - skb->dev = addr->master->dev; |
|---|
| 848 | | - len = skb->len + ETH_HLEN; |
|---|
| 849 | | - ipvlan_count_rx(addr->master, len, true, false); |
|---|
| 850 | | -out: |
|---|
| 851 | | - return NF_ACCEPT; |
|---|
| 852 | 767 | } |
|---|