treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / net / ipvlan / ipvlan_l3s.c
blob943d26cbf39f5d8d14ed247f4918d51b5104f31f
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
3 */
5 #include "ipvlan.h"
7 static unsigned int ipvlan_netid __read_mostly;
9 struct ipvlan_netns {
10 unsigned int ipvl_nf_hook_refcnt;
13 static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
14 struct net_device *dev)
16 struct ipvl_addr *addr = NULL;
17 struct ipvl_port *port;
18 int addr_type;
19 void *lyr3h;
21 if (!dev || !netif_is_ipvlan_port(dev))
22 goto out;
24 port = ipvlan_port_get_rcu(dev);
25 if (!port || port->mode != IPVLAN_MODE_L3S)
26 goto out;
28 lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
29 if (!lyr3h)
30 goto out;
32 addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
33 out:
34 return addr;
37 static struct sk_buff *ipvlan_l3_rcv(struct net_device *dev,
38 struct sk_buff *skb, u16 proto)
40 struct ipvl_addr *addr;
41 struct net_device *sdev;
43 addr = ipvlan_skb_to_addr(skb, dev);
44 if (!addr)
45 goto out;
47 sdev = addr->master->dev;
48 switch (proto) {
49 case AF_INET:
51 struct iphdr *ip4h = ip_hdr(skb);
52 int err;
54 err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
55 ip4h->tos, sdev);
56 if (unlikely(err))
57 goto out;
58 break;
60 #if IS_ENABLED(CONFIG_IPV6)
61 case AF_INET6:
63 struct dst_entry *dst;
64 struct ipv6hdr *ip6h = ipv6_hdr(skb);
65 int flags = RT6_LOOKUP_F_HAS_SADDR;
66 struct flowi6 fl6 = {
67 .flowi6_iif = sdev->ifindex,
68 .daddr = ip6h->daddr,
69 .saddr = ip6h->saddr,
70 .flowlabel = ip6_flowinfo(ip6h),
71 .flowi6_mark = skb->mark,
72 .flowi6_proto = ip6h->nexthdr,
75 skb_dst_drop(skb);
76 dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6,
77 skb, flags);
78 skb_dst_set(skb, dst);
79 break;
81 #endif
82 default:
83 break;
85 out:
86 return skb;
89 static const struct l3mdev_ops ipvl_l3mdev_ops = {
90 .l3mdev_l3_rcv = ipvlan_l3_rcv,
93 static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
94 const struct nf_hook_state *state)
96 struct ipvl_addr *addr;
97 unsigned int len;
99 addr = ipvlan_skb_to_addr(skb, skb->dev);
100 if (!addr)
101 goto out;
103 skb->dev = addr->master->dev;
104 len = skb->len + ETH_HLEN;
105 ipvlan_count_rx(addr->master, len, true, false);
106 out:
107 return NF_ACCEPT;
110 static const struct nf_hook_ops ipvl_nfops[] = {
112 .hook = ipvlan_nf_input,
113 .pf = NFPROTO_IPV4,
114 .hooknum = NF_INET_LOCAL_IN,
115 .priority = INT_MAX,
117 #if IS_ENABLED(CONFIG_IPV6)
119 .hook = ipvlan_nf_input,
120 .pf = NFPROTO_IPV6,
121 .hooknum = NF_INET_LOCAL_IN,
122 .priority = INT_MAX,
124 #endif
127 static int ipvlan_register_nf_hook(struct net *net)
129 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
130 int err = 0;
132 if (!vnet->ipvl_nf_hook_refcnt) {
133 err = nf_register_net_hooks(net, ipvl_nfops,
134 ARRAY_SIZE(ipvl_nfops));
135 if (!err)
136 vnet->ipvl_nf_hook_refcnt = 1;
137 } else {
138 vnet->ipvl_nf_hook_refcnt++;
141 return err;
144 static void ipvlan_unregister_nf_hook(struct net *net)
146 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
148 if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
149 return;
151 vnet->ipvl_nf_hook_refcnt--;
152 if (!vnet->ipvl_nf_hook_refcnt)
153 nf_unregister_net_hooks(net, ipvl_nfops,
154 ARRAY_SIZE(ipvl_nfops));
157 void ipvlan_migrate_l3s_hook(struct net *oldnet, struct net *newnet)
159 struct ipvlan_netns *old_vnet;
161 ASSERT_RTNL();
163 old_vnet = net_generic(oldnet, ipvlan_netid);
164 if (!old_vnet->ipvl_nf_hook_refcnt)
165 return;
167 ipvlan_register_nf_hook(newnet);
168 ipvlan_unregister_nf_hook(oldnet);
171 static void ipvlan_ns_exit(struct net *net)
173 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
175 if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
176 vnet->ipvl_nf_hook_refcnt = 0;
177 nf_unregister_net_hooks(net, ipvl_nfops,
178 ARRAY_SIZE(ipvl_nfops));
182 static struct pernet_operations ipvlan_net_ops = {
183 .id = &ipvlan_netid,
184 .size = sizeof(struct ipvlan_netns),
185 .exit = ipvlan_ns_exit,
188 int ipvlan_l3s_init(void)
190 return register_pernet_subsys(&ipvlan_net_ops);
193 void ipvlan_l3s_cleanup(void)
195 unregister_pernet_subsys(&ipvlan_net_ops);
198 int ipvlan_l3s_register(struct ipvl_port *port)
200 struct net_device *dev = port->dev;
201 int ret;
203 ASSERT_RTNL();
205 ret = ipvlan_register_nf_hook(read_pnet(&port->pnet));
206 if (!ret) {
207 dev->l3mdev_ops = &ipvl_l3mdev_ops;
208 dev->priv_flags |= IFF_L3MDEV_RX_HANDLER;
211 return ret;
214 void ipvlan_l3s_unregister(struct ipvl_port *port)
216 struct net_device *dev = port->dev;
218 ASSERT_RTNL();
220 dev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER;
221 ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
222 dev->l3mdev_ops = NULL;