xref: /linux/drivers/net/ipvlan/ipvlan_core.c (revision 9410645520e9b820069761f3450ef6661418e279)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22ad7bf36SMahesh Bandewar /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
32ad7bf36SMahesh Bandewar  */
42ad7bf36SMahesh Bandewar 
5*939cd1abSIdo Schimmel #include <net/inet_dscp.h>
6*939cd1abSIdo Schimmel 
72ad7bf36SMahesh Bandewar #include "ipvlan.h"
82ad7bf36SMahesh Bandewar 
9207895fdSDaniel Borkmann static u32 ipvlan_jhash_secret __read_mostly;
102ad7bf36SMahesh Bandewar 
ipvlan_init_secret(void)112ad7bf36SMahesh Bandewar void ipvlan_init_secret(void)
122ad7bf36SMahesh Bandewar {
132ad7bf36SMahesh Bandewar 	net_get_random_once(&ipvlan_jhash_secret, sizeof(ipvlan_jhash_secret));
142ad7bf36SMahesh Bandewar }
152ad7bf36SMahesh Bandewar 
ipvlan_count_rx(const struct ipvl_dev * ipvlan,unsigned int len,bool success,bool mcast)16235a9d89SSainath Grandhi void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
172ad7bf36SMahesh Bandewar 			    unsigned int len, bool success, bool mcast)
182ad7bf36SMahesh Bandewar {
192ad7bf36SMahesh Bandewar 	if (likely(success)) {
202ad7bf36SMahesh Bandewar 		struct ipvl_pcpu_stats *pcptr;
212ad7bf36SMahesh Bandewar 
222ad7bf36SMahesh Bandewar 		pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
232ad7bf36SMahesh Bandewar 		u64_stats_update_begin(&pcptr->syncp);
245665f48eSEric Dumazet 		u64_stats_inc(&pcptr->rx_pkts);
255665f48eSEric Dumazet 		u64_stats_add(&pcptr->rx_bytes, len);
262ad7bf36SMahesh Bandewar 		if (mcast)
275665f48eSEric Dumazet 			u64_stats_inc(&pcptr->rx_mcast);
282ad7bf36SMahesh Bandewar 		u64_stats_update_end(&pcptr->syncp);
292ad7bf36SMahesh Bandewar 	} else {
302ad7bf36SMahesh Bandewar 		this_cpu_inc(ipvlan->pcpu_stats->rx_errs);
312ad7bf36SMahesh Bandewar 	}
322ad7bf36SMahesh Bandewar }
33235a9d89SSainath Grandhi EXPORT_SYMBOL_GPL(ipvlan_count_rx);
342ad7bf36SMahesh Bandewar 
3594333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
ipvlan_get_v6_hash(const void * iaddr)362ad7bf36SMahesh Bandewar static u8 ipvlan_get_v6_hash(const void *iaddr)
372ad7bf36SMahesh Bandewar {
382ad7bf36SMahesh Bandewar 	const struct in6_addr *ip6_addr = iaddr;
392ad7bf36SMahesh Bandewar 
402ad7bf36SMahesh Bandewar 	return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) &
412ad7bf36SMahesh Bandewar 	       IPVLAN_HASH_MASK;
422ad7bf36SMahesh Bandewar }
4394333facSMatteo Croce #else
ipvlan_get_v6_hash(const void * iaddr)4494333facSMatteo Croce static u8 ipvlan_get_v6_hash(const void *iaddr)
4594333facSMatteo Croce {
4694333facSMatteo Croce 	return 0;
4794333facSMatteo Croce }
4894333facSMatteo Croce #endif
492ad7bf36SMahesh Bandewar 
ipvlan_get_v4_hash(const void * iaddr)502ad7bf36SMahesh Bandewar static u8 ipvlan_get_v4_hash(const void *iaddr)
512ad7bf36SMahesh Bandewar {
522ad7bf36SMahesh Bandewar 	const struct in_addr *ip4_addr = iaddr;
532ad7bf36SMahesh Bandewar 
542ad7bf36SMahesh Bandewar 	return jhash_1word(ip4_addr->s_addr, ipvlan_jhash_secret) &
552ad7bf36SMahesh Bandewar 	       IPVLAN_HASH_MASK;
562ad7bf36SMahesh Bandewar }
572ad7bf36SMahesh Bandewar 
addr_equal(bool is_v6,struct ipvl_addr * addr,const void * iaddr)5894333facSMatteo Croce static bool addr_equal(bool is_v6, struct ipvl_addr *addr, const void *iaddr)
5994333facSMatteo Croce {
6094333facSMatteo Croce 	if (!is_v6 && addr->atype == IPVL_IPV4) {
6194333facSMatteo Croce 		struct in_addr *i4addr = (struct in_addr *)iaddr;
6294333facSMatteo Croce 
6394333facSMatteo Croce 		return addr->ip4addr.s_addr == i4addr->s_addr;
6494333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
6594333facSMatteo Croce 	} else if (is_v6 && addr->atype == IPVL_IPV6) {
6694333facSMatteo Croce 		struct in6_addr *i6addr = (struct in6_addr *)iaddr;
6794333facSMatteo Croce 
6894333facSMatteo Croce 		return ipv6_addr_equal(&addr->ip6addr, i6addr);
6994333facSMatteo Croce #endif
7094333facSMatteo Croce 	}
7194333facSMatteo Croce 
7294333facSMatteo Croce 	return false;
7394333facSMatteo Croce }
7494333facSMatteo Croce 
ipvlan_ht_addr_lookup(const struct ipvl_port * port,const void * iaddr,bool is_v6)75ab5b7013SMahesh Bandewar static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
762ad7bf36SMahesh Bandewar 					       const void *iaddr, bool is_v6)
772ad7bf36SMahesh Bandewar {
782ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr;
792ad7bf36SMahesh Bandewar 	u8 hash;
802ad7bf36SMahesh Bandewar 
812ad7bf36SMahesh Bandewar 	hash = is_v6 ? ipvlan_get_v6_hash(iaddr) :
822ad7bf36SMahesh Bandewar 	       ipvlan_get_v4_hash(iaddr);
8394333facSMatteo Croce 	hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
8494333facSMatteo Croce 		if (addr_equal(is_v6, addr, iaddr))
852ad7bf36SMahesh Bandewar 			return addr;
862ad7bf36SMahesh Bandewar 	return NULL;
872ad7bf36SMahesh Bandewar }
882ad7bf36SMahesh Bandewar 
ipvlan_ht_addr_add(struct ipvl_dev * ipvlan,struct ipvl_addr * addr)892ad7bf36SMahesh Bandewar void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
902ad7bf36SMahesh Bandewar {
912ad7bf36SMahesh Bandewar 	struct ipvl_port *port = ipvlan->port;
922ad7bf36SMahesh Bandewar 	u8 hash;
932ad7bf36SMahesh Bandewar 
942ad7bf36SMahesh Bandewar 	hash = (addr->atype == IPVL_IPV6) ?
952ad7bf36SMahesh Bandewar 	       ipvlan_get_v6_hash(&addr->ip6addr) :
962ad7bf36SMahesh Bandewar 	       ipvlan_get_v4_hash(&addr->ip4addr);
9727705f70SJiri Benc 	if (hlist_unhashed(&addr->hlnode))
982ad7bf36SMahesh Bandewar 		hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
992ad7bf36SMahesh Bandewar }
1002ad7bf36SMahesh Bandewar 
ipvlan_ht_addr_del(struct ipvl_addr * addr)1016640e673SKonstantin Khlebnikov void ipvlan_ht_addr_del(struct ipvl_addr *addr)
1022ad7bf36SMahesh Bandewar {
10327705f70SJiri Benc 	hlist_del_init_rcu(&addr->hlnode);
1042ad7bf36SMahesh Bandewar }
1052ad7bf36SMahesh Bandewar 
ipvlan_find_addr(const struct ipvl_dev * ipvlan,const void * iaddr,bool is_v6)106e9997c29SJiri Benc struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
107e9997c29SJiri Benc 				   const void *iaddr, bool is_v6)
1082ad7bf36SMahesh Bandewar {
10982308194SPaolo Abeni 	struct ipvl_addr *addr, *ret = NULL;
1102ad7bf36SMahesh Bandewar 
11182308194SPaolo Abeni 	rcu_read_lock();
11282308194SPaolo Abeni 	list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) {
11382308194SPaolo Abeni 		if (addr_equal(is_v6, addr, iaddr)) {
11482308194SPaolo Abeni 			ret = addr;
11582308194SPaolo Abeni 			break;
11682308194SPaolo Abeni 		}
11782308194SPaolo Abeni 	}
11882308194SPaolo Abeni 	rcu_read_unlock();
11982308194SPaolo Abeni 	return ret;
1202ad7bf36SMahesh Bandewar }
1212ad7bf36SMahesh Bandewar 
ipvlan_addr_busy(struct ipvl_port * port,void * iaddr,bool is_v6)122e9997c29SJiri Benc bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
123e9997c29SJiri Benc {
124e9997c29SJiri Benc 	struct ipvl_dev *ipvlan;
12582308194SPaolo Abeni 	bool ret = false;
1262ad7bf36SMahesh Bandewar 
12782308194SPaolo Abeni 	rcu_read_lock();
12882308194SPaolo Abeni 	list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
12982308194SPaolo Abeni 		if (ipvlan_find_addr(ipvlan, iaddr, is_v6)) {
13082308194SPaolo Abeni 			ret = true;
13182308194SPaolo Abeni 			break;
132e9997c29SJiri Benc 		}
13382308194SPaolo Abeni 	}
13482308194SPaolo Abeni 	rcu_read_unlock();
13582308194SPaolo Abeni 	return ret;
1362ad7bf36SMahesh Bandewar }
1372ad7bf36SMahesh Bandewar 
ipvlan_get_L3_hdr(struct ipvl_port * port,struct sk_buff * skb,int * type)138c675e06aSDaniel Borkmann void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type)
1392ad7bf36SMahesh Bandewar {
1402ad7bf36SMahesh Bandewar 	void *lyr3h = NULL;
1412ad7bf36SMahesh Bandewar 
1422ad7bf36SMahesh Bandewar 	switch (skb->protocol) {
1432ad7bf36SMahesh Bandewar 	case htons(ETH_P_ARP): {
1442ad7bf36SMahesh Bandewar 		struct arphdr *arph;
1452ad7bf36SMahesh Bandewar 
1465fc9220aSGao Feng 		if (unlikely(!pskb_may_pull(skb, arp_hdr_len(port->dev))))
1472ad7bf36SMahesh Bandewar 			return NULL;
1482ad7bf36SMahesh Bandewar 
1492ad7bf36SMahesh Bandewar 		arph = arp_hdr(skb);
1502ad7bf36SMahesh Bandewar 		*type = IPVL_ARP;
1512ad7bf36SMahesh Bandewar 		lyr3h = arph;
1522ad7bf36SMahesh Bandewar 		break;
1532ad7bf36SMahesh Bandewar 	}
1542ad7bf36SMahesh Bandewar 	case htons(ETH_P_IP): {
1552ad7bf36SMahesh Bandewar 		u32 pktlen;
1562ad7bf36SMahesh Bandewar 		struct iphdr *ip4h;
1572ad7bf36SMahesh Bandewar 
1582ad7bf36SMahesh Bandewar 		if (unlikely(!pskb_may_pull(skb, sizeof(*ip4h))))
1592ad7bf36SMahesh Bandewar 			return NULL;
1602ad7bf36SMahesh Bandewar 
1612ad7bf36SMahesh Bandewar 		ip4h = ip_hdr(skb);
16250e6fb5cSXin Long 		pktlen = skb_ip_totlen(skb);
1632ad7bf36SMahesh Bandewar 		if (ip4h->ihl < 5 || ip4h->version != 4)
1642ad7bf36SMahesh Bandewar 			return NULL;
1652ad7bf36SMahesh Bandewar 		if (skb->len < pktlen || pktlen < (ip4h->ihl * 4))
1662ad7bf36SMahesh Bandewar 			return NULL;
1672ad7bf36SMahesh Bandewar 
1682ad7bf36SMahesh Bandewar 		*type = IPVL_IPV4;
1692ad7bf36SMahesh Bandewar 		lyr3h = ip4h;
1702ad7bf36SMahesh Bandewar 		break;
1712ad7bf36SMahesh Bandewar 	}
17294333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
1732ad7bf36SMahesh Bandewar 	case htons(ETH_P_IPV6): {
1742ad7bf36SMahesh Bandewar 		struct ipv6hdr *ip6h;
1752ad7bf36SMahesh Bandewar 
1762ad7bf36SMahesh Bandewar 		if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h))))
1772ad7bf36SMahesh Bandewar 			return NULL;
1782ad7bf36SMahesh Bandewar 
1792ad7bf36SMahesh Bandewar 		ip6h = ipv6_hdr(skb);
1802ad7bf36SMahesh Bandewar 		if (ip6h->version != 6)
1812ad7bf36SMahesh Bandewar 			return NULL;
1822ad7bf36SMahesh Bandewar 
1832ad7bf36SMahesh Bandewar 		*type = IPVL_IPV6;
1842ad7bf36SMahesh Bandewar 		lyr3h = ip6h;
1852ad7bf36SMahesh Bandewar 		/* Only Neighbour Solicitation pkts need different treatment */
1862ad7bf36SMahesh Bandewar 		if (ipv6_addr_any(&ip6h->saddr) &&
1872ad7bf36SMahesh Bandewar 		    ip6h->nexthdr == NEXTHDR_ICMP) {
188747a7135SGao Feng 			struct icmp6hdr	*icmph;
189747a7135SGao Feng 
190747a7135SGao Feng 			if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h) + sizeof(*icmph))))
191747a7135SGao Feng 				return NULL;
192747a7135SGao Feng 
193747a7135SGao Feng 			ip6h = ipv6_hdr(skb);
194747a7135SGao Feng 			icmph = (struct icmp6hdr *)(ip6h + 1);
195747a7135SGao Feng 
196747a7135SGao Feng 			if (icmph->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
197747a7135SGao Feng 				/* Need to access the ipv6 address in body */
198747a7135SGao Feng 				if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h) + sizeof(*icmph)
199747a7135SGao Feng 						+ sizeof(struct in6_addr))))
200747a7135SGao Feng 					return NULL;
201747a7135SGao Feng 
202747a7135SGao Feng 				ip6h = ipv6_hdr(skb);
203747a7135SGao Feng 				icmph = (struct icmp6hdr *)(ip6h + 1);
204747a7135SGao Feng 			}
205747a7135SGao Feng 
2062ad7bf36SMahesh Bandewar 			*type = IPVL_ICMPV6;
207747a7135SGao Feng 			lyr3h = icmph;
2082ad7bf36SMahesh Bandewar 		}
2092ad7bf36SMahesh Bandewar 		break;
2102ad7bf36SMahesh Bandewar 	}
21194333facSMatteo Croce #endif
2122ad7bf36SMahesh Bandewar 	default:
2132ad7bf36SMahesh Bandewar 		return NULL;
2142ad7bf36SMahesh Bandewar 	}
2152ad7bf36SMahesh Bandewar 
2162ad7bf36SMahesh Bandewar 	return lyr3h;
2172ad7bf36SMahesh Bandewar }
2182ad7bf36SMahesh Bandewar 
ipvlan_mac_hash(const unsigned char * addr)2192ad7bf36SMahesh Bandewar unsigned int ipvlan_mac_hash(const unsigned char *addr)
2202ad7bf36SMahesh Bandewar {
2212ad7bf36SMahesh Bandewar 	u32 hash = jhash_1word(__get_unaligned_cpu32(addr+2),
2222ad7bf36SMahesh Bandewar 			       ipvlan_jhash_secret);
2232ad7bf36SMahesh Bandewar 
2242ad7bf36SMahesh Bandewar 	return hash & IPVLAN_MAC_FILTER_MASK;
2252ad7bf36SMahesh Bandewar }
2262ad7bf36SMahesh Bandewar 
ipvlan_process_multicast(struct work_struct * work)227ba35f858SMahesh Bandewar void ipvlan_process_multicast(struct work_struct *work)
2282ad7bf36SMahesh Bandewar {
229ba35f858SMahesh Bandewar 	struct ipvl_port *port = container_of(work, struct ipvl_port, wq);
230ba35f858SMahesh Bandewar 	struct ethhdr *ethh;
2312ad7bf36SMahesh Bandewar 	struct ipvl_dev *ipvlan;
232ba35f858SMahesh Bandewar 	struct sk_buff *skb, *nskb;
233ba35f858SMahesh Bandewar 	struct sk_buff_head list;
2342ad7bf36SMahesh Bandewar 	unsigned int len;
2352ad7bf36SMahesh Bandewar 	unsigned int mac_hash;
2362ad7bf36SMahesh Bandewar 	int ret;
237ba35f858SMahesh Bandewar 	u8 pkt_type;
238e2525360SMahesh Bandewar 	bool tx_pkt;
2392ad7bf36SMahesh Bandewar 
240ba35f858SMahesh Bandewar 	__skb_queue_head_init(&list);
2412ad7bf36SMahesh Bandewar 
242ba35f858SMahesh Bandewar 	spin_lock_bh(&port->backlog.lock);
243ba35f858SMahesh Bandewar 	skb_queue_splice_tail_init(&port->backlog, &list);
244ba35f858SMahesh Bandewar 	spin_unlock_bh(&port->backlog.lock);
245ba35f858SMahesh Bandewar 
246ba35f858SMahesh Bandewar 	while ((skb = __skb_dequeue(&list)) != NULL) {
247b1227d01SEric Dumazet 		struct net_device *dev = skb->dev;
248b1227d01SEric Dumazet 		bool consumed = false;
249b1227d01SEric Dumazet 
250ba35f858SMahesh Bandewar 		ethh = eth_hdr(skb);
251e2525360SMahesh Bandewar 		tx_pkt = IPVL_SKB_CB(skb)->tx_pkt;
252ba35f858SMahesh Bandewar 		mac_hash = ipvlan_mac_hash(ethh->h_dest);
253ba35f858SMahesh Bandewar 
254ba35f858SMahesh Bandewar 		if (ether_addr_equal(ethh->h_dest, port->dev->broadcast))
255ba35f858SMahesh Bandewar 			pkt_type = PACKET_BROADCAST;
256ba35f858SMahesh Bandewar 		else
257ba35f858SMahesh Bandewar 			pkt_type = PACKET_MULTICAST;
258ba35f858SMahesh Bandewar 
2592afa650cSJiri Benc 		rcu_read_lock();
2602afa650cSJiri Benc 		list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
261e2525360SMahesh Bandewar 			if (tx_pkt && (ipvlan->dev == skb->dev))
2622ad7bf36SMahesh Bandewar 				continue;
2632ad7bf36SMahesh Bandewar 			if (!test_bit(mac_hash, ipvlan->mac_filters))
2642ad7bf36SMahesh Bandewar 				continue;
265b1227d01SEric Dumazet 			if (!(ipvlan->dev->flags & IFF_UP))
266b1227d01SEric Dumazet 				continue;
2672ad7bf36SMahesh Bandewar 			ret = NET_RX_DROP;
2682ad7bf36SMahesh Bandewar 			len = skb->len + ETH_HLEN;
2692ad7bf36SMahesh Bandewar 			nskb = skb_clone(skb, GFP_ATOMIC);
270b1227d01SEric Dumazet 			local_bh_disable();
271b1227d01SEric Dumazet 			if (nskb) {
272b1227d01SEric Dumazet 				consumed = true;
273ba35f858SMahesh Bandewar 				nskb->pkt_type = pkt_type;
2742ad7bf36SMahesh Bandewar 				nskb->dev = ipvlan->dev;
275e2525360SMahesh Bandewar 				if (tx_pkt)
2762ad7bf36SMahesh Bandewar 					ret = dev_forward_skb(ipvlan->dev, nskb);
2772ad7bf36SMahesh Bandewar 				else
2782ad7bf36SMahesh Bandewar 					ret = netif_rx(nskb);
279b1227d01SEric Dumazet 			}
2802ad7bf36SMahesh Bandewar 			ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
281b1227d01SEric Dumazet 			local_bh_enable();
2822ad7bf36SMahesh Bandewar 		}
2832afa650cSJiri Benc 		rcu_read_unlock();
2842ad7bf36SMahesh Bandewar 
285e2525360SMahesh Bandewar 		if (tx_pkt) {
286ba35f858SMahesh Bandewar 			/* If the packet originated here, send it out. */
287ba35f858SMahesh Bandewar 			skb->dev = port->dev;
288ba35f858SMahesh Bandewar 			skb->pkt_type = pkt_type;
289ba35f858SMahesh Bandewar 			dev_queue_xmit(skb);
290ba35f858SMahesh Bandewar 		} else {
291b1227d01SEric Dumazet 			if (consumed)
292b1227d01SEric Dumazet 				consume_skb(skb);
293b1227d01SEric Dumazet 			else
294ba35f858SMahesh Bandewar 				kfree_skb(skb);
2952ad7bf36SMahesh Bandewar 		}
296b1227d01SEric Dumazet 		dev_put(dev);
297afe207d8SEric Dumazet 		cond_resched();
2982ad7bf36SMahesh Bandewar 	}
2992ad7bf36SMahesh Bandewar }
3002ad7bf36SMahesh Bandewar 
ipvlan_skb_crossing_ns(struct sk_buff * skb,struct net_device * dev)301b93dd49cSMahesh Bandewar static void ipvlan_skb_crossing_ns(struct sk_buff *skb, struct net_device *dev)
302b93dd49cSMahesh Bandewar {
303b93dd49cSMahesh Bandewar 	bool xnet = true;
304b93dd49cSMahesh Bandewar 
305b93dd49cSMahesh Bandewar 	if (dev)
306b93dd49cSMahesh Bandewar 		xnet = !net_eq(dev_net(skb->dev), dev_net(dev));
307b93dd49cSMahesh Bandewar 
308b93dd49cSMahesh Bandewar 	skb_scrub_packet(skb, xnet);
309b93dd49cSMahesh Bandewar 	if (dev)
310b93dd49cSMahesh Bandewar 		skb->dev = dev;
311b93dd49cSMahesh Bandewar }
312b93dd49cSMahesh Bandewar 
ipvlan_rcv_frame(struct ipvl_addr * addr,struct sk_buff ** pskb,bool local)313cf554adaSSabrina Dubroca static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
3142ad7bf36SMahesh Bandewar 			    bool local)
3152ad7bf36SMahesh Bandewar {
3162ad7bf36SMahesh Bandewar 	struct ipvl_dev *ipvlan = addr->master;
3172ad7bf36SMahesh Bandewar 	struct net_device *dev = ipvlan->dev;
3182ad7bf36SMahesh Bandewar 	unsigned int len;
3192ad7bf36SMahesh Bandewar 	rx_handler_result_t ret = RX_HANDLER_CONSUMED;
3202ad7bf36SMahesh Bandewar 	bool success = false;
321cf554adaSSabrina Dubroca 	struct sk_buff *skb = *pskb;
3222ad7bf36SMahesh Bandewar 
3232ad7bf36SMahesh Bandewar 	len = skb->len + ETH_HLEN;
324ab5b7013SMahesh Bandewar 	/* Only packets exchanged between two local slaves need to have
325ab5b7013SMahesh Bandewar 	 * device-up check as well as skb-share check.
326ab5b7013SMahesh Bandewar 	 */
327ab5b7013SMahesh Bandewar 	if (local) {
3282ad7bf36SMahesh Bandewar 		if (unlikely(!(dev->flags & IFF_UP))) {
3292ad7bf36SMahesh Bandewar 			kfree_skb(skb);
3302ad7bf36SMahesh Bandewar 			goto out;
3312ad7bf36SMahesh Bandewar 		}
3322ad7bf36SMahesh Bandewar 
3332ad7bf36SMahesh Bandewar 		skb = skb_share_check(skb, GFP_ATOMIC);
3342ad7bf36SMahesh Bandewar 		if (!skb)
3352ad7bf36SMahesh Bandewar 			goto out;
3362ad7bf36SMahesh Bandewar 
337cf554adaSSabrina Dubroca 		*pskb = skb;
338ab5b7013SMahesh Bandewar 	}
3392ad7bf36SMahesh Bandewar 
3402ad7bf36SMahesh Bandewar 	if (local) {
341ab5b7013SMahesh Bandewar 		skb->pkt_type = PACKET_HOST;
3422ad7bf36SMahesh Bandewar 		if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS)
3432ad7bf36SMahesh Bandewar 			success = true;
3442ad7bf36SMahesh Bandewar 	} else {
345c0d451c8SMahesh Bandewar 		skb->dev = dev;
3462ad7bf36SMahesh Bandewar 		ret = RX_HANDLER_ANOTHER;
3472ad7bf36SMahesh Bandewar 		success = true;
3482ad7bf36SMahesh Bandewar 	}
3492ad7bf36SMahesh Bandewar 
3502ad7bf36SMahesh Bandewar out:
3512ad7bf36SMahesh Bandewar 	ipvlan_count_rx(ipvlan, len, success, false);
3522ad7bf36SMahesh Bandewar 	return ret;
3532ad7bf36SMahesh Bandewar }
3542ad7bf36SMahesh Bandewar 
ipvlan_addr_lookup(struct ipvl_port * port,void * lyr3h,int addr_type,bool use_dest)355c675e06aSDaniel Borkmann struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
356c675e06aSDaniel Borkmann 				     int addr_type, bool use_dest)
3572ad7bf36SMahesh Bandewar {
3582ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr = NULL;
3592ad7bf36SMahesh Bandewar 
36094333facSMatteo Croce 	switch (addr_type) {
36194333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
36294333facSMatteo Croce 	case IPVL_IPV6: {
3632ad7bf36SMahesh Bandewar 		struct ipv6hdr *ip6h;
3642ad7bf36SMahesh Bandewar 		struct in6_addr *i6addr;
3652ad7bf36SMahesh Bandewar 
3662ad7bf36SMahesh Bandewar 		ip6h = (struct ipv6hdr *)lyr3h;
3672ad7bf36SMahesh Bandewar 		i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
3682ad7bf36SMahesh Bandewar 		addr = ipvlan_ht_addr_lookup(port, i6addr, true);
36994333facSMatteo Croce 		break;
37094333facSMatteo Croce 	}
37194333facSMatteo Croce 	case IPVL_ICMPV6: {
3722ad7bf36SMahesh Bandewar 		struct nd_msg *ndmh;
3732ad7bf36SMahesh Bandewar 		struct in6_addr *i6addr;
3742ad7bf36SMahesh Bandewar 
3752ad7bf36SMahesh Bandewar 		/* Make sure that the NeighborSolicitation ICMPv6 packets
3762ad7bf36SMahesh Bandewar 		 * are handled to avoid DAD issue.
3772ad7bf36SMahesh Bandewar 		 */
3782ad7bf36SMahesh Bandewar 		ndmh = (struct nd_msg *)lyr3h;
3792ad7bf36SMahesh Bandewar 		if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
3802ad7bf36SMahesh Bandewar 			i6addr = &ndmh->target;
3812ad7bf36SMahesh Bandewar 			addr = ipvlan_ht_addr_lookup(port, i6addr, true);
3822ad7bf36SMahesh Bandewar 		}
38394333facSMatteo Croce 		break;
38494333facSMatteo Croce 	}
38594333facSMatteo Croce #endif
38694333facSMatteo Croce 	case IPVL_IPV4: {
3872ad7bf36SMahesh Bandewar 		struct iphdr *ip4h;
3882ad7bf36SMahesh Bandewar 		__be32 *i4addr;
3892ad7bf36SMahesh Bandewar 
3902ad7bf36SMahesh Bandewar 		ip4h = (struct iphdr *)lyr3h;
3912ad7bf36SMahesh Bandewar 		i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
3922ad7bf36SMahesh Bandewar 		addr = ipvlan_ht_addr_lookup(port, i4addr, false);
39394333facSMatteo Croce 		break;
39494333facSMatteo Croce 	}
39594333facSMatteo Croce 	case IPVL_ARP: {
3962ad7bf36SMahesh Bandewar 		struct arphdr *arph;
3972ad7bf36SMahesh Bandewar 		unsigned char *arp_ptr;
3982ad7bf36SMahesh Bandewar 		__be32 dip;
3992ad7bf36SMahesh Bandewar 
4002ad7bf36SMahesh Bandewar 		arph = (struct arphdr *)lyr3h;
4012ad7bf36SMahesh Bandewar 		arp_ptr = (unsigned char *)(arph + 1);
4022ad7bf36SMahesh Bandewar 		if (use_dest)
4032ad7bf36SMahesh Bandewar 			arp_ptr += (2 * port->dev->addr_len) + 4;
4042ad7bf36SMahesh Bandewar 		else
4052ad7bf36SMahesh Bandewar 			arp_ptr += port->dev->addr_len;
4062ad7bf36SMahesh Bandewar 
4072ad7bf36SMahesh Bandewar 		memcpy(&dip, arp_ptr, 4);
4082ad7bf36SMahesh Bandewar 		addr = ipvlan_ht_addr_lookup(port, &dip, false);
40994333facSMatteo Croce 		break;
41094333facSMatteo Croce 	}
4112ad7bf36SMahesh Bandewar 	}
4122ad7bf36SMahesh Bandewar 
4132ad7bf36SMahesh Bandewar 	return addr;
4142ad7bf36SMahesh Bandewar }
4152ad7bf36SMahesh Bandewar 
ipvlan_process_v4_outbound(struct sk_buff * skb)41618f03942SEric Dumazet static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb)
4172ad7bf36SMahesh Bandewar {
4182ad7bf36SMahesh Bandewar 	const struct iphdr *ip4h = ip_hdr(skb);
4192ad7bf36SMahesh Bandewar 	struct net_device *dev = skb->dev;
42057c4bf85SEric W. Biederman 	struct net *net = dev_net(dev);
4212ad7bf36SMahesh Bandewar 	struct rtable *rt;
4222ad7bf36SMahesh Bandewar 	int err, ret = NET_XMIT_DROP;
4232ad7bf36SMahesh Bandewar 	struct flowi4 fl4 = {
42463b11e75SBrenden Blanco 		.flowi4_oif = dev->ifindex,
425*939cd1abSIdo Schimmel 		.flowi4_tos = ip4h->tos & INET_DSCP_MASK,
4262ad7bf36SMahesh Bandewar 		.flowi4_flags = FLOWI_FLAG_ANYSRC,
427a98a4ebcSGao Feng 		.flowi4_mark = skb->mark,
4282ad7bf36SMahesh Bandewar 		.daddr = ip4h->daddr,
4292ad7bf36SMahesh Bandewar 		.saddr = ip4h->saddr,
4302ad7bf36SMahesh Bandewar 	};
4312ad7bf36SMahesh Bandewar 
43257c4bf85SEric W. Biederman 	rt = ip_route_output_flow(net, &fl4, NULL);
4332ad7bf36SMahesh Bandewar 	if (IS_ERR(rt))
4342ad7bf36SMahesh Bandewar 		goto err;
4352ad7bf36SMahesh Bandewar 
4362ad7bf36SMahesh Bandewar 	if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
4372ad7bf36SMahesh Bandewar 		ip_rt_put(rt);
4382ad7bf36SMahesh Bandewar 		goto err;
4392ad7bf36SMahesh Bandewar 	}
4402ad7bf36SMahesh Bandewar 	skb_dst_set(skb, &rt->dst);
44190cbed52St.feng 
44290cbed52St.feng 	memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
44390cbed52St.feng 
444b3dc6e80SYue Haibing 	err = ip_local_out(net, NULL, skb);
4452ad7bf36SMahesh Bandewar 	if (unlikely(net_xmit_eval(err)))
446ff672b9fSEric Dumazet 		DEV_STATS_INC(dev, tx_errors);
4472ad7bf36SMahesh Bandewar 	else
4482ad7bf36SMahesh Bandewar 		ret = NET_XMIT_SUCCESS;
4492ad7bf36SMahesh Bandewar 	goto out;
4502ad7bf36SMahesh Bandewar err:
451ff672b9fSEric Dumazet 	DEV_STATS_INC(dev, tx_errors);
4522ad7bf36SMahesh Bandewar 	kfree_skb(skb);
4532ad7bf36SMahesh Bandewar out:
4542ad7bf36SMahesh Bandewar 	return ret;
4552ad7bf36SMahesh Bandewar }
4562ad7bf36SMahesh Bandewar 
45794333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
45818f03942SEric Dumazet 
45918f03942SEric Dumazet static noinline_for_stack int
ipvlan_route_v6_outbound(struct net_device * dev,struct sk_buff * skb)46018f03942SEric Dumazet ipvlan_route_v6_outbound(struct net_device *dev, struct sk_buff *skb)
4612ad7bf36SMahesh Bandewar {
4622ad7bf36SMahesh Bandewar 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
4632ad7bf36SMahesh Bandewar 	struct flowi6 fl6 = {
464ca29fd7cSKeefe Liu 		.flowi6_oif = dev->ifindex,
4652ad7bf36SMahesh Bandewar 		.daddr = ip6h->daddr,
4662ad7bf36SMahesh Bandewar 		.saddr = ip6h->saddr,
4672ad7bf36SMahesh Bandewar 		.flowi6_flags = FLOWI_FLAG_ANYSRC,
4682ad7bf36SMahesh Bandewar 		.flowlabel = ip6_flowinfo(ip6h),
4692ad7bf36SMahesh Bandewar 		.flowi6_mark = skb->mark,
4702ad7bf36SMahesh Bandewar 		.flowi6_proto = ip6h->nexthdr,
4712ad7bf36SMahesh Bandewar 	};
47218f03942SEric Dumazet 	struct dst_entry *dst;
47318f03942SEric Dumazet 	int err;
4742ad7bf36SMahesh Bandewar 
47518f03942SEric Dumazet 	dst = ip6_route_output(dev_net(dev), NULL, &fl6);
47618f03942SEric Dumazet 	err = dst->error;
47718f03942SEric Dumazet 	if (err) {
4782aab9525SMahesh Bandewar 		dst_release(dst);
47918f03942SEric Dumazet 		return err;
4802aab9525SMahesh Bandewar 	}
4812ad7bf36SMahesh Bandewar 	skb_dst_set(skb, dst);
48218f03942SEric Dumazet 	return 0;
48318f03942SEric Dumazet }
48418f03942SEric Dumazet 
ipvlan_process_v6_outbound(struct sk_buff * skb)48518f03942SEric Dumazet static int ipvlan_process_v6_outbound(struct sk_buff *skb)
48618f03942SEric Dumazet {
48718f03942SEric Dumazet 	struct net_device *dev = skb->dev;
48818f03942SEric Dumazet 	int err, ret = NET_XMIT_DROP;
48918f03942SEric Dumazet 
49018f03942SEric Dumazet 	err = ipvlan_route_v6_outbound(dev, skb);
49118f03942SEric Dumazet 	if (unlikely(err)) {
49218f03942SEric Dumazet 		DEV_STATS_INC(dev, tx_errors);
49318f03942SEric Dumazet 		kfree_skb(skb);
49418f03942SEric Dumazet 		return err;
49518f03942SEric Dumazet 	}
49690cbed52St.feng 
49790cbed52St.feng 	memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
49890cbed52St.feng 
499b3dc6e80SYue Haibing 	err = ip6_local_out(dev_net(dev), NULL, skb);
5002ad7bf36SMahesh Bandewar 	if (unlikely(net_xmit_eval(err)))
501ff672b9fSEric Dumazet 		DEV_STATS_INC(dev, tx_errors);
5022ad7bf36SMahesh Bandewar 	else
5032ad7bf36SMahesh Bandewar 		ret = NET_XMIT_SUCCESS;
5042ad7bf36SMahesh Bandewar 	return ret;
5052ad7bf36SMahesh Bandewar }
50694333facSMatteo Croce #else
ipvlan_process_v6_outbound(struct sk_buff * skb)50794333facSMatteo Croce static int ipvlan_process_v6_outbound(struct sk_buff *skb)
50894333facSMatteo Croce {
50994333facSMatteo Croce 	return NET_XMIT_DROP;
51094333facSMatteo Croce }
51194333facSMatteo Croce #endif
5122ad7bf36SMahesh Bandewar 
ipvlan_process_outbound(struct sk_buff * skb)513b93dd49cSMahesh Bandewar static int ipvlan_process_outbound(struct sk_buff *skb)
5142ad7bf36SMahesh Bandewar {
5152ad7bf36SMahesh Bandewar 	int ret = NET_XMIT_DROP;
5162ad7bf36SMahesh Bandewar 
5172ad7bf36SMahesh Bandewar 	/* The ipvlan is a pseudo-L2 device, so the packets that we receive
5182ad7bf36SMahesh Bandewar 	 * will have L2; which need to discarded and processed further
5192ad7bf36SMahesh Bandewar 	 * in the net-ns of the main-device.
5202ad7bf36SMahesh Bandewar 	 */
5212ad7bf36SMahesh Bandewar 	if (skb_mac_header_was_set(skb)) {
522ad819276SMahesh Bandewar 		/* In this mode we dont care about
523ad819276SMahesh Bandewar 		 * multicast and broadcast traffic */
52481225b2eSLu Wei 		struct ethhdr *ethh = eth_hdr(skb);
52581225b2eSLu Wei 
526ad819276SMahesh Bandewar 		if (is_multicast_ether_addr(ethh->h_dest)) {
527ad819276SMahesh Bandewar 			pr_debug_ratelimited(
528ad819276SMahesh Bandewar 				"Dropped {multi|broad}cast of type=[%x]\n",
529ad819276SMahesh Bandewar 				ntohs(skb->protocol));
530ad819276SMahesh Bandewar 			kfree_skb(skb);
531ad819276SMahesh Bandewar 			goto out;
532ad819276SMahesh Bandewar 		}
533ad819276SMahesh Bandewar 
5342ad7bf36SMahesh Bandewar 		skb_pull(skb, sizeof(*ethh));
5352ad7bf36SMahesh Bandewar 		skb->mac_header = (typeof(skb->mac_header))~0U;
5362ad7bf36SMahesh Bandewar 		skb_reset_network_header(skb);
5372ad7bf36SMahesh Bandewar 	}
5382ad7bf36SMahesh Bandewar 
5392ad7bf36SMahesh Bandewar 	if (skb->protocol == htons(ETH_P_IPV6))
540b93dd49cSMahesh Bandewar 		ret = ipvlan_process_v6_outbound(skb);
5412ad7bf36SMahesh Bandewar 	else if (skb->protocol == htons(ETH_P_IP))
542b93dd49cSMahesh Bandewar 		ret = ipvlan_process_v4_outbound(skb);
5432ad7bf36SMahesh Bandewar 	else {
5442ad7bf36SMahesh Bandewar 		pr_warn_ratelimited("Dropped outbound packet type=%x\n",
5452ad7bf36SMahesh Bandewar 				    ntohs(skb->protocol));
5462ad7bf36SMahesh Bandewar 		kfree_skb(skb);
5472ad7bf36SMahesh Bandewar 	}
5482ad7bf36SMahesh Bandewar out:
5492ad7bf36SMahesh Bandewar 	return ret;
5502ad7bf36SMahesh Bandewar }
5512ad7bf36SMahesh Bandewar 
ipvlan_multicast_enqueue(struct ipvl_port * port,struct sk_buff * skb,bool tx_pkt)552ba35f858SMahesh Bandewar static void ipvlan_multicast_enqueue(struct ipvl_port *port,
553e2525360SMahesh Bandewar 				     struct sk_buff *skb, bool tx_pkt)
554ba35f858SMahesh Bandewar {
555ba35f858SMahesh Bandewar 	if (skb->protocol == htons(ETH_P_PAUSE)) {
556ba35f858SMahesh Bandewar 		kfree_skb(skb);
557ba35f858SMahesh Bandewar 		return;
558ba35f858SMahesh Bandewar 	}
559ba35f858SMahesh Bandewar 
560e2525360SMahesh Bandewar 	/* Record that the deferred packet is from TX or RX path. By
561e2525360SMahesh Bandewar 	 * looking at mac-addresses on packet will lead to erronus decisions.
562e2525360SMahesh Bandewar 	 * (This would be true for a loopback-mode on master device or a
563e2525360SMahesh Bandewar 	 * hair-pin mode of the switch.)
564e2525360SMahesh Bandewar 	 */
565e2525360SMahesh Bandewar 	IPVL_SKB_CB(skb)->tx_pkt = tx_pkt;
566e2525360SMahesh Bandewar 
567ba35f858SMahesh Bandewar 	spin_lock(&port->backlog.lock);
568ba35f858SMahesh Bandewar 	if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) {
569b1227d01SEric Dumazet 		dev_hold(skb->dev);
570ba35f858SMahesh Bandewar 		__skb_queue_tail(&port->backlog, skb);
571ba35f858SMahesh Bandewar 		spin_unlock(&port->backlog.lock);
572ba35f858SMahesh Bandewar 		schedule_work(&port->wq);
573ba35f858SMahesh Bandewar 	} else {
574ba35f858SMahesh Bandewar 		spin_unlock(&port->backlog.lock);
575625788b5SEric Dumazet 		dev_core_stats_rx_dropped_inc(skb->dev);
576ba35f858SMahesh Bandewar 		kfree_skb(skb);
577ba35f858SMahesh Bandewar 	}
578ba35f858SMahesh Bandewar }
579ba35f858SMahesh Bandewar 
ipvlan_xmit_mode_l3(struct sk_buff * skb,struct net_device * dev)5802ad7bf36SMahesh Bandewar static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
5812ad7bf36SMahesh Bandewar {
5822ad7bf36SMahesh Bandewar 	const struct ipvl_dev *ipvlan = netdev_priv(dev);
5832ad7bf36SMahesh Bandewar 	void *lyr3h;
5842ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr;
5852ad7bf36SMahesh Bandewar 	int addr_type;
5862ad7bf36SMahesh Bandewar 
5875fc9220aSGao Feng 	lyr3h = ipvlan_get_L3_hdr(ipvlan->port, skb, &addr_type);
5882ad7bf36SMahesh Bandewar 	if (!lyr3h)
5892ad7bf36SMahesh Bandewar 		goto out;
5902ad7bf36SMahesh Bandewar 
591fe89aa6bSMahesh Bandewar 	if (!ipvlan_is_vepa(ipvlan->port)) {
5922ad7bf36SMahesh Bandewar 		addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
593a190d04dSMahesh Bandewar 		if (addr) {
594a190d04dSMahesh Bandewar 			if (ipvlan_is_private(ipvlan->port)) {
595a190d04dSMahesh Bandewar 				consume_skb(skb);
596a190d04dSMahesh Bandewar 				return NET_XMIT_DROP;
597a190d04dSMahesh Bandewar 			}
5988a9922e7SCambda Zhu 			ipvlan_rcv_frame(addr, &skb, true);
5998a9922e7SCambda Zhu 			return NET_XMIT_SUCCESS;
600a190d04dSMahesh Bandewar 		}
601fe89aa6bSMahesh Bandewar 	}
6022ad7bf36SMahesh Bandewar out:
603b93dd49cSMahesh Bandewar 	ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev);
604b93dd49cSMahesh Bandewar 	return ipvlan_process_outbound(skb);
6052ad7bf36SMahesh Bandewar }
6062ad7bf36SMahesh Bandewar 
ipvlan_xmit_mode_l2(struct sk_buff * skb,struct net_device * dev)6072ad7bf36SMahesh Bandewar static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
6082ad7bf36SMahesh Bandewar {
6092ad7bf36SMahesh Bandewar 	const struct ipvl_dev *ipvlan = netdev_priv(dev);
61081225b2eSLu Wei 	struct ethhdr *eth = skb_eth_hdr(skb);
6112ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr;
6122ad7bf36SMahesh Bandewar 	void *lyr3h;
6132ad7bf36SMahesh Bandewar 	int addr_type;
6142ad7bf36SMahesh Bandewar 
615fe89aa6bSMahesh Bandewar 	if (!ipvlan_is_vepa(ipvlan->port) &&
616fe89aa6bSMahesh Bandewar 	    ether_addr_equal(eth->h_dest, eth->h_source)) {
6175fc9220aSGao Feng 		lyr3h = ipvlan_get_L3_hdr(ipvlan->port, skb, &addr_type);
6182ad7bf36SMahesh Bandewar 		if (lyr3h) {
6192ad7bf36SMahesh Bandewar 			addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
620a190d04dSMahesh Bandewar 			if (addr) {
621a190d04dSMahesh Bandewar 				if (ipvlan_is_private(ipvlan->port)) {
622a190d04dSMahesh Bandewar 					consume_skb(skb);
623a190d04dSMahesh Bandewar 					return NET_XMIT_DROP;
624a190d04dSMahesh Bandewar 				}
6258a9922e7SCambda Zhu 				ipvlan_rcv_frame(addr, &skb, true);
6268a9922e7SCambda Zhu 				return NET_XMIT_SUCCESS;
6272ad7bf36SMahesh Bandewar 			}
628a190d04dSMahesh Bandewar 		}
6292ad7bf36SMahesh Bandewar 		skb = skb_share_check(skb, GFP_ATOMIC);
6302ad7bf36SMahesh Bandewar 		if (!skb)
6312ad7bf36SMahesh Bandewar 			return NET_XMIT_DROP;
6322ad7bf36SMahesh Bandewar 
6332ad7bf36SMahesh Bandewar 		/* Packet definitely does not belong to any of the
6342ad7bf36SMahesh Bandewar 		 * virtual devices, but the dest is local. So forward
6352ad7bf36SMahesh Bandewar 		 * the skb for the main-dev. At the RX side we just return
6362ad7bf36SMahesh Bandewar 		 * RX_PASS for it to be processed further on the stack.
6372ad7bf36SMahesh Bandewar 		 */
6388a9922e7SCambda Zhu 		dev_forward_skb(ipvlan->phy_dev, skb);
6398a9922e7SCambda Zhu 		return NET_XMIT_SUCCESS;
6402ad7bf36SMahesh Bandewar 
6412ad7bf36SMahesh Bandewar 	} else if (is_multicast_ether_addr(eth->h_dest)) {
64281225b2eSLu Wei 		skb_reset_mac_header(skb);
643b93dd49cSMahesh Bandewar 		ipvlan_skb_crossing_ns(skb, NULL);
644e2525360SMahesh Bandewar 		ipvlan_multicast_enqueue(ipvlan->port, skb, true);
645ba35f858SMahesh Bandewar 		return NET_XMIT_SUCCESS;
6462ad7bf36SMahesh Bandewar 	}
6472ad7bf36SMahesh Bandewar 
648c0d451c8SMahesh Bandewar 	skb->dev = ipvlan->phy_dev;
6492ad7bf36SMahesh Bandewar 	return dev_queue_xmit(skb);
6502ad7bf36SMahesh Bandewar }
6512ad7bf36SMahesh Bandewar 
ipvlan_queue_xmit(struct sk_buff * skb,struct net_device * dev)6522ad7bf36SMahesh Bandewar int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
6532ad7bf36SMahesh Bandewar {
6542ad7bf36SMahesh Bandewar 	struct ipvl_dev *ipvlan = netdev_priv(dev);
6550fba37a3SWANG Cong 	struct ipvl_port *port = ipvlan_port_get_rcu_bh(ipvlan->phy_dev);
6562ad7bf36SMahesh Bandewar 
6572ad7bf36SMahesh Bandewar 	if (!port)
6582ad7bf36SMahesh Bandewar 		goto out;
6592ad7bf36SMahesh Bandewar 
6602ad7bf36SMahesh Bandewar 	if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
6612ad7bf36SMahesh Bandewar 		goto out;
6622ad7bf36SMahesh Bandewar 
6632ad7bf36SMahesh Bandewar 	switch(port->mode) {
6642ad7bf36SMahesh Bandewar 	case IPVLAN_MODE_L2:
6652ad7bf36SMahesh Bandewar 		return ipvlan_xmit_mode_l2(skb, dev);
6662ad7bf36SMahesh Bandewar 	case IPVLAN_MODE_L3:
667c675e06aSDaniel Borkmann #ifdef CONFIG_IPVLAN_L3S
6684fbae7d8SMahesh Bandewar 	case IPVLAN_MODE_L3S:
669c675e06aSDaniel Borkmann #endif
6702ad7bf36SMahesh Bandewar 		return ipvlan_xmit_mode_l3(skb, dev);
6712ad7bf36SMahesh Bandewar 	}
6722ad7bf36SMahesh Bandewar 
6732ad7bf36SMahesh Bandewar 	/* Should not reach here */
674d7a177eaSTom Rix 	WARN_ONCE(true, "%s called for mode = [%x]\n", __func__, port->mode);
6752ad7bf36SMahesh Bandewar out:
6762ad7bf36SMahesh Bandewar 	kfree_skb(skb);
6772ad7bf36SMahesh Bandewar 	return NET_XMIT_DROP;
6782ad7bf36SMahesh Bandewar }
6792ad7bf36SMahesh Bandewar 
ipvlan_external_frame(struct sk_buff * skb,struct ipvl_port * port)6802ad7bf36SMahesh Bandewar static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port)
6812ad7bf36SMahesh Bandewar {
6822ad7bf36SMahesh Bandewar 	struct ethhdr *eth = eth_hdr(skb);
6832ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr;
6842ad7bf36SMahesh Bandewar 	void *lyr3h;
6852ad7bf36SMahesh Bandewar 	int addr_type;
6862ad7bf36SMahesh Bandewar 
6872ad7bf36SMahesh Bandewar 	if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) {
6885fc9220aSGao Feng 		lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
6892ad7bf36SMahesh Bandewar 		if (!lyr3h)
6902ad7bf36SMahesh Bandewar 			return true;
6912ad7bf36SMahesh Bandewar 
6922ad7bf36SMahesh Bandewar 		addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false);
6932ad7bf36SMahesh Bandewar 		if (addr)
6942ad7bf36SMahesh Bandewar 			return false;
6952ad7bf36SMahesh Bandewar 	}
6962ad7bf36SMahesh Bandewar 
6972ad7bf36SMahesh Bandewar 	return true;
6982ad7bf36SMahesh Bandewar }
6992ad7bf36SMahesh Bandewar 
ipvlan_handle_mode_l3(struct sk_buff ** pskb,struct ipvl_port * port)7002ad7bf36SMahesh Bandewar static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
7012ad7bf36SMahesh Bandewar 						 struct ipvl_port *port)
7022ad7bf36SMahesh Bandewar {
7032ad7bf36SMahesh Bandewar 	void *lyr3h;
7042ad7bf36SMahesh Bandewar 	int addr_type;
7052ad7bf36SMahesh Bandewar 	struct ipvl_addr *addr;
7062ad7bf36SMahesh Bandewar 	struct sk_buff *skb = *pskb;
7072ad7bf36SMahesh Bandewar 	rx_handler_result_t ret = RX_HANDLER_PASS;
7082ad7bf36SMahesh Bandewar 
7095fc9220aSGao Feng 	lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
7102ad7bf36SMahesh Bandewar 	if (!lyr3h)
7112ad7bf36SMahesh Bandewar 		goto out;
7122ad7bf36SMahesh Bandewar 
7132ad7bf36SMahesh Bandewar 	addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
7142ad7bf36SMahesh Bandewar 	if (addr)
715cf554adaSSabrina Dubroca 		ret = ipvlan_rcv_frame(addr, pskb, false);
7162ad7bf36SMahesh Bandewar 
7172ad7bf36SMahesh Bandewar out:
7182ad7bf36SMahesh Bandewar 	return ret;
7192ad7bf36SMahesh Bandewar }
7202ad7bf36SMahesh Bandewar 
ipvlan_handle_mode_l2(struct sk_buff ** pskb,struct ipvl_port * port)7212ad7bf36SMahesh Bandewar static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
7222ad7bf36SMahesh Bandewar 						 struct ipvl_port *port)
7232ad7bf36SMahesh Bandewar {
7242ad7bf36SMahesh Bandewar 	struct sk_buff *skb = *pskb;
7252ad7bf36SMahesh Bandewar 	struct ethhdr *eth = eth_hdr(skb);
7262ad7bf36SMahesh Bandewar 	rx_handler_result_t ret = RX_HANDLER_PASS;
7272ad7bf36SMahesh Bandewar 
7282ad7bf36SMahesh Bandewar 	if (is_multicast_ether_addr(eth->h_dest)) {
729ba35f858SMahesh Bandewar 		if (ipvlan_external_frame(skb, port)) {
730ba35f858SMahesh Bandewar 			struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
731ba35f858SMahesh Bandewar 
732ba35f858SMahesh Bandewar 			/* External frames are queued for device local
733ba35f858SMahesh Bandewar 			 * distribution, but a copy is given to master
734ba35f858SMahesh Bandewar 			 * straight away to avoid sending duplicates later
735ba35f858SMahesh Bandewar 			 * when work-queue processes this frame. This is
736ba35f858SMahesh Bandewar 			 * achieved by returning RX_HANDLER_PASS.
737ba35f858SMahesh Bandewar 			 */
738b93dd49cSMahesh Bandewar 			if (nskb) {
739b93dd49cSMahesh Bandewar 				ipvlan_skb_crossing_ns(nskb, NULL);
740e2525360SMahesh Bandewar 				ipvlan_multicast_enqueue(port, nskb, false);
741ba35f858SMahesh Bandewar 			}
742b93dd49cSMahesh Bandewar 		}
7432ad7bf36SMahesh Bandewar 	} else {
74424e5992aSGao Feng 		/* Perform like l3 mode for non-multicast packet */
74524e5992aSGao Feng 		ret = ipvlan_handle_mode_l3(pskb, port);
7462ad7bf36SMahesh Bandewar 	}
7472ad7bf36SMahesh Bandewar 
7482ad7bf36SMahesh Bandewar 	return ret;
7492ad7bf36SMahesh Bandewar }
7502ad7bf36SMahesh Bandewar 
ipvlan_handle_frame(struct sk_buff ** pskb)7512ad7bf36SMahesh Bandewar rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
7522ad7bf36SMahesh Bandewar {
7532ad7bf36SMahesh Bandewar 	struct sk_buff *skb = *pskb;
7542ad7bf36SMahesh Bandewar 	struct ipvl_port *port = ipvlan_port_get_rcu(skb->dev);
7552ad7bf36SMahesh Bandewar 
7562ad7bf36SMahesh Bandewar 	if (!port)
7572ad7bf36SMahesh Bandewar 		return RX_HANDLER_PASS;
7582ad7bf36SMahesh Bandewar 
7592ad7bf36SMahesh Bandewar 	switch (port->mode) {
7602ad7bf36SMahesh Bandewar 	case IPVLAN_MODE_L2:
7612ad7bf36SMahesh Bandewar 		return ipvlan_handle_mode_l2(pskb, port);
7622ad7bf36SMahesh Bandewar 	case IPVLAN_MODE_L3:
7632ad7bf36SMahesh Bandewar 		return ipvlan_handle_mode_l3(pskb, port);
764c675e06aSDaniel Borkmann #ifdef CONFIG_IPVLAN_L3S
7654fbae7d8SMahesh Bandewar 	case IPVLAN_MODE_L3S:
7664fbae7d8SMahesh Bandewar 		return RX_HANDLER_PASS;
767c675e06aSDaniel Borkmann #endif
7682ad7bf36SMahesh Bandewar 	}
7692ad7bf36SMahesh Bandewar 
7702ad7bf36SMahesh Bandewar 	/* Should not reach here */
771d7a177eaSTom Rix 	WARN_ONCE(true, "%s called for mode = [%x]\n", __func__, port->mode);
7722ad7bf36SMahesh Bandewar 	kfree_skb(skb);
773a534dc52SSabrina Dubroca 	return RX_HANDLER_CONSUMED;
7742ad7bf36SMahesh Bandewar }
775