12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22ad7bf36SMahesh Bandewar /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
32ad7bf36SMahesh Bandewar */
42ad7bf36SMahesh Bandewar
5ed8f499fSIdo Schimmel #include <net/inet_dscp.h>
6cc6c6b7aSGuillaume Nault #include <net/ip.h>
7ed8f499fSIdo Schimmel
82ad7bf36SMahesh Bandewar #include "ipvlan.h"
92ad7bf36SMahesh Bandewar
10207895fdSDaniel Borkmann static u32 ipvlan_jhash_secret __read_mostly;
112ad7bf36SMahesh Bandewar
ipvlan_init_secret(void)122ad7bf36SMahesh Bandewar void ipvlan_init_secret(void)
132ad7bf36SMahesh Bandewar {
142ad7bf36SMahesh Bandewar net_get_random_once(&ipvlan_jhash_secret, sizeof(ipvlan_jhash_secret));
152ad7bf36SMahesh Bandewar }
162ad7bf36SMahesh Bandewar
ipvlan_count_rx(const struct ipvl_dev * ipvlan,unsigned int len,bool success,bool mcast)17235a9d89SSainath Grandhi void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
182ad7bf36SMahesh Bandewar unsigned int len, bool success, bool mcast)
192ad7bf36SMahesh Bandewar {
202ad7bf36SMahesh Bandewar if (likely(success)) {
212ad7bf36SMahesh Bandewar struct ipvl_pcpu_stats *pcptr;
222ad7bf36SMahesh Bandewar
232ad7bf36SMahesh Bandewar pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
242ad7bf36SMahesh Bandewar u64_stats_update_begin(&pcptr->syncp);
255665f48eSEric Dumazet u64_stats_inc(&pcptr->rx_pkts);
265665f48eSEric Dumazet u64_stats_add(&pcptr->rx_bytes, len);
272ad7bf36SMahesh Bandewar if (mcast)
285665f48eSEric Dumazet u64_stats_inc(&pcptr->rx_mcast);
292ad7bf36SMahesh Bandewar u64_stats_update_end(&pcptr->syncp);
302ad7bf36SMahesh Bandewar } else {
312ad7bf36SMahesh Bandewar this_cpu_inc(ipvlan->pcpu_stats->rx_errs);
322ad7bf36SMahesh Bandewar }
332ad7bf36SMahesh Bandewar }
34235a9d89SSainath Grandhi EXPORT_SYMBOL_GPL(ipvlan_count_rx);
352ad7bf36SMahesh Bandewar
3694333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
ipvlan_get_v6_hash(const void * iaddr)372ad7bf36SMahesh Bandewar static u8 ipvlan_get_v6_hash(const void *iaddr)
382ad7bf36SMahesh Bandewar {
392ad7bf36SMahesh Bandewar const struct in6_addr *ip6_addr = iaddr;
402ad7bf36SMahesh Bandewar
412ad7bf36SMahesh Bandewar return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) &
422ad7bf36SMahesh Bandewar IPVLAN_HASH_MASK;
432ad7bf36SMahesh Bandewar }
4494333facSMatteo Croce #else
ipvlan_get_v6_hash(const void * iaddr)4594333facSMatteo Croce static u8 ipvlan_get_v6_hash(const void *iaddr)
4694333facSMatteo Croce {
4794333facSMatteo Croce return 0;
4894333facSMatteo Croce }
4994333facSMatteo Croce #endif
502ad7bf36SMahesh Bandewar
ipvlan_get_v4_hash(const void * iaddr)512ad7bf36SMahesh Bandewar static u8 ipvlan_get_v4_hash(const void *iaddr)
522ad7bf36SMahesh Bandewar {
532ad7bf36SMahesh Bandewar const struct in_addr *ip4_addr = iaddr;
542ad7bf36SMahesh Bandewar
552ad7bf36SMahesh Bandewar return jhash_1word(ip4_addr->s_addr, ipvlan_jhash_secret) &
562ad7bf36SMahesh Bandewar IPVLAN_HASH_MASK;
572ad7bf36SMahesh Bandewar }
582ad7bf36SMahesh Bandewar
addr_equal(bool is_v6,struct ipvl_addr * addr,const void * iaddr)5994333facSMatteo Croce static bool addr_equal(bool is_v6, struct ipvl_addr *addr, const void *iaddr)
6094333facSMatteo Croce {
6194333facSMatteo Croce if (!is_v6 && addr->atype == IPVL_IPV4) {
6294333facSMatteo Croce struct in_addr *i4addr = (struct in_addr *)iaddr;
6394333facSMatteo Croce
6494333facSMatteo Croce return addr->ip4addr.s_addr == i4addr->s_addr;
6594333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
6694333facSMatteo Croce } else if (is_v6 && addr->atype == IPVL_IPV6) {
6794333facSMatteo Croce struct in6_addr *i6addr = (struct in6_addr *)iaddr;
6894333facSMatteo Croce
6994333facSMatteo Croce return ipv6_addr_equal(&addr->ip6addr, i6addr);
7094333facSMatteo Croce #endif
7194333facSMatteo Croce }
7294333facSMatteo Croce
7394333facSMatteo Croce return false;
7494333facSMatteo Croce }
7594333facSMatteo Croce
ipvlan_ht_addr_lookup(const struct ipvl_port * port,const void * iaddr,bool is_v6)76ab5b7013SMahesh Bandewar static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
772ad7bf36SMahesh Bandewar const void *iaddr, bool is_v6)
782ad7bf36SMahesh Bandewar {
792ad7bf36SMahesh Bandewar struct ipvl_addr *addr;
802ad7bf36SMahesh Bandewar u8 hash;
812ad7bf36SMahesh Bandewar
822ad7bf36SMahesh Bandewar hash = is_v6 ? ipvlan_get_v6_hash(iaddr) :
832ad7bf36SMahesh Bandewar ipvlan_get_v4_hash(iaddr);
8494333facSMatteo Croce hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
8594333facSMatteo Croce if (addr_equal(is_v6, addr, iaddr))
862ad7bf36SMahesh Bandewar return addr;
872ad7bf36SMahesh Bandewar return NULL;
882ad7bf36SMahesh Bandewar }
892ad7bf36SMahesh Bandewar
ipvlan_ht_addr_add(struct ipvl_dev * ipvlan,struct ipvl_addr * addr)902ad7bf36SMahesh Bandewar void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)
912ad7bf36SMahesh Bandewar {
922ad7bf36SMahesh Bandewar struct ipvl_port *port = ipvlan->port;
932ad7bf36SMahesh Bandewar u8 hash;
942ad7bf36SMahesh Bandewar
952ad7bf36SMahesh Bandewar hash = (addr->atype == IPVL_IPV6) ?
962ad7bf36SMahesh Bandewar ipvlan_get_v6_hash(&addr->ip6addr) :
972ad7bf36SMahesh Bandewar ipvlan_get_v4_hash(&addr->ip4addr);
9827705f70SJiri Benc if (hlist_unhashed(&addr->hlnode))
992ad7bf36SMahesh Bandewar hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
1002ad7bf36SMahesh Bandewar }
1012ad7bf36SMahesh Bandewar
ipvlan_ht_addr_del(struct ipvl_addr * addr)1026640e673SKonstantin Khlebnikov void ipvlan_ht_addr_del(struct ipvl_addr *addr)
1032ad7bf36SMahesh Bandewar {
10427705f70SJiri Benc hlist_del_init_rcu(&addr->hlnode);
1052ad7bf36SMahesh Bandewar }
1062ad7bf36SMahesh Bandewar
ipvlan_find_addr(const struct ipvl_dev * ipvlan,const void * iaddr,bool is_v6)107e9997c29SJiri Benc struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
108e9997c29SJiri Benc const void *iaddr, bool is_v6)
1092ad7bf36SMahesh Bandewar {
11082308194SPaolo Abeni struct ipvl_addr *addr, *ret = NULL;
1112ad7bf36SMahesh Bandewar
11282308194SPaolo Abeni rcu_read_lock();
11382308194SPaolo Abeni list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) {
11482308194SPaolo Abeni if (addr_equal(is_v6, addr, iaddr)) {
11582308194SPaolo Abeni ret = addr;
11682308194SPaolo Abeni break;
11782308194SPaolo Abeni }
11882308194SPaolo Abeni }
11982308194SPaolo Abeni rcu_read_unlock();
12082308194SPaolo Abeni return ret;
1212ad7bf36SMahesh Bandewar }
1222ad7bf36SMahesh Bandewar
ipvlan_addr_busy(struct ipvl_port * port,void * iaddr,bool is_v6)123e9997c29SJiri Benc bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
124e9997c29SJiri Benc {
125e9997c29SJiri Benc struct ipvl_dev *ipvlan;
12682308194SPaolo Abeni bool ret = false;
1272ad7bf36SMahesh Bandewar
12882308194SPaolo Abeni rcu_read_lock();
12982308194SPaolo Abeni list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
13082308194SPaolo Abeni if (ipvlan_find_addr(ipvlan, iaddr, is_v6)) {
13182308194SPaolo Abeni ret = true;
13282308194SPaolo Abeni break;
133e9997c29SJiri Benc }
13482308194SPaolo Abeni }
13582308194SPaolo Abeni rcu_read_unlock();
13682308194SPaolo Abeni return ret;
1372ad7bf36SMahesh Bandewar }
1382ad7bf36SMahesh Bandewar
ipvlan_get_L3_hdr(struct ipvl_port * port,struct sk_buff * skb,int * type)139c675e06aSDaniel Borkmann void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type)
1402ad7bf36SMahesh Bandewar {
1412ad7bf36SMahesh Bandewar void *lyr3h = NULL;
1422ad7bf36SMahesh Bandewar
1432ad7bf36SMahesh Bandewar switch (skb->protocol) {
1442ad7bf36SMahesh Bandewar case htons(ETH_P_ARP): {
1452ad7bf36SMahesh Bandewar struct arphdr *arph;
1462ad7bf36SMahesh Bandewar
1475fc9220aSGao Feng if (unlikely(!pskb_may_pull(skb, arp_hdr_len(port->dev))))
1482ad7bf36SMahesh Bandewar return NULL;
1492ad7bf36SMahesh Bandewar
1502ad7bf36SMahesh Bandewar arph = arp_hdr(skb);
1512ad7bf36SMahesh Bandewar *type = IPVL_ARP;
1522ad7bf36SMahesh Bandewar lyr3h = arph;
1532ad7bf36SMahesh Bandewar break;
1542ad7bf36SMahesh Bandewar }
1552ad7bf36SMahesh Bandewar case htons(ETH_P_IP): {
1562ad7bf36SMahesh Bandewar u32 pktlen;
1572ad7bf36SMahesh Bandewar struct iphdr *ip4h;
1582ad7bf36SMahesh Bandewar
1592ad7bf36SMahesh Bandewar if (unlikely(!pskb_may_pull(skb, sizeof(*ip4h))))
1602ad7bf36SMahesh Bandewar return NULL;
1612ad7bf36SMahesh Bandewar
1622ad7bf36SMahesh Bandewar ip4h = ip_hdr(skb);
16350e6fb5cSXin Long pktlen = skb_ip_totlen(skb);
1642ad7bf36SMahesh Bandewar if (ip4h->ihl < 5 || ip4h->version != 4)
1652ad7bf36SMahesh Bandewar return NULL;
1662ad7bf36SMahesh Bandewar if (skb->len < pktlen || pktlen < (ip4h->ihl * 4))
1672ad7bf36SMahesh Bandewar return NULL;
1682ad7bf36SMahesh Bandewar
1692ad7bf36SMahesh Bandewar *type = IPVL_IPV4;
1702ad7bf36SMahesh Bandewar lyr3h = ip4h;
1712ad7bf36SMahesh Bandewar break;
1722ad7bf36SMahesh Bandewar }
17394333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
1742ad7bf36SMahesh Bandewar case htons(ETH_P_IPV6): {
1752ad7bf36SMahesh Bandewar struct ipv6hdr *ip6h;
1762ad7bf36SMahesh Bandewar
1772ad7bf36SMahesh Bandewar if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h))))
1782ad7bf36SMahesh Bandewar return NULL;
1792ad7bf36SMahesh Bandewar
1802ad7bf36SMahesh Bandewar ip6h = ipv6_hdr(skb);
1812ad7bf36SMahesh Bandewar if (ip6h->version != 6)
1822ad7bf36SMahesh Bandewar return NULL;
1832ad7bf36SMahesh Bandewar
1842ad7bf36SMahesh Bandewar *type = IPVL_IPV6;
1852ad7bf36SMahesh Bandewar lyr3h = ip6h;
1862ad7bf36SMahesh Bandewar /* Only Neighbour Solicitation pkts need different treatment */
1872ad7bf36SMahesh Bandewar if (ipv6_addr_any(&ip6h->saddr) &&
1882ad7bf36SMahesh Bandewar ip6h->nexthdr == NEXTHDR_ICMP) {
189747a7135SGao Feng struct icmp6hdr *icmph;
190747a7135SGao Feng
191747a7135SGao Feng if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h) + sizeof(*icmph))))
192747a7135SGao Feng return NULL;
193747a7135SGao Feng
194747a7135SGao Feng ip6h = ipv6_hdr(skb);
195747a7135SGao Feng icmph = (struct icmp6hdr *)(ip6h + 1);
196747a7135SGao Feng
197747a7135SGao Feng if (icmph->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
198747a7135SGao Feng /* Need to access the ipv6 address in body */
199747a7135SGao Feng if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h) + sizeof(*icmph)
200747a7135SGao Feng + sizeof(struct in6_addr))))
201747a7135SGao Feng return NULL;
202747a7135SGao Feng
203747a7135SGao Feng ip6h = ipv6_hdr(skb);
204747a7135SGao Feng icmph = (struct icmp6hdr *)(ip6h + 1);
205747a7135SGao Feng }
206747a7135SGao Feng
2072ad7bf36SMahesh Bandewar *type = IPVL_ICMPV6;
208747a7135SGao Feng lyr3h = icmph;
2092ad7bf36SMahesh Bandewar }
2102ad7bf36SMahesh Bandewar break;
2112ad7bf36SMahesh Bandewar }
21294333facSMatteo Croce #endif
2132ad7bf36SMahesh Bandewar default:
2142ad7bf36SMahesh Bandewar return NULL;
2152ad7bf36SMahesh Bandewar }
2162ad7bf36SMahesh Bandewar
2172ad7bf36SMahesh Bandewar return lyr3h;
2182ad7bf36SMahesh Bandewar }
2192ad7bf36SMahesh Bandewar
ipvlan_mac_hash(const unsigned char * addr)2202ad7bf36SMahesh Bandewar unsigned int ipvlan_mac_hash(const unsigned char *addr)
2212ad7bf36SMahesh Bandewar {
2222ad7bf36SMahesh Bandewar u32 hash = jhash_1word(__get_unaligned_cpu32(addr+2),
2232ad7bf36SMahesh Bandewar ipvlan_jhash_secret);
2242ad7bf36SMahesh Bandewar
2252ad7bf36SMahesh Bandewar return hash & IPVLAN_MAC_FILTER_MASK;
2262ad7bf36SMahesh Bandewar }
2272ad7bf36SMahesh Bandewar
ipvlan_process_multicast(struct work_struct * work)228ba35f858SMahesh Bandewar void ipvlan_process_multicast(struct work_struct *work)
2292ad7bf36SMahesh Bandewar {
230ba35f858SMahesh Bandewar struct ipvl_port *port = container_of(work, struct ipvl_port, wq);
231ba35f858SMahesh Bandewar struct ethhdr *ethh;
2322ad7bf36SMahesh Bandewar struct ipvl_dev *ipvlan;
233ba35f858SMahesh Bandewar struct sk_buff *skb, *nskb;
234ba35f858SMahesh Bandewar struct sk_buff_head list;
2352ad7bf36SMahesh Bandewar unsigned int len;
2362ad7bf36SMahesh Bandewar unsigned int mac_hash;
2372ad7bf36SMahesh Bandewar int ret;
238ba35f858SMahesh Bandewar u8 pkt_type;
239e2525360SMahesh Bandewar bool tx_pkt;
2402ad7bf36SMahesh Bandewar
241ba35f858SMahesh Bandewar __skb_queue_head_init(&list);
2422ad7bf36SMahesh Bandewar
243ba35f858SMahesh Bandewar spin_lock_bh(&port->backlog.lock);
244ba35f858SMahesh Bandewar skb_queue_splice_tail_init(&port->backlog, &list);
245ba35f858SMahesh Bandewar spin_unlock_bh(&port->backlog.lock);
246ba35f858SMahesh Bandewar
247ba35f858SMahesh Bandewar while ((skb = __skb_dequeue(&list)) != NULL) {
248b1227d01SEric Dumazet struct net_device *dev = skb->dev;
249b1227d01SEric Dumazet bool consumed = false;
250b1227d01SEric Dumazet
251ba35f858SMahesh Bandewar ethh = eth_hdr(skb);
252e2525360SMahesh Bandewar tx_pkt = IPVL_SKB_CB(skb)->tx_pkt;
253ba35f858SMahesh Bandewar mac_hash = ipvlan_mac_hash(ethh->h_dest);
254ba35f858SMahesh Bandewar
255ba35f858SMahesh Bandewar if (ether_addr_equal(ethh->h_dest, port->dev->broadcast))
256ba35f858SMahesh Bandewar pkt_type = PACKET_BROADCAST;
257ba35f858SMahesh Bandewar else
258ba35f858SMahesh Bandewar pkt_type = PACKET_MULTICAST;
259ba35f858SMahesh Bandewar
2602afa650cSJiri Benc rcu_read_lock();
2612afa650cSJiri Benc list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) {
262e2525360SMahesh Bandewar if (tx_pkt && (ipvlan->dev == skb->dev))
2632ad7bf36SMahesh Bandewar continue;
2642ad7bf36SMahesh Bandewar if (!test_bit(mac_hash, ipvlan->mac_filters))
2652ad7bf36SMahesh Bandewar continue;
266b1227d01SEric Dumazet if (!(ipvlan->dev->flags & IFF_UP))
267b1227d01SEric Dumazet continue;
2682ad7bf36SMahesh Bandewar ret = NET_RX_DROP;
2692ad7bf36SMahesh Bandewar len = skb->len + ETH_HLEN;
2702ad7bf36SMahesh Bandewar nskb = skb_clone(skb, GFP_ATOMIC);
271b1227d01SEric Dumazet local_bh_disable();
272b1227d01SEric Dumazet if (nskb) {
273b1227d01SEric Dumazet consumed = true;
274ba35f858SMahesh Bandewar nskb->pkt_type = pkt_type;
2752ad7bf36SMahesh Bandewar nskb->dev = ipvlan->dev;
276e2525360SMahesh Bandewar if (tx_pkt)
2772ad7bf36SMahesh Bandewar ret = dev_forward_skb(ipvlan->dev, nskb);
2782ad7bf36SMahesh Bandewar else
2792ad7bf36SMahesh Bandewar ret = netif_rx(nskb);
280b1227d01SEric Dumazet }
2812ad7bf36SMahesh Bandewar ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true);
282b1227d01SEric Dumazet local_bh_enable();
2832ad7bf36SMahesh Bandewar }
2842afa650cSJiri Benc rcu_read_unlock();
2852ad7bf36SMahesh Bandewar
286e2525360SMahesh Bandewar if (tx_pkt) {
287ba35f858SMahesh Bandewar /* If the packet originated here, send it out. */
288ba35f858SMahesh Bandewar skb->dev = port->dev;
289ba35f858SMahesh Bandewar skb->pkt_type = pkt_type;
290ba35f858SMahesh Bandewar dev_queue_xmit(skb);
291ba35f858SMahesh Bandewar } else {
292b1227d01SEric Dumazet if (consumed)
293b1227d01SEric Dumazet consume_skb(skb);
294b1227d01SEric Dumazet else
295ba35f858SMahesh Bandewar kfree_skb(skb);
2962ad7bf36SMahesh Bandewar }
297b1227d01SEric Dumazet dev_put(dev);
298afe207d8SEric Dumazet cond_resched();
2992ad7bf36SMahesh Bandewar }
3002ad7bf36SMahesh Bandewar }
3012ad7bf36SMahesh Bandewar
ipvlan_skb_crossing_ns(struct sk_buff * skb,struct net_device * dev)302b93dd49cSMahesh Bandewar static void ipvlan_skb_crossing_ns(struct sk_buff *skb, struct net_device *dev)
303b93dd49cSMahesh Bandewar {
304b93dd49cSMahesh Bandewar bool xnet = true;
305b93dd49cSMahesh Bandewar
306b93dd49cSMahesh Bandewar if (dev)
307b93dd49cSMahesh Bandewar xnet = !net_eq(dev_net(skb->dev), dev_net(dev));
308b93dd49cSMahesh Bandewar
309b93dd49cSMahesh Bandewar skb_scrub_packet(skb, xnet);
310b93dd49cSMahesh Bandewar if (dev)
311b93dd49cSMahesh Bandewar skb->dev = dev;
312b93dd49cSMahesh Bandewar }
313b93dd49cSMahesh Bandewar
ipvlan_rcv_frame(struct ipvl_addr * addr,struct sk_buff ** pskb,bool local)314cf554adaSSabrina Dubroca static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
3152ad7bf36SMahesh Bandewar bool local)
3162ad7bf36SMahesh Bandewar {
3172ad7bf36SMahesh Bandewar struct ipvl_dev *ipvlan = addr->master;
3182ad7bf36SMahesh Bandewar struct net_device *dev = ipvlan->dev;
3192ad7bf36SMahesh Bandewar unsigned int len;
3202ad7bf36SMahesh Bandewar rx_handler_result_t ret = RX_HANDLER_CONSUMED;
3212ad7bf36SMahesh Bandewar bool success = false;
322cf554adaSSabrina Dubroca struct sk_buff *skb = *pskb;
3232ad7bf36SMahesh Bandewar
3242ad7bf36SMahesh Bandewar len = skb->len + ETH_HLEN;
325ab5b7013SMahesh Bandewar /* Only packets exchanged between two local slaves need to have
326ab5b7013SMahesh Bandewar * device-up check as well as skb-share check.
327ab5b7013SMahesh Bandewar */
328ab5b7013SMahesh Bandewar if (local) {
3292ad7bf36SMahesh Bandewar if (unlikely(!(dev->flags & IFF_UP))) {
3302ad7bf36SMahesh Bandewar kfree_skb(skb);
3312ad7bf36SMahesh Bandewar goto out;
3322ad7bf36SMahesh Bandewar }
3332ad7bf36SMahesh Bandewar
3342ad7bf36SMahesh Bandewar skb = skb_share_check(skb, GFP_ATOMIC);
3352ad7bf36SMahesh Bandewar if (!skb)
3362ad7bf36SMahesh Bandewar goto out;
3372ad7bf36SMahesh Bandewar
338cf554adaSSabrina Dubroca *pskb = skb;
339ab5b7013SMahesh Bandewar }
3402ad7bf36SMahesh Bandewar
3412ad7bf36SMahesh Bandewar if (local) {
342ab5b7013SMahesh Bandewar skb->pkt_type = PACKET_HOST;
3432ad7bf36SMahesh Bandewar if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS)
3442ad7bf36SMahesh Bandewar success = true;
3452ad7bf36SMahesh Bandewar } else {
346c0d451c8SMahesh Bandewar skb->dev = dev;
3472ad7bf36SMahesh Bandewar ret = RX_HANDLER_ANOTHER;
3482ad7bf36SMahesh Bandewar success = true;
3492ad7bf36SMahesh Bandewar }
3502ad7bf36SMahesh Bandewar
3512ad7bf36SMahesh Bandewar out:
3522ad7bf36SMahesh Bandewar ipvlan_count_rx(ipvlan, len, success, false);
3532ad7bf36SMahesh Bandewar return ret;
3542ad7bf36SMahesh Bandewar }
3552ad7bf36SMahesh Bandewar
ipvlan_addr_lookup(struct ipvl_port * port,void * lyr3h,int addr_type,bool use_dest)356c675e06aSDaniel Borkmann struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
357c675e06aSDaniel Borkmann int addr_type, bool use_dest)
3582ad7bf36SMahesh Bandewar {
3592ad7bf36SMahesh Bandewar struct ipvl_addr *addr = NULL;
3602ad7bf36SMahesh Bandewar
36194333facSMatteo Croce switch (addr_type) {
36294333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
36394333facSMatteo Croce case IPVL_IPV6: {
3642ad7bf36SMahesh Bandewar struct ipv6hdr *ip6h;
3652ad7bf36SMahesh Bandewar struct in6_addr *i6addr;
3662ad7bf36SMahesh Bandewar
3672ad7bf36SMahesh Bandewar ip6h = (struct ipv6hdr *)lyr3h;
3682ad7bf36SMahesh Bandewar i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
3692ad7bf36SMahesh Bandewar addr = ipvlan_ht_addr_lookup(port, i6addr, true);
37094333facSMatteo Croce break;
37194333facSMatteo Croce }
37294333facSMatteo Croce case IPVL_ICMPV6: {
3732ad7bf36SMahesh Bandewar struct nd_msg *ndmh;
3742ad7bf36SMahesh Bandewar struct in6_addr *i6addr;
3752ad7bf36SMahesh Bandewar
3762ad7bf36SMahesh Bandewar /* Make sure that the NeighborSolicitation ICMPv6 packets
3772ad7bf36SMahesh Bandewar * are handled to avoid DAD issue.
3782ad7bf36SMahesh Bandewar */
3792ad7bf36SMahesh Bandewar ndmh = (struct nd_msg *)lyr3h;
3802ad7bf36SMahesh Bandewar if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
3812ad7bf36SMahesh Bandewar i6addr = &ndmh->target;
3822ad7bf36SMahesh Bandewar addr = ipvlan_ht_addr_lookup(port, i6addr, true);
3832ad7bf36SMahesh Bandewar }
38494333facSMatteo Croce break;
38594333facSMatteo Croce }
38694333facSMatteo Croce #endif
38794333facSMatteo Croce case IPVL_IPV4: {
3882ad7bf36SMahesh Bandewar struct iphdr *ip4h;
3892ad7bf36SMahesh Bandewar __be32 *i4addr;
3902ad7bf36SMahesh Bandewar
3912ad7bf36SMahesh Bandewar ip4h = (struct iphdr *)lyr3h;
3922ad7bf36SMahesh Bandewar i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
3932ad7bf36SMahesh Bandewar addr = ipvlan_ht_addr_lookup(port, i4addr, false);
39494333facSMatteo Croce break;
39594333facSMatteo Croce }
39694333facSMatteo Croce case IPVL_ARP: {
3972ad7bf36SMahesh Bandewar struct arphdr *arph;
3982ad7bf36SMahesh Bandewar unsigned char *arp_ptr;
3992ad7bf36SMahesh Bandewar __be32 dip;
4002ad7bf36SMahesh Bandewar
4012ad7bf36SMahesh Bandewar arph = (struct arphdr *)lyr3h;
4022ad7bf36SMahesh Bandewar arp_ptr = (unsigned char *)(arph + 1);
4032ad7bf36SMahesh Bandewar if (use_dest)
4042ad7bf36SMahesh Bandewar arp_ptr += (2 * port->dev->addr_len) + 4;
4052ad7bf36SMahesh Bandewar else
4062ad7bf36SMahesh Bandewar arp_ptr += port->dev->addr_len;
4072ad7bf36SMahesh Bandewar
4082ad7bf36SMahesh Bandewar memcpy(&dip, arp_ptr, 4);
4092ad7bf36SMahesh Bandewar addr = ipvlan_ht_addr_lookup(port, &dip, false);
41094333facSMatteo Croce break;
41194333facSMatteo Croce }
4122ad7bf36SMahesh Bandewar }
4132ad7bf36SMahesh Bandewar
4142ad7bf36SMahesh Bandewar return addr;
4152ad7bf36SMahesh Bandewar }
4162ad7bf36SMahesh Bandewar
ipvlan_process_v4_outbound(struct sk_buff * skb)41703cddc4dSEric Dumazet static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb)
4182ad7bf36SMahesh Bandewar {
4192ad7bf36SMahesh Bandewar struct net_device *dev = skb->dev;
42057c4bf85SEric W. Biederman struct net *net = dev_net(dev);
4212ad7bf36SMahesh Bandewar int err, ret = NET_XMIT_DROP;
422*4ec48f81SEric Dumazet const struct iphdr *ip4h;
423*4ec48f81SEric Dumazet struct rtable *rt;
4242ad7bf36SMahesh Bandewar struct flowi4 fl4 = {
42563b11e75SBrenden Blanco .flowi4_oif = dev->ifindex,
4262ad7bf36SMahesh Bandewar .flowi4_flags = FLOWI_FLAG_ANYSRC,
427a98a4ebcSGao Feng .flowi4_mark = skb->mark,
4282ad7bf36SMahesh Bandewar };
4292ad7bf36SMahesh Bandewar
430*4ec48f81SEric Dumazet if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
431*4ec48f81SEric Dumazet goto err;
432*4ec48f81SEric Dumazet
433*4ec48f81SEric Dumazet ip4h = ip_hdr(skb);
434*4ec48f81SEric Dumazet fl4.daddr = ip4h->daddr;
435*4ec48f81SEric Dumazet fl4.saddr = ip4h->saddr;
436*4ec48f81SEric Dumazet fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h));
437*4ec48f81SEric Dumazet
43857c4bf85SEric W. Biederman rt = ip_route_output_flow(net, &fl4, NULL);
4392ad7bf36SMahesh Bandewar if (IS_ERR(rt))
4402ad7bf36SMahesh Bandewar goto err;
4412ad7bf36SMahesh Bandewar
4422ad7bf36SMahesh Bandewar if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
4432ad7bf36SMahesh Bandewar ip_rt_put(rt);
4442ad7bf36SMahesh Bandewar goto err;
4452ad7bf36SMahesh Bandewar }
4462ad7bf36SMahesh Bandewar skb_dst_set(skb, &rt->dst);
44790cbed52St.feng
44890cbed52St.feng memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
44990cbed52St.feng
45054213c09SYue Haibing err = ip_local_out(net, NULL, skb);
4512ad7bf36SMahesh Bandewar if (unlikely(net_xmit_eval(err)))
4524553020dSEric Dumazet DEV_STATS_INC(dev, tx_errors);
4532ad7bf36SMahesh Bandewar else
4542ad7bf36SMahesh Bandewar ret = NET_XMIT_SUCCESS;
4552ad7bf36SMahesh Bandewar goto out;
4562ad7bf36SMahesh Bandewar err:
4574553020dSEric Dumazet DEV_STATS_INC(dev, tx_errors);
4582ad7bf36SMahesh Bandewar kfree_skb(skb);
4592ad7bf36SMahesh Bandewar out:
4602ad7bf36SMahesh Bandewar return ret;
4612ad7bf36SMahesh Bandewar }
4622ad7bf36SMahesh Bandewar
46394333facSMatteo Croce #if IS_ENABLED(CONFIG_IPV6)
46403cddc4dSEric Dumazet
46503cddc4dSEric Dumazet static noinline_for_stack int
ipvlan_route_v6_outbound(struct net_device * dev,struct sk_buff * skb)46603cddc4dSEric Dumazet ipvlan_route_v6_outbound(struct net_device *dev, struct sk_buff *skb)
4672ad7bf36SMahesh Bandewar {
4682ad7bf36SMahesh Bandewar const struct ipv6hdr *ip6h = ipv6_hdr(skb);
4692ad7bf36SMahesh Bandewar struct flowi6 fl6 = {
470ca29fd7cSKeefe Liu .flowi6_oif = dev->ifindex,
4712ad7bf36SMahesh Bandewar .daddr = ip6h->daddr,
4722ad7bf36SMahesh Bandewar .saddr = ip6h->saddr,
4732ad7bf36SMahesh Bandewar .flowi6_flags = FLOWI_FLAG_ANYSRC,
4742ad7bf36SMahesh Bandewar .flowlabel = ip6_flowinfo(ip6h),
4752ad7bf36SMahesh Bandewar .flowi6_mark = skb->mark,
4762ad7bf36SMahesh Bandewar .flowi6_proto = ip6h->nexthdr,
4772ad7bf36SMahesh Bandewar };
47803cddc4dSEric Dumazet struct dst_entry *dst;
47903cddc4dSEric Dumazet int err;
4802ad7bf36SMahesh Bandewar
48103cddc4dSEric Dumazet dst = ip6_route_output(dev_net(dev), NULL, &fl6);
48203cddc4dSEric Dumazet err = dst->error;
48303cddc4dSEric Dumazet if (err) {
4842aab9525SMahesh Bandewar dst_release(dst);
48503cddc4dSEric Dumazet return err;
4862aab9525SMahesh Bandewar }
4872ad7bf36SMahesh Bandewar skb_dst_set(skb, dst);
48803cddc4dSEric Dumazet return 0;
48903cddc4dSEric Dumazet }
49003cddc4dSEric Dumazet
ipvlan_process_v6_outbound(struct sk_buff * skb)49103cddc4dSEric Dumazet static int ipvlan_process_v6_outbound(struct sk_buff *skb)
49203cddc4dSEric Dumazet {
49303cddc4dSEric Dumazet struct net_device *dev = skb->dev;
49403cddc4dSEric Dumazet int err, ret = NET_XMIT_DROP;
49503cddc4dSEric Dumazet
496*4ec48f81SEric Dumazet if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) {
497*4ec48f81SEric Dumazet DEV_STATS_INC(dev, tx_errors);
498*4ec48f81SEric Dumazet kfree_skb(skb);
499*4ec48f81SEric Dumazet return ret;
500*4ec48f81SEric Dumazet }
501*4ec48f81SEric Dumazet
50203cddc4dSEric Dumazet err = ipvlan_route_v6_outbound(dev, skb);
50303cddc4dSEric Dumazet if (unlikely(err)) {
50403cddc4dSEric Dumazet DEV_STATS_INC(dev, tx_errors);
50503cddc4dSEric Dumazet kfree_skb(skb);
50603cddc4dSEric Dumazet return err;
50703cddc4dSEric Dumazet }
50890cbed52St.feng
50990cbed52St.feng memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
51090cbed52St.feng
51154213c09SYue Haibing err = ip6_local_out(dev_net(dev), NULL, skb);
5122ad7bf36SMahesh Bandewar if (unlikely(net_xmit_eval(err)))
5134553020dSEric Dumazet DEV_STATS_INC(dev, tx_errors);
5142ad7bf36SMahesh Bandewar else
5152ad7bf36SMahesh Bandewar ret = NET_XMIT_SUCCESS;
5162ad7bf36SMahesh Bandewar return ret;
5172ad7bf36SMahesh Bandewar }
51894333facSMatteo Croce #else
ipvlan_process_v6_outbound(struct sk_buff * skb)51994333facSMatteo Croce static int ipvlan_process_v6_outbound(struct sk_buff *skb)
52094333facSMatteo Croce {
52194333facSMatteo Croce return NET_XMIT_DROP;
52294333facSMatteo Croce }
52394333facSMatteo Croce #endif
5242ad7bf36SMahesh Bandewar
ipvlan_process_outbound(struct sk_buff * skb)525b93dd49cSMahesh Bandewar static int ipvlan_process_outbound(struct sk_buff *skb)
5262ad7bf36SMahesh Bandewar {
5272ad7bf36SMahesh Bandewar int ret = NET_XMIT_DROP;
5282ad7bf36SMahesh Bandewar
5292ad7bf36SMahesh Bandewar /* The ipvlan is a pseudo-L2 device, so the packets that we receive
5302ad7bf36SMahesh Bandewar * will have L2; which need to discarded and processed further
5312ad7bf36SMahesh Bandewar * in the net-ns of the main-device.
5322ad7bf36SMahesh Bandewar */
5332ad7bf36SMahesh Bandewar if (skb_mac_header_was_set(skb)) {
534ad819276SMahesh Bandewar /* In this mode we dont care about
535ad819276SMahesh Bandewar * multicast and broadcast traffic */
53681225b2eSLu Wei struct ethhdr *ethh = eth_hdr(skb);
53781225b2eSLu Wei
538ad819276SMahesh Bandewar if (is_multicast_ether_addr(ethh->h_dest)) {
539ad819276SMahesh Bandewar pr_debug_ratelimited(
540ad819276SMahesh Bandewar "Dropped {multi|broad}cast of type=[%x]\n",
541ad819276SMahesh Bandewar ntohs(skb->protocol));
542ad819276SMahesh Bandewar kfree_skb(skb);
543ad819276SMahesh Bandewar goto out;
544ad819276SMahesh Bandewar }
545ad819276SMahesh Bandewar
5462ad7bf36SMahesh Bandewar skb_pull(skb, sizeof(*ethh));
5472ad7bf36SMahesh Bandewar skb->mac_header = (typeof(skb->mac_header))~0U;
5482ad7bf36SMahesh Bandewar skb_reset_network_header(skb);
5492ad7bf36SMahesh Bandewar }
5502ad7bf36SMahesh Bandewar
5512ad7bf36SMahesh Bandewar if (skb->protocol == htons(ETH_P_IPV6))
552b93dd49cSMahesh Bandewar ret = ipvlan_process_v6_outbound(skb);
5532ad7bf36SMahesh Bandewar else if (skb->protocol == htons(ETH_P_IP))
554b93dd49cSMahesh Bandewar ret = ipvlan_process_v4_outbound(skb);
5552ad7bf36SMahesh Bandewar else {
5562ad7bf36SMahesh Bandewar pr_warn_ratelimited("Dropped outbound packet type=%x\n",
5572ad7bf36SMahesh Bandewar ntohs(skb->protocol));
5582ad7bf36SMahesh Bandewar kfree_skb(skb);
5592ad7bf36SMahesh Bandewar }
5602ad7bf36SMahesh Bandewar out:
5612ad7bf36SMahesh Bandewar return ret;
5622ad7bf36SMahesh Bandewar }
5632ad7bf36SMahesh Bandewar
ipvlan_multicast_enqueue(struct ipvl_port * port,struct sk_buff * skb,bool tx_pkt)564ba35f858SMahesh Bandewar static void ipvlan_multicast_enqueue(struct ipvl_port *port,
565e2525360SMahesh Bandewar struct sk_buff *skb, bool tx_pkt)
566ba35f858SMahesh Bandewar {
567ba35f858SMahesh Bandewar if (skb->protocol == htons(ETH_P_PAUSE)) {
568ba35f858SMahesh Bandewar kfree_skb(skb);
569ba35f858SMahesh Bandewar return;
570ba35f858SMahesh Bandewar }
571ba35f858SMahesh Bandewar
572e2525360SMahesh Bandewar /* Record that the deferred packet is from TX or RX path. By
573e2525360SMahesh Bandewar * looking at mac-addresses on packet will lead to erronus decisions.
574e2525360SMahesh Bandewar * (This would be true for a loopback-mode on master device or a
575e2525360SMahesh Bandewar * hair-pin mode of the switch.)
576e2525360SMahesh Bandewar */
577e2525360SMahesh Bandewar IPVL_SKB_CB(skb)->tx_pkt = tx_pkt;
578e2525360SMahesh Bandewar
579ba35f858SMahesh Bandewar spin_lock(&port->backlog.lock);
580ba35f858SMahesh Bandewar if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) {
581b1227d01SEric Dumazet dev_hold(skb->dev);
582ba35f858SMahesh Bandewar __skb_queue_tail(&port->backlog, skb);
583ba35f858SMahesh Bandewar spin_unlock(&port->backlog.lock);
584ba35f858SMahesh Bandewar schedule_work(&port->wq);
585ba35f858SMahesh Bandewar } else {
586ba35f858SMahesh Bandewar spin_unlock(&port->backlog.lock);
587625788b5SEric Dumazet dev_core_stats_rx_dropped_inc(skb->dev);
588ba35f858SMahesh Bandewar kfree_skb(skb);
589ba35f858SMahesh Bandewar }
590ba35f858SMahesh Bandewar }
591ba35f858SMahesh Bandewar
ipvlan_xmit_mode_l3(struct sk_buff * skb,struct net_device * dev)5922ad7bf36SMahesh Bandewar static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
5932ad7bf36SMahesh Bandewar {
5942ad7bf36SMahesh Bandewar const struct ipvl_dev *ipvlan = netdev_priv(dev);
5952ad7bf36SMahesh Bandewar void *lyr3h;
5962ad7bf36SMahesh Bandewar struct ipvl_addr *addr;
5972ad7bf36SMahesh Bandewar int addr_type;
5982ad7bf36SMahesh Bandewar
5995fc9220aSGao Feng lyr3h = ipvlan_get_L3_hdr(ipvlan->port, skb, &addr_type);
6002ad7bf36SMahesh Bandewar if (!lyr3h)
6012ad7bf36SMahesh Bandewar goto out;
6022ad7bf36SMahesh Bandewar
603fe89aa6bSMahesh Bandewar if (!ipvlan_is_vepa(ipvlan->port)) {
6042ad7bf36SMahesh Bandewar addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
605a190d04dSMahesh Bandewar if (addr) {
606a190d04dSMahesh Bandewar if (ipvlan_is_private(ipvlan->port)) {
607a190d04dSMahesh Bandewar consume_skb(skb);
608a190d04dSMahesh Bandewar return NET_XMIT_DROP;
609a190d04dSMahesh Bandewar }
6108a9922e7SCambda Zhu ipvlan_rcv_frame(addr, &skb, true);
6118a9922e7SCambda Zhu return NET_XMIT_SUCCESS;
612a190d04dSMahesh Bandewar }
613fe89aa6bSMahesh Bandewar }
6142ad7bf36SMahesh Bandewar out:
615b93dd49cSMahesh Bandewar ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev);
616b93dd49cSMahesh Bandewar return ipvlan_process_outbound(skb);
6172ad7bf36SMahesh Bandewar }
6182ad7bf36SMahesh Bandewar
ipvlan_xmit_mode_l2(struct sk_buff * skb,struct net_device * dev)6192ad7bf36SMahesh Bandewar static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
6202ad7bf36SMahesh Bandewar {
6212ad7bf36SMahesh Bandewar const struct ipvl_dev *ipvlan = netdev_priv(dev);
62281225b2eSLu Wei struct ethhdr *eth = skb_eth_hdr(skb);
6232ad7bf36SMahesh Bandewar struct ipvl_addr *addr;
6242ad7bf36SMahesh Bandewar void *lyr3h;
6252ad7bf36SMahesh Bandewar int addr_type;
6262ad7bf36SMahesh Bandewar
627fe89aa6bSMahesh Bandewar if (!ipvlan_is_vepa(ipvlan->port) &&
628fe89aa6bSMahesh Bandewar ether_addr_equal(eth->h_dest, eth->h_source)) {
6295fc9220aSGao Feng lyr3h = ipvlan_get_L3_hdr(ipvlan->port, skb, &addr_type);
6302ad7bf36SMahesh Bandewar if (lyr3h) {
6312ad7bf36SMahesh Bandewar addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
632a190d04dSMahesh Bandewar if (addr) {
633a190d04dSMahesh Bandewar if (ipvlan_is_private(ipvlan->port)) {
634a190d04dSMahesh Bandewar consume_skb(skb);
635a190d04dSMahesh Bandewar return NET_XMIT_DROP;
636a190d04dSMahesh Bandewar }
6378a9922e7SCambda Zhu ipvlan_rcv_frame(addr, &skb, true);
6388a9922e7SCambda Zhu return NET_XMIT_SUCCESS;
6392ad7bf36SMahesh Bandewar }
640a190d04dSMahesh Bandewar }
6412ad7bf36SMahesh Bandewar skb = skb_share_check(skb, GFP_ATOMIC);
6422ad7bf36SMahesh Bandewar if (!skb)
6432ad7bf36SMahesh Bandewar return NET_XMIT_DROP;
6442ad7bf36SMahesh Bandewar
6452ad7bf36SMahesh Bandewar /* Packet definitely does not belong to any of the
6462ad7bf36SMahesh Bandewar * virtual devices, but the dest is local. So forward
6472ad7bf36SMahesh Bandewar * the skb for the main-dev. At the RX side we just return
6482ad7bf36SMahesh Bandewar * RX_PASS for it to be processed further on the stack.
6492ad7bf36SMahesh Bandewar */
6508a9922e7SCambda Zhu dev_forward_skb(ipvlan->phy_dev, skb);
6518a9922e7SCambda Zhu return NET_XMIT_SUCCESS;
6522ad7bf36SMahesh Bandewar
6532ad7bf36SMahesh Bandewar } else if (is_multicast_ether_addr(eth->h_dest)) {
65481225b2eSLu Wei skb_reset_mac_header(skb);
655b93dd49cSMahesh Bandewar ipvlan_skb_crossing_ns(skb, NULL);
656e2525360SMahesh Bandewar ipvlan_multicast_enqueue(ipvlan->port, skb, true);
657ba35f858SMahesh Bandewar return NET_XMIT_SUCCESS;
6582ad7bf36SMahesh Bandewar }
6592ad7bf36SMahesh Bandewar
660c0d451c8SMahesh Bandewar skb->dev = ipvlan->phy_dev;
6612ad7bf36SMahesh Bandewar return dev_queue_xmit(skb);
6622ad7bf36SMahesh Bandewar }
6632ad7bf36SMahesh Bandewar
ipvlan_queue_xmit(struct sk_buff * skb,struct net_device * dev)6642ad7bf36SMahesh Bandewar int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
6652ad7bf36SMahesh Bandewar {
6662ad7bf36SMahesh Bandewar struct ipvl_dev *ipvlan = netdev_priv(dev);
6670fba37a3SWANG Cong struct ipvl_port *port = ipvlan_port_get_rcu_bh(ipvlan->phy_dev);
6682ad7bf36SMahesh Bandewar
6692ad7bf36SMahesh Bandewar if (!port)
6702ad7bf36SMahesh Bandewar goto out;
6712ad7bf36SMahesh Bandewar
6722ad7bf36SMahesh Bandewar if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
6732ad7bf36SMahesh Bandewar goto out;
6742ad7bf36SMahesh Bandewar
6752ad7bf36SMahesh Bandewar switch(port->mode) {
6762ad7bf36SMahesh Bandewar case IPVLAN_MODE_L2:
6772ad7bf36SMahesh Bandewar return ipvlan_xmit_mode_l2(skb, dev);
6782ad7bf36SMahesh Bandewar case IPVLAN_MODE_L3:
679c675e06aSDaniel Borkmann #ifdef CONFIG_IPVLAN_L3S
6804fbae7d8SMahesh Bandewar case IPVLAN_MODE_L3S:
681c675e06aSDaniel Borkmann #endif
6822ad7bf36SMahesh Bandewar return ipvlan_xmit_mode_l3(skb, dev);
6832ad7bf36SMahesh Bandewar }
6842ad7bf36SMahesh Bandewar
6852ad7bf36SMahesh Bandewar /* Should not reach here */
686d7a177eaSTom Rix WARN_ONCE(true, "%s called for mode = [%x]\n", __func__, port->mode);
6872ad7bf36SMahesh Bandewar out:
6882ad7bf36SMahesh Bandewar kfree_skb(skb);
6892ad7bf36SMahesh Bandewar return NET_XMIT_DROP;
6902ad7bf36SMahesh Bandewar }
6912ad7bf36SMahesh Bandewar
ipvlan_external_frame(struct sk_buff * skb,struct ipvl_port * port)6922ad7bf36SMahesh Bandewar static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port)
6932ad7bf36SMahesh Bandewar {
6942ad7bf36SMahesh Bandewar struct ethhdr *eth = eth_hdr(skb);
6952ad7bf36SMahesh Bandewar struct ipvl_addr *addr;
6962ad7bf36SMahesh Bandewar void *lyr3h;
6972ad7bf36SMahesh Bandewar int addr_type;
6982ad7bf36SMahesh Bandewar
6992ad7bf36SMahesh Bandewar if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) {
7005fc9220aSGao Feng lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
7012ad7bf36SMahesh Bandewar if (!lyr3h)
7022ad7bf36SMahesh Bandewar return true;
7032ad7bf36SMahesh Bandewar
7042ad7bf36SMahesh Bandewar addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false);
7052ad7bf36SMahesh Bandewar if (addr)
7062ad7bf36SMahesh Bandewar return false;
7072ad7bf36SMahesh Bandewar }
7082ad7bf36SMahesh Bandewar
7092ad7bf36SMahesh Bandewar return true;
7102ad7bf36SMahesh Bandewar }
7112ad7bf36SMahesh Bandewar
ipvlan_handle_mode_l3(struct sk_buff ** pskb,struct ipvl_port * port)7122ad7bf36SMahesh Bandewar static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
7132ad7bf36SMahesh Bandewar struct ipvl_port *port)
7142ad7bf36SMahesh Bandewar {
7152ad7bf36SMahesh Bandewar void *lyr3h;
7162ad7bf36SMahesh Bandewar int addr_type;
7172ad7bf36SMahesh Bandewar struct ipvl_addr *addr;
7182ad7bf36SMahesh Bandewar struct sk_buff *skb = *pskb;
7192ad7bf36SMahesh Bandewar rx_handler_result_t ret = RX_HANDLER_PASS;
7202ad7bf36SMahesh Bandewar
7215fc9220aSGao Feng lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
7222ad7bf36SMahesh Bandewar if (!lyr3h)
7232ad7bf36SMahesh Bandewar goto out;
7242ad7bf36SMahesh Bandewar
7252ad7bf36SMahesh Bandewar addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
7262ad7bf36SMahesh Bandewar if (addr)
727cf554adaSSabrina Dubroca ret = ipvlan_rcv_frame(addr, pskb, false);
7282ad7bf36SMahesh Bandewar
7292ad7bf36SMahesh Bandewar out:
7302ad7bf36SMahesh Bandewar return ret;
7312ad7bf36SMahesh Bandewar }
7322ad7bf36SMahesh Bandewar
ipvlan_handle_mode_l2(struct sk_buff ** pskb,struct ipvl_port * port)7332ad7bf36SMahesh Bandewar static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
7342ad7bf36SMahesh Bandewar struct ipvl_port *port)
7352ad7bf36SMahesh Bandewar {
7362ad7bf36SMahesh Bandewar struct sk_buff *skb = *pskb;
7372ad7bf36SMahesh Bandewar struct ethhdr *eth = eth_hdr(skb);
7382ad7bf36SMahesh Bandewar rx_handler_result_t ret = RX_HANDLER_PASS;
7392ad7bf36SMahesh Bandewar
7402ad7bf36SMahesh Bandewar if (is_multicast_ether_addr(eth->h_dest)) {
741ba35f858SMahesh Bandewar if (ipvlan_external_frame(skb, port)) {
742ba35f858SMahesh Bandewar struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
743ba35f858SMahesh Bandewar
744ba35f858SMahesh Bandewar /* External frames are queued for device local
745ba35f858SMahesh Bandewar * distribution, but a copy is given to master
746ba35f858SMahesh Bandewar * straight away to avoid sending duplicates later
747ba35f858SMahesh Bandewar * when work-queue processes this frame. This is
748ba35f858SMahesh Bandewar * achieved by returning RX_HANDLER_PASS.
749ba35f858SMahesh Bandewar */
750b93dd49cSMahesh Bandewar if (nskb) {
751b93dd49cSMahesh Bandewar ipvlan_skb_crossing_ns(nskb, NULL);
752e2525360SMahesh Bandewar ipvlan_multicast_enqueue(port, nskb, false);
753ba35f858SMahesh Bandewar }
754b93dd49cSMahesh Bandewar }
7552ad7bf36SMahesh Bandewar } else {
75624e5992aSGao Feng /* Perform like l3 mode for non-multicast packet */
75724e5992aSGao Feng ret = ipvlan_handle_mode_l3(pskb, port);
7582ad7bf36SMahesh Bandewar }
7592ad7bf36SMahesh Bandewar
7602ad7bf36SMahesh Bandewar return ret;
7612ad7bf36SMahesh Bandewar }
7622ad7bf36SMahesh Bandewar
ipvlan_handle_frame(struct sk_buff ** pskb)7632ad7bf36SMahesh Bandewar rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
7642ad7bf36SMahesh Bandewar {
7652ad7bf36SMahesh Bandewar struct sk_buff *skb = *pskb;
7662ad7bf36SMahesh Bandewar struct ipvl_port *port = ipvlan_port_get_rcu(skb->dev);
7672ad7bf36SMahesh Bandewar
7682ad7bf36SMahesh Bandewar if (!port)
7692ad7bf36SMahesh Bandewar return RX_HANDLER_PASS;
7702ad7bf36SMahesh Bandewar
7712ad7bf36SMahesh Bandewar switch (port->mode) {
7722ad7bf36SMahesh Bandewar case IPVLAN_MODE_L2:
7732ad7bf36SMahesh Bandewar return ipvlan_handle_mode_l2(pskb, port);
7742ad7bf36SMahesh Bandewar case IPVLAN_MODE_L3:
7752ad7bf36SMahesh Bandewar return ipvlan_handle_mode_l3(pskb, port);
776c675e06aSDaniel Borkmann #ifdef CONFIG_IPVLAN_L3S
7774fbae7d8SMahesh Bandewar case IPVLAN_MODE_L3S:
7784fbae7d8SMahesh Bandewar return RX_HANDLER_PASS;
779c675e06aSDaniel Borkmann #endif
7802ad7bf36SMahesh Bandewar }
7812ad7bf36SMahesh Bandewar
7822ad7bf36SMahesh Bandewar /* Should not reach here */
783d7a177eaSTom Rix WARN_ONCE(true, "%s called for mode = [%x]\n", __func__, port->mode);
7842ad7bf36SMahesh Bandewar kfree_skb(skb);
785a534dc52SSabrina Dubroca return RX_HANDLER_CONSUMED;
7862ad7bf36SMahesh Bandewar }
787