Linux Audio

Check our new training course

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