| .. | .. |
|---|
| 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 | |
|---|
| .. | .. |
|---|
| 502 | 496 | |
|---|
| 503 | 497 | static int ipvlan_process_outbound(struct sk_buff *skb) |
|---|
| 504 | 498 | { |
|---|
| 505 | | - struct ethhdr *ethh = eth_hdr(skb); |
|---|
| 506 | 499 | int ret = NET_XMIT_DROP; |
|---|
| 507 | 500 | |
|---|
| 508 | 501 | /* The ipvlan is a pseudo-L2 device, so the packets that we receive |
|---|
| .. | .. |
|---|
| 512 | 505 | if (skb_mac_header_was_set(skb)) { |
|---|
| 513 | 506 | /* In this mode we dont care about |
|---|
| 514 | 507 | * multicast and broadcast traffic */ |
|---|
| 508 | + struct ethhdr *ethh = eth_hdr(skb); |
|---|
| 509 | + |
|---|
| 515 | 510 | if (is_multicast_ether_addr(ethh->h_dest)) { |
|---|
| 516 | 511 | pr_debug_ratelimited( |
|---|
| 517 | 512 | "Dropped {multi|broad}cast of type=[%x]\n", |
|---|
| .. | .. |
|---|
| 596 | 591 | static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) |
|---|
| 597 | 592 | { |
|---|
| 598 | 593 | const struct ipvl_dev *ipvlan = netdev_priv(dev); |
|---|
| 599 | | - struct ethhdr *eth = eth_hdr(skb); |
|---|
| 594 | + struct ethhdr *eth = skb_eth_hdr(skb); |
|---|
| 600 | 595 | struct ipvl_addr *addr; |
|---|
| 601 | 596 | void *lyr3h; |
|---|
| 602 | 597 | int addr_type; |
|---|
| .. | .. |
|---|
| 626 | 621 | return dev_forward_skb(ipvlan->phy_dev, skb); |
|---|
| 627 | 622 | |
|---|
| 628 | 623 | } else if (is_multicast_ether_addr(eth->h_dest)) { |
|---|
| 624 | + skb_reset_mac_header(skb); |
|---|
| 629 | 625 | ipvlan_skb_crossing_ns(skb, NULL); |
|---|
| 630 | 626 | ipvlan_multicast_enqueue(ipvlan->port, skb, true); |
|---|
| 631 | 627 | return NET_XMIT_SUCCESS; |
|---|
| .. | .. |
|---|
| 650 | 646 | case IPVLAN_MODE_L2: |
|---|
| 651 | 647 | return ipvlan_xmit_mode_l2(skb, dev); |
|---|
| 652 | 648 | case IPVLAN_MODE_L3: |
|---|
| 649 | +#ifdef CONFIG_IPVLAN_L3S |
|---|
| 653 | 650 | case IPVLAN_MODE_L3S: |
|---|
| 651 | +#endif |
|---|
| 654 | 652 | return ipvlan_xmit_mode_l3(skb, dev); |
|---|
| 655 | 653 | } |
|---|
| 656 | 654 | |
|---|
| .. | .. |
|---|
| 746 | 744 | return ipvlan_handle_mode_l2(pskb, port); |
|---|
| 747 | 745 | case IPVLAN_MODE_L3: |
|---|
| 748 | 746 | return ipvlan_handle_mode_l3(pskb, port); |
|---|
| 747 | +#ifdef CONFIG_IPVLAN_L3S |
|---|
| 749 | 748 | case IPVLAN_MODE_L3S: |
|---|
| 750 | 749 | return RX_HANDLER_PASS; |
|---|
| 750 | +#endif |
|---|
| 751 | 751 | } |
|---|
| 752 | 752 | |
|---|
| 753 | 753 | /* Should not reach here */ |
|---|
| .. | .. |
|---|
| 755 | 755 | port->mode); |
|---|
| 756 | 756 | kfree_skb(skb); |
|---|
| 757 | 757 | 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 | 758 | } |
|---|