@@ -116,25 +116,34 @@ bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
return false;
}
-static void *ipvlan_get_L3_hdr(struct sk_buff *skb, int *type)
+static struct ipvl_addr *ipvlan_get_slave_addr(struct sk_buff *skb,
+ struct ipvl_port *port,
+ bool use_dest)
{
- void *lyr3h = NULL;
+ struct ipvl_addr *addr = NULL;
switch (skb->protocol) {
case htons(ETH_P_ARP): {
- struct arphdr *arph;
+ u8 *arp_ptr;
+ __be32 dip;
- if (unlikely(!pskb_may_pull(skb, sizeof(*arph))))
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct arphdr))))
return NULL;
- arph = arp_hdr(skb);
- *type = IPVL_ARP;
- lyr3h = arph;
+ arp_ptr = (u8 *)(arp_hdr(skb) + 1);
+ if (use_dest)
+ arp_ptr += (2 * port->dev->addr_len) + 4;
+ else
+ arp_ptr += port->dev->addr_len;
+
+ memcpy(&dip, arp_ptr, 4);
+ addr = ipvlan_ht_addr_lookup(port, &dip, false);
break;
}
case htons(ETH_P_IP): {
u32 pktlen;
struct iphdr *ip4h;
+ __be32 *i4addr;
if (unlikely(!pskb_may_pull(skb, sizeof(*ip4h))))
return NULL;
@@ -146,12 +155,14 @@ static void *ipvlan_get_L3_hdr(struct sk_buff *skb, int *type)
if (skb->len < pktlen || pktlen < (ip4h->ihl * 4))
return NULL;
- *type = IPVL_IPV4;
- lyr3h = ip4h;
+ i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
+ addr = ipvlan_ht_addr_lookup(port, i4addr, false);
break;
}
case htons(ETH_P_IPV6): {
struct ipv6hdr *ip6h;
+ struct nd_msg *ndmh;
+ struct in6_addr *i6addr;
if (unlikely(!pskb_may_pull(skb, sizeof(*ip6h))))
return NULL;
@@ -160,21 +171,28 @@ static void *ipvlan_get_L3_hdr(struct sk_buff *skb, int *type)
if (ip6h->version != 6)
return NULL;
- *type = IPVL_IPV6;
- lyr3h = ip6h;
- /* Only Neighbour Solicitation pkts need different treatment */
+ ndmh = (struct nd_msg *)(ip6h + 1);
if (ipv6_addr_any(&ip6h->saddr) &&
- ip6h->nexthdr == NEXTHDR_ICMP) {
- *type = IPVL_ICMPV6;
- lyr3h = ip6h + 1;
- }
+ ip6h->nexthdr == NEXTHDR_ICMP &&
+ ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
+ i6addr = &ndmh->target;
+ else
+ i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
+
+ addr = ipvlan_ht_addr_lookup(port, i6addr, true);
break;
}
default:
return NULL;
}
- return lyr3h;
+ return addr;
+}
+
+static inline struct ipvl_addr *ipvlan_get_slave_addr_dst(struct sk_buff *skb,
+ struct ipvl_port *port)
+{
+ return ipvlan_get_slave_addr(skb, port, true);
}
unsigned int ipvlan_mac_hash(const unsigned char *addr)
@@ -312,57 +330,6 @@ static int ipvlan_rcv_int_frame(struct ipvl_addr *addr, struct sk_buff **pskb)
return RX_HANDLER_CONSUMED;
}
-static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
- void *lyr3h, int addr_type,
- bool use_dest)
-{
- struct ipvl_addr *addr = NULL;
-
- if (addr_type == IPVL_IPV6) {
- struct ipv6hdr *ip6h;
- struct in6_addr *i6addr;
-
- ip6h = (struct ipv6hdr *)lyr3h;
- i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
- addr = ipvlan_ht_addr_lookup(port, i6addr, true);
- } else if (addr_type == IPVL_ICMPV6) {
- struct nd_msg *ndmh;
- struct in6_addr *i6addr;
-
- /* Make sure that the NeighborSolicitation ICMPv6 packets
- * are handled to avoid DAD issue.
- */
- ndmh = (struct nd_msg *)lyr3h;
- if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
- i6addr = &ndmh->target;
- addr = ipvlan_ht_addr_lookup(port, i6addr, true);
- }
- } else if (addr_type == IPVL_IPV4) {
- struct iphdr *ip4h;
- __be32 *i4addr;
-
- ip4h = (struct iphdr *)lyr3h;
- i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
- addr = ipvlan_ht_addr_lookup(port, i4addr, false);
- } else if (addr_type == IPVL_ARP) {
- struct arphdr *arph;
- unsigned char *arp_ptr;
- __be32 dip;
-
- arph = (struct arphdr *)lyr3h;
- arp_ptr = (unsigned char *)(arph + 1);
- if (use_dest)
- arp_ptr += (2 * port->dev->addr_len) + 4;
- else
- arp_ptr += port->dev->addr_len;
-
- memcpy(&dip, arp_ptr, 4);
- addr = ipvlan_ht_addr_lookup(port, &dip, false);
- }
-
- return addr;
-}
-
static int ipvlan_process_v4_outbound(struct sk_buff *skb)
{
const struct iphdr *ip4h = ip_hdr(skb);
@@ -505,19 +472,12 @@ static void ipvlan_multicast_enqueue(struct ipvl_port *port,
static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
{
const struct ipvl_dev *ipvlan = netdev_priv(dev);
- void *lyr3h;
struct ipvl_addr *addr;
- int addr_type;
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (!lyr3h)
- goto out;
-
- addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
+ addr = ipvlan_get_slave_addr_dst(skb, ipvlan->port);
if (addr)
return ipvlan_rcv_int_frame(addr, &skb);
-out:
ipvlan_skb_crossing_ns(skb, ipvlan->phy_dev);
return ipvlan_process_outbound(skb);
}
@@ -527,17 +487,12 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
const struct ipvl_dev *ipvlan = netdev_priv(dev);
struct ethhdr *eth = eth_hdr(skb);
struct ipvl_addr *addr;
- void *lyr3h;
- int addr_type;
if (ether_addr_equal(eth->h_dest, eth->h_source)) {
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (lyr3h) {
- addr = ipvlan_addr_lookup(ipvlan->port, lyr3h,
- addr_type, true);
- if (addr)
- return ipvlan_rcv_int_frame(addr, &skb);
- }
+ addr = ipvlan_get_slave_addr_dst(skb, ipvlan->port);
+ if (addr)
+ return ipvlan_rcv_int_frame(addr, &skb);
+
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return NET_XMIT_DROP;
@@ -586,24 +541,10 @@ int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
return NET_XMIT_DROP;
}
-static bool ipvlan_external_frame(struct sk_buff *skb, struct ipvl_port *port)
+static inline bool ipvlan_external_frame(struct sk_buff *skb,
+ struct ipvl_port *port)
{
- struct ethhdr *eth = eth_hdr(skb);
- struct ipvl_addr *addr;
- void *lyr3h;
- int addr_type;
-
- if (ether_addr_equal(eth->h_source, skb->dev->dev_addr)) {
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (!lyr3h)
- return true;
-
- addr = ipvlan_addr_lookup(port, lyr3h, addr_type, false);
- if (addr)
- return false;
- }
-
- return true;
+ return !ipvlan_get_slave_addr(skb, port, false);
}
static int ipvlan_rcv_ext_frame(struct ipvl_addr *addr, struct sk_buff *skb)
@@ -621,22 +562,14 @@ static int ipvlan_rcv_ext_frame(struct ipvl_addr *addr, struct sk_buff *skb)
static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
struct ipvl_port *port)
{
- void *lyr3h;
- int addr_type;
struct ipvl_addr *addr;
struct sk_buff *skb = *pskb;
- rx_handler_result_t ret = RX_HANDLER_PASS;
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (!lyr3h)
- goto out;
-
- addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
+ addr = ipvlan_get_slave_addr_dst(skb, port);
if (addr)
- ret = ipvlan_rcv_ext_frame(addr, skb);
+ return ipvlan_rcv_ext_frame(addr, skb);
-out:
- return ret;
+ return RX_HANDLER_PASS;
}
static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
@@ -644,9 +577,6 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
{
struct sk_buff *skb = *pskb;
struct ethhdr *eth = eth_hdr(skb);
- rx_handler_result_t ret = RX_HANDLER_PASS;
- void *lyr3h;
- int addr_type;
if (is_multicast_ether_addr(eth->h_dest)) {
if (ipvlan_external_frame(skb, port)) {
@@ -666,16 +596,12 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
} else {
struct ipvl_addr *addr;
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (!lyr3h)
- return ret;
-
- addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
+ addr = ipvlan_get_slave_addr_dst(skb, port);
if (addr)
- ret = ipvlan_rcv_ext_frame(addr, skb);
+ return ipvlan_rcv_ext_frame(addr, skb);
}
- return ret;
+ return RX_HANDLER_PASS;
}
rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
@@ -705,25 +631,16 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
struct net_device *dev)
{
- struct ipvl_addr *addr = NULL;
struct ipvl_port *port;
- void *lyr3h;
- int addr_type;
if (!dev || !netif_is_ipvlan_port(dev))
- goto out;
+ return NULL;
port = ipvlan_port_get_rcu(dev);
if (!port || port->mode != IPVLAN_MODE_L3S)
- goto out;
-
- lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
- if (!lyr3h)
- goto out;
+ return NULL;
- addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
-out:
- return addr;
+ return ipvlan_get_slave_addr_dst(skb, port);
}
struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,