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