aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ipvlan/ipvlan_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_core.c')
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index b5f9511d819e..b4e990743e1d 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -560,6 +560,7 @@ int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
560 case IPVLAN_MODE_L2: 560 case IPVLAN_MODE_L2:
561 return ipvlan_xmit_mode_l2(skb, dev); 561 return ipvlan_xmit_mode_l2(skb, dev);
562 case IPVLAN_MODE_L3: 562 case IPVLAN_MODE_L3:
563 case IPVLAN_MODE_L3S:
563 return ipvlan_xmit_mode_l3(skb, dev); 564 return ipvlan_xmit_mode_l3(skb, dev);
564 } 565 }
565 566
@@ -664,6 +665,8 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
664 return ipvlan_handle_mode_l2(pskb, port); 665 return ipvlan_handle_mode_l2(pskb, port);
665 case IPVLAN_MODE_L3: 666 case IPVLAN_MODE_L3:
666 return ipvlan_handle_mode_l3(pskb, port); 667 return ipvlan_handle_mode_l3(pskb, port);
668 case IPVLAN_MODE_L3S:
669 return RX_HANDLER_PASS;
667 } 670 }
668 671
669 /* Should not reach here */ 672 /* Should not reach here */
@@ -672,3 +675,94 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
672 kfree_skb(skb); 675 kfree_skb(skb);
673 return RX_HANDLER_CONSUMED; 676 return RX_HANDLER_CONSUMED;
674} 677}
678
679static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
680 struct net_device *dev)
681{
682 struct ipvl_addr *addr = NULL;
683 struct ipvl_port *port;
684 void *lyr3h;
685 int addr_type;
686
687 if (!dev || !netif_is_ipvlan_port(dev))
688 goto out;
689
690 port = ipvlan_port_get_rcu(dev);
691 if (!port || port->mode != IPVLAN_MODE_L3S)
692 goto out;
693
694 lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
695 if (!lyr3h)
696 goto out;
697
698 addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
699out:
700 return addr;
701}
702
703struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
704 u16 proto)
705{
706 struct ipvl_addr *addr;
707 struct net_device *sdev;
708
709 addr = ipvlan_skb_to_addr(skb, dev);
710 if (!addr)
711 goto out;
712
713 sdev = addr->master->dev;
714 switch (proto) {
715 case AF_INET:
716 {
717 int err;
718 struct iphdr *ip4h = ip_hdr(skb);
719
720 err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
721 ip4h->tos, sdev);
722 if (unlikely(err))
723 goto out;
724 break;
725 }
726 case AF_INET6:
727 {
728 struct dst_entry *dst;
729 struct ipv6hdr *ip6h = ipv6_hdr(skb);
730 int flags = RT6_LOOKUP_F_HAS_SADDR;
731 struct flowi6 fl6 = {
732 .flowi6_iif = sdev->ifindex,
733 .daddr = ip6h->daddr,
734 .saddr = ip6h->saddr,
735 .flowlabel = ip6_flowinfo(ip6h),
736 .flowi6_mark = skb->mark,
737 .flowi6_proto = ip6h->nexthdr,
738 };
739
740 skb_dst_drop(skb);
741 dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6, flags);
742 skb_dst_set(skb, dst);
743 break;
744 }
745 default:
746 break;
747 }
748
749out:
750 return skb;
751}
752
753unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
754 const struct nf_hook_state *state)
755{
756 struct ipvl_addr *addr;
757 unsigned int len;
758
759 addr = ipvlan_skb_to_addr(skb, skb->dev);
760 if (!addr)
761 goto out;
762
763 skb->dev = addr->master->dev;
764 len = skb->len + ETH_HLEN;
765 ipvlan_count_rx(addr->master, len, true, false);
766out:
767 return NF_ACCEPT;
768}