From c3aaa06d5a63609641b7ad62ee0956f3de86c1cd Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 20 Feb 2016 19:31:32 -0800 Subject: [PATCH 1/3] ipvlan: scrub skb before routing in L3 mode. Scrub skb before hitting the iptable hooks to ensure packets hit these hooks. Set the xnet param only when the packet is crossing the ns boundry so if the IPvlan slave and master belong to the same ns, the param will be set to false. Signed-off-by: Mahesh Bandewar CC: Cong Wang Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 8c48bb2a94ea..4e60c6bbdb6e 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -342,7 +342,7 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, return addr; } -static int ipvlan_process_v4_outbound(struct sk_buff *skb) +static int ipvlan_process_v4_outbound(struct sk_buff *skb, bool xnet) { const struct iphdr *ip4h = ip_hdr(skb); struct net_device *dev = skb->dev; @@ -365,7 +365,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb) ip_rt_put(rt); goto err; } - skb_dst_drop(skb); + skb_scrub_packet(skb, xnet); skb_dst_set(skb, &rt->dst); err = ip_local_out(net, skb->sk, skb); if (unlikely(net_xmit_eval(err))) @@ -380,7 +380,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb) return ret; } -static int ipvlan_process_v6_outbound(struct sk_buff *skb) +static int ipvlan_process_v6_outbound(struct sk_buff *skb, bool xnet) { const struct ipv6hdr *ip6h = ipv6_hdr(skb); struct net_device *dev = skb->dev; @@ -403,7 +403,7 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) dst_release(dst); goto err; } - skb_dst_drop(skb); + skb_scrub_packet(skb, xnet); skb_dst_set(skb, dst); err = ip6_local_out(net, skb->sk, skb); if (unlikely(net_xmit_eval(err))) @@ -418,8 +418,7 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb) return ret; } -static int ipvlan_process_outbound(struct sk_buff *skb, - const struct ipvl_dev *ipvlan) +static int ipvlan_process_outbound(struct sk_buff *skb, bool xnet) { struct ethhdr *ethh = eth_hdr(skb); int ret = NET_XMIT_DROP; @@ -443,9 +442,9 @@ static int ipvlan_process_outbound(struct sk_buff *skb, } if (skb->protocol == htons(ETH_P_IPV6)) - ret = ipvlan_process_v6_outbound(skb); + ret = ipvlan_process_v6_outbound(skb, xnet); else if (skb->protocol == htons(ETH_P_IP)) - ret = ipvlan_process_v4_outbound(skb); + ret = ipvlan_process_v4_outbound(skb, xnet); else { pr_warn_ratelimited("Dropped outbound packet type=%x\n", ntohs(skb->protocol)); @@ -481,6 +480,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) void *lyr3h; struct ipvl_addr *addr; int addr_type; + bool xnet; lyr3h = ipvlan_get_L3_hdr(skb, &addr_type); if (!lyr3h) @@ -491,8 +491,9 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) return ipvlan_rcv_frame(addr, &skb, true); out: + xnet = !net_eq(dev_net(skb->dev), dev_net(ipvlan->phy_dev)); skb->dev = ipvlan->phy_dev; - return ipvlan_process_outbound(skb, ipvlan); + return ipvlan_process_outbound(skb, xnet); } static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) From e93fbc5a15ff25d4f9fd92a13c33cd37d99a2340 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 20 Feb 2016 19:31:36 -0800 Subject: [PATCH 2/3] ipvlan: mode is u16 The mode argument was erronusly defined as u32 but it has always been u16. Also use ipvlan_set_mode() helper to set the mode instead of assigning directly. This should avoid future erronus assignments / updates. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan.h | 1 - drivers/net/ipvlan/ipvlan_main.c | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 9542b7bac61a..817cab1a7959 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -115,7 +115,6 @@ static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d) } void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev); -void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval); void ipvlan_init_secret(void); unsigned int ipvlan_mac_hash(const unsigned char *addr); rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 7a3b41468a55..5bcb852c5500 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -14,7 +14,7 @@ void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj; } -void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval) +static void ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) { struct ipvl_dev *ipvlan; @@ -442,6 +442,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, struct ipvl_port *port; struct net_device *phy_dev; int err; + u16 mode = IPVLAN_MODE_L3; if (!tb[IFLA_LINK]) return -EINVAL; @@ -460,10 +461,10 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, return err; } - port = ipvlan_port_get_rtnl(phy_dev); if (data && data[IFLA_IPVLAN_MODE]) - port->mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); + mode = nla_get_u16(data[IFLA_IPVLAN_MODE]); + port = ipvlan_port_get_rtnl(phy_dev); ipvlan->phy_dev = phy_dev; ipvlan->dev = dev; ipvlan->port = port; @@ -489,6 +490,8 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev, goto ipvlan_destroy_port; list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); + ipvlan_set_port_mode(port, mode); + netif_stacked_transfer_operstate(phy_dev, dev); return 0; From ab5b7013db3cc637a8f19e00d71310e40db75bf6 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Sat, 20 Feb 2016 19:31:41 -0800 Subject: [PATCH 3/3] ipvlan: misc changes 1. scope correction for few functions that are used in single file. 2. Adjust variables that are used in fast-path to fit into single cacheline 3. Update rcv_frame() to skip shared check for frames coming over wire Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan.h | 9 +++------ drivers/net/ipvlan/ipvlan_core.c | 29 +++++++++++++++++------------ drivers/net/ipvlan/ipvlan_main.c | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 817cab1a7959..695a5dc9ace3 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -84,19 +84,19 @@ struct ipvl_addr { #define ip4addr ipu.ip4 struct hlist_node hlnode; /* Hash-table linkage */ struct list_head anode; /* logical-interface linkage */ - struct rcu_head rcu; ipvl_hdr_type atype; + struct rcu_head rcu; }; struct ipvl_port { struct net_device *dev; struct hlist_head hlhead[IPVLAN_HASH_SIZE]; struct list_head ipvlans; - struct rcu_head rcu; + u16 mode; struct work_struct wq; struct sk_buff_head backlog; int count; - u16 mode; + struct rcu_head rcu; }; static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d) @@ -114,7 +114,6 @@ static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d) return rtnl_dereference(d->rx_handler_data); } -void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev); void ipvlan_init_secret(void); unsigned int ipvlan_mac_hash(const unsigned char *addr); rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb); @@ -124,7 +123,5 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr); struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan, const void *iaddr, bool is_v6); bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6); -struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, - const void *iaddr, bool is_v6); void ipvlan_ht_addr_del(struct ipvl_addr *addr); #endif /* __IPVLAN_H */ diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 4e60c6bbdb6e..d6d0524ee5fd 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -53,8 +53,8 @@ static u8 ipvlan_get_v4_hash(const void *iaddr) IPVLAN_HASH_MASK; } -struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, - const void *iaddr, bool is_v6) +static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, + const void *iaddr, bool is_v6) { struct ipvl_addr *addr; u8 hash; @@ -265,20 +265,25 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb, struct sk_buff *skb = *pskb; len = skb->len + ETH_HLEN; - if (unlikely(!(dev->flags & IFF_UP))) { - kfree_skb(skb); - goto out; + /* Only packets exchanged between two local slaves need to have + * device-up check as well as skb-share check. + */ + if (local) { + if (unlikely(!(dev->flags & IFF_UP))) { + kfree_skb(skb); + goto out; + } + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + goto out; + + *pskb = skb; } - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out; - - *pskb = skb; skb->dev = dev; - skb->pkt_type = PACKET_HOST; if (local) { + skb->pkt_type = PACKET_HOST; if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS) success = true; } else { diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 5bcb852c5500..a7ca1c519a0d 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -9,7 +9,7 @@ #include "ipvlan.h" -void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) +static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) { ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj; }