1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
3*4882a593Smuzhiyun */
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include "ipvlan.h"
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun static unsigned int ipvlan_netid __read_mostly;
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun struct ipvlan_netns {
10*4882a593Smuzhiyun unsigned int ipvl_nf_hook_refcnt;
11*4882a593Smuzhiyun };
12*4882a593Smuzhiyun
ipvlan_skb_to_addr(struct sk_buff * skb,struct net_device * dev)13*4882a593Smuzhiyun static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
14*4882a593Smuzhiyun struct net_device *dev)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun struct ipvl_addr *addr = NULL;
17*4882a593Smuzhiyun struct ipvl_port *port;
18*4882a593Smuzhiyun int addr_type;
19*4882a593Smuzhiyun void *lyr3h;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun if (!dev || !netif_is_ipvlan_port(dev))
22*4882a593Smuzhiyun goto out;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun port = ipvlan_port_get_rcu(dev);
25*4882a593Smuzhiyun if (!port || port->mode != IPVLAN_MODE_L3S)
26*4882a593Smuzhiyun goto out;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
29*4882a593Smuzhiyun if (!lyr3h)
30*4882a593Smuzhiyun goto out;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
33*4882a593Smuzhiyun out:
34*4882a593Smuzhiyun return addr;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun
ipvlan_l3_rcv(struct net_device * dev,struct sk_buff * skb,u16 proto)37*4882a593Smuzhiyun static struct sk_buff *ipvlan_l3_rcv(struct net_device *dev,
38*4882a593Smuzhiyun struct sk_buff *skb, u16 proto)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun struct ipvl_addr *addr;
41*4882a593Smuzhiyun struct net_device *sdev;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun addr = ipvlan_skb_to_addr(skb, dev);
44*4882a593Smuzhiyun if (!addr)
45*4882a593Smuzhiyun goto out;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun sdev = addr->master->dev;
48*4882a593Smuzhiyun switch (proto) {
49*4882a593Smuzhiyun case AF_INET:
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun struct iphdr *ip4h = ip_hdr(skb);
52*4882a593Smuzhiyun int err;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
55*4882a593Smuzhiyun ip4h->tos, sdev);
56*4882a593Smuzhiyun if (unlikely(err))
57*4882a593Smuzhiyun goto out;
58*4882a593Smuzhiyun break;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
61*4882a593Smuzhiyun case AF_INET6:
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun struct dst_entry *dst;
64*4882a593Smuzhiyun struct ipv6hdr *ip6h = ipv6_hdr(skb);
65*4882a593Smuzhiyun int flags = RT6_LOOKUP_F_HAS_SADDR;
66*4882a593Smuzhiyun struct flowi6 fl6 = {
67*4882a593Smuzhiyun .flowi6_iif = sdev->ifindex,
68*4882a593Smuzhiyun .daddr = ip6h->daddr,
69*4882a593Smuzhiyun .saddr = ip6h->saddr,
70*4882a593Smuzhiyun .flowlabel = ip6_flowinfo(ip6h),
71*4882a593Smuzhiyun .flowi6_mark = skb->mark,
72*4882a593Smuzhiyun .flowi6_proto = ip6h->nexthdr,
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun skb_dst_drop(skb);
76*4882a593Smuzhiyun dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6,
77*4882a593Smuzhiyun skb, flags);
78*4882a593Smuzhiyun skb_dst_set(skb, dst);
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun default:
83*4882a593Smuzhiyun break;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun out:
86*4882a593Smuzhiyun return skb;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static const struct l3mdev_ops ipvl_l3mdev_ops = {
90*4882a593Smuzhiyun .l3mdev_l3_rcv = ipvlan_l3_rcv,
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
ipvlan_nf_input(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)93*4882a593Smuzhiyun static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
94*4882a593Smuzhiyun const struct nf_hook_state *state)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct ipvl_addr *addr;
97*4882a593Smuzhiyun unsigned int len;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun addr = ipvlan_skb_to_addr(skb, skb->dev);
100*4882a593Smuzhiyun if (!addr)
101*4882a593Smuzhiyun goto out;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun skb->dev = addr->master->dev;
104*4882a593Smuzhiyun len = skb->len + ETH_HLEN;
105*4882a593Smuzhiyun ipvlan_count_rx(addr->master, len, true, false);
106*4882a593Smuzhiyun out:
107*4882a593Smuzhiyun return NF_ACCEPT;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun static const struct nf_hook_ops ipvl_nfops[] = {
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun .hook = ipvlan_nf_input,
113*4882a593Smuzhiyun .pf = NFPROTO_IPV4,
114*4882a593Smuzhiyun .hooknum = NF_INET_LOCAL_IN,
115*4882a593Smuzhiyun .priority = INT_MAX,
116*4882a593Smuzhiyun },
117*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun .hook = ipvlan_nf_input,
120*4882a593Smuzhiyun .pf = NFPROTO_IPV6,
121*4882a593Smuzhiyun .hooknum = NF_INET_LOCAL_IN,
122*4882a593Smuzhiyun .priority = INT_MAX,
123*4882a593Smuzhiyun },
124*4882a593Smuzhiyun #endif
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun
ipvlan_register_nf_hook(struct net * net)127*4882a593Smuzhiyun static int ipvlan_register_nf_hook(struct net *net)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
130*4882a593Smuzhiyun int err = 0;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun if (!vnet->ipvl_nf_hook_refcnt) {
133*4882a593Smuzhiyun err = nf_register_net_hooks(net, ipvl_nfops,
134*4882a593Smuzhiyun ARRAY_SIZE(ipvl_nfops));
135*4882a593Smuzhiyun if (!err)
136*4882a593Smuzhiyun vnet->ipvl_nf_hook_refcnt = 1;
137*4882a593Smuzhiyun } else {
138*4882a593Smuzhiyun vnet->ipvl_nf_hook_refcnt++;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return err;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
ipvlan_unregister_nf_hook(struct net * net)144*4882a593Smuzhiyun static void ipvlan_unregister_nf_hook(struct net *net)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
149*4882a593Smuzhiyun return;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun vnet->ipvl_nf_hook_refcnt--;
152*4882a593Smuzhiyun if (!vnet->ipvl_nf_hook_refcnt)
153*4882a593Smuzhiyun nf_unregister_net_hooks(net, ipvl_nfops,
154*4882a593Smuzhiyun ARRAY_SIZE(ipvl_nfops));
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
ipvlan_migrate_l3s_hook(struct net * oldnet,struct net * newnet)157*4882a593Smuzhiyun void ipvlan_migrate_l3s_hook(struct net *oldnet, struct net *newnet)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun struct ipvlan_netns *old_vnet;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun ASSERT_RTNL();
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun old_vnet = net_generic(oldnet, ipvlan_netid);
164*4882a593Smuzhiyun if (!old_vnet->ipvl_nf_hook_refcnt)
165*4882a593Smuzhiyun return;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun ipvlan_register_nf_hook(newnet);
168*4882a593Smuzhiyun ipvlan_unregister_nf_hook(oldnet);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
ipvlan_ns_exit(struct net * net)171*4882a593Smuzhiyun static void ipvlan_ns_exit(struct net *net)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
176*4882a593Smuzhiyun vnet->ipvl_nf_hook_refcnt = 0;
177*4882a593Smuzhiyun nf_unregister_net_hooks(net, ipvl_nfops,
178*4882a593Smuzhiyun ARRAY_SIZE(ipvl_nfops));
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun static struct pernet_operations ipvlan_net_ops = {
183*4882a593Smuzhiyun .id = &ipvlan_netid,
184*4882a593Smuzhiyun .size = sizeof(struct ipvlan_netns),
185*4882a593Smuzhiyun .exit = ipvlan_ns_exit,
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun
ipvlan_l3s_init(void)188*4882a593Smuzhiyun int ipvlan_l3s_init(void)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun return register_pernet_subsys(&ipvlan_net_ops);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
ipvlan_l3s_cleanup(void)193*4882a593Smuzhiyun void ipvlan_l3s_cleanup(void)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun unregister_pernet_subsys(&ipvlan_net_ops);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
ipvlan_l3s_register(struct ipvl_port * port)198*4882a593Smuzhiyun int ipvlan_l3s_register(struct ipvl_port *port)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun struct net_device *dev = port->dev;
201*4882a593Smuzhiyun int ret;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun ASSERT_RTNL();
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun ret = ipvlan_register_nf_hook(read_pnet(&port->pnet));
206*4882a593Smuzhiyun if (!ret) {
207*4882a593Smuzhiyun dev->l3mdev_ops = &ipvl_l3mdev_ops;
208*4882a593Smuzhiyun dev->priv_flags |= IFF_L3MDEV_RX_HANDLER;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun return ret;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
ipvlan_l3s_unregister(struct ipvl_port * port)214*4882a593Smuzhiyun void ipvlan_l3s_unregister(struct ipvl_port *port)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun struct net_device *dev = port->dev;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun ASSERT_RTNL();
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun dev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER;
221*4882a593Smuzhiyun ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
222*4882a593Smuzhiyun dev->l3mdev_ops = NULL;
223*4882a593Smuzhiyun }
224