This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++-
include/linux/skbuff.h | 2 +
net/core/dev.c | 144 +++++++++++---------------------------
net/core/skbuff.c | 1 +
4 files changed, 119 insertions(+), 103 deletions(-)
@@ -1423,6 +1423,68 @@ static void bond_setup_by_slave(struct net_device *bond_dev,bond->setup_by_slave=1;}+/* On bonding slaves other than the currently active slave, suppress+*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and+*ARPonactive-backupslaveswitharp_validateenabled.+*/+staticboolbond_should_deliver_exact_match(structsk_buff*skb,+structnet_device*slave_dev,+structnet_device*bond_dev)+{+if(slave_dev->priv_flags&IFF_SLAVE_INACTIVE){+if(slave_dev->priv_flags&IFF_SLAVE_NEEDARP&&+skb->protocol==__cpu_to_be16(ETH_P_ARP))+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+skb->pkt_type!=PACKET_BROADCAST&&+skb->pkt_type!=PACKET_MULTICAST)+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_8023AD&&+skb->protocol==__cpu_to_be16(ETH_P_SLOW))+returnfalse;++returntrue;+}+returnfalse;+}++staticstructsk_buff*bond_handle_frame(structsk_buff*skb)+{+structnet_device*slave_dev;+structnet_device*bond_dev;++skb=skb_share_check(skb,GFP_ATOMIC);+if(unlikely(!skb))+returnNULL;+slave_dev=skb->dev;+bond_dev=ACCESS_ONCE(slave_dev->master);+if(unlikely(!bond_dev))+returnskb;++if(bond_dev->priv_flags&IFF_MASTER_ARPMON)+slave_dev->last_rx=jiffies;++if(bond_should_deliver_exact_match(skb,slave_dev,bond_dev)){+skb->deliver_no_wcard=1;+returnskb;+}++skb->dev=bond_dev;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+bond_dev->priv_flags&IFF_BRIDGE_PORT&&+skb->pkt_type==PACKET_HOST){+u16*dest=(u16*)eth_hdr(skb)->h_dest;++memcpy(dest,bond_dev->dev_addr,ETH_ALEN);+}++netif_rx(skb);+returnNULL;+}+/* enslave device <slave> to bond device <master> */intbond_enslave(structnet_device*bond_dev,structnet_device*slave_dev){
@@ -1599,11 +1661,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)pr_debug("Error %d calling netdev_set_bond_master\n",res);gotoerr_restore_mac;}+res=netdev_rx_handler_register(slave_dev,bond_handle_frame,NULL);+if(res){+pr_debug("Error %d calling netdev_rx_handler_register\n",res);+gotoerr_unset_master;+}+/* open the slave since the application closed it */res=dev_open(slave_dev);if(res){pr_debug("Opening slave %s failed\n",slave_dev->name);-gotoerr_unset_master;+gotoerr_unreg_rxhandler;}new_slave->dev=slave_dev;
@@ -2114,6 +2186,7 @@ static int bond_release_all(struct net_device *bond_dev)netif_addr_unlock_bh(bond_dev);}+netdev_rx_handler_unregister(slave_dev);netdev_set_bond_master(slave_dev,NULL);/* close slave before restoring its mac address */
@@ -3092,63 +3096,30 @@ void netdev_rx_handler_unregister(struct net_device *dev)}EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);-staticinlinevoidskb_bond_set_mac_by_master(structsk_buff*skb,-structnet_device*master)-{-if(skb->pkt_type==PACKET_HOST){-u16*dest=(u16*)eth_hdr(skb)->h_dest;--memcpy(dest,master->dev_addr,ETH_ALEN);-}-}--/* On bonding slaves other than the currently active slave, suppress-*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and-*ARPonactive-backupslaveswitharp_validateenabled.-*/-staticint__skb_bond_should_drop(structsk_buff*skb,-structnet_device*master)+staticvoidvlan_on_bond_hook(structsk_buff*skb){-structnet_device*dev=skb->dev;--if(master->priv_flags&IFF_MASTER_ARPMON)-dev->last_rx=jiffies;--if((master->priv_flags&IFF_MASTER_ALB)&&-(master->priv_flags&IFF_BRIDGE_PORT)){-/* Do address unmangle. The local destination address-*willbealwaystheonemasterhas.Providestheright-*functionalityinabridge.-*/-skb_bond_set_mac_by_master(skb,master);-}--if(dev->priv_flags&IFF_SLAVE_INACTIVE){-if((dev->priv_flags&IFF_SLAVE_NEEDARP)&&-skb->protocol==__cpu_to_be16(ETH_P_ARP))-return0;--if(master->priv_flags&IFF_MASTER_ALB){-if(skb->pkt_type!=PACKET_BROADCAST&&-skb->pkt_type!=PACKET_MULTICAST)-return0;-}-if(master->priv_flags&IFF_MASTER_8023AD&&-skb->protocol==__cpu_to_be16(ETH_P_SLOW))-return0;+/*+*MakesureARPframesreceivedonVLANinterfacesstackedon+*bondinginterfacesstillmaketheirwaytoanybasebonding+*devicethatmayhaveregisteredforaspecificptype.+*/+if(skb->dev->priv_flags&IFF_802_1Q_VLAN&&+vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING&&+skb->protocol==htons(ETH_P_ARP)){+structsk_buff*skb2=skb_clone(skb,GFP_ATOMIC);-return1;+if(!skb2)+return;+skb2->dev=vlan_dev_real_dev(skb->dev);+netif_rx(skb2);}-return0;}staticint__netif_receive_skb(structsk_buff*skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;-structnet_device*orig_dev;-structnet_device*null_or_orig;-structnet_device*orig_or_bond;+structnet_device*null_or_dev;intret=NET_RX_DROP;__be16type;
@@ -3164,29 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)if(!skb->skb_iif)skb->skb_iif=skb->dev->ifindex;-/*-*bondingnote:skbsreceivedoninactiveslavesshouldonly-*bedeliveredtopkthandlersthatareexactmatches.Also-*thedeliver_no_wcardflagwillbeset.Ifpackethandlers-*aresensitivetoduplicatepacketstheseskbswillneedto-*bedroppedatthehandler.-*/-null_or_orig=NULL;-orig_dev=skb->dev;-if(skb->deliver_no_wcard)-null_or_orig=orig_dev;-elseif(netif_is_bond_slave(orig_dev)){-structnet_device*bond_master=ACCESS_ONCE(orig_dev->master);--if(likely(bond_master)){-if(__skb_bond_should_drop(skb,bond_master)){-skb->deliver_no_wcard=1;-/* deliver only exact match */-null_or_orig=orig_dev;-}else-skb->dev=bond_master;-}-}+if(!skb->input_dev)+skb->input_dev=skb->dev;__this_cpu_inc(softnet_data.processed);skb_reset_network_header(skb);
@@ -3205,26 +3155,24 @@ static int __netif_receive_skb(struct sk_buff *skb)#endiflist_for_each_entry_rcu(ptype,&ptype_all,list){-if(ptype->dev==null_or_orig||ptype->dev==skb->dev||-ptype->dev==orig_dev){+if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)-ret=deliver_skb(skb,pt_prev,orig_dev);+ret=deliver_skb(skb,pt_prev);pt_prev=ptype;}}#ifdef CONFIG_NET_CLS_ACT-skb=handle_ing(skb,&pt_prev,&ret,orig_dev);+skb=handle_ing(skb,&pt_prev,&ret);if(!skb)gotoout;ncls:#endif-/* Handle special case of bridge or macvlan */rx_handler=rcu_dereference(skb->dev->rx_handler);if(rx_handler){if(pt_prev){-ret=deliver_skb(skb,pt_prev,orig_dev);+ret=deliver_skb(skb,pt_prev);pt_prev=NULL;}skb=rx_handler(skb);
@@ -3244,32 +3192,24 @@ ncls:gotoout;}-/*-*MakesureframesreceivedonVLANinterfacesstackedon-*bondinginterfacesstillmaketheirwaytoanybasebonding-*devicethatmayhaveregisteredforaspecificptype.The-*handlermayhavetoadjustskb->devandorig_dev.-*/-orig_or_bond=orig_dev;-if((skb->dev->priv_flags&IFF_802_1Q_VLAN)&&-(vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING)){-orig_or_bond=vlan_dev_real_dev(skb->dev);-}+vlan_on_bond_hook(skb);++/* deliver only exact match when indicated */+null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&(ptype->dev==null_or_orig||-ptype->dev==skb->dev||ptype->dev==orig_dev||-ptype->dev==orig_or_bond)){+if(ptype->type==type&&+(ptype->dev==null_or_dev||ptype->dev==skb->dev)){if(pt_prev)-ret=deliver_skb(skb,pt_prev,orig_dev);+ret=deliver_skb(skb,pt_prev);pt_prev=ptype;}}if(pt_prev){-ret=pt_prev->func(skb,skb->dev,pt_prev,orig_dev);+ret=__deliver_skb(skb,pt_prev);}else{atomic_long_inc(&skb->dev->rx_dropped);kfree_skb(skb);
From: Eric Dumazet <hidden> Date: 2011-02-18 13:30:05
Le vendredi 18 février 2011 à 14:25 +0100, Jiri Pirko a écrit :
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++-
include/linux/skbuff.h | 2 +
net/core/dev.c | 144 +++++++++++---------------------------
net/core/skbuff.c | 1 +
4 files changed, 119 insertions(+), 103 deletions(-)
Fri, Feb 18, 2011 at 02:29:51PM CET, eric.dumazet@gmail.com wrote:
Le vendredi 18 février 2011 à 14:25 +0100, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++-
include/linux/skbuff.h | 2 +
net/core/dev.c | 144 +++++++++++---------------------------
net/core/skbuff.c | 1 +
4 files changed, 119 insertions(+), 103 deletions(-)
Your patch looks fine, but adding 8 bytes to sk_buff for a "cleanup" is
really a show stopper for me.
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
Thanks.
Jirka
From: Eric Dumazet <hidden> Date: 2011-02-18 14:27:50
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
From: Patrick McHardy <hidden> Date: 2011-02-18 14:46:49
Am 18.02.2011 15:27, schrieb Eric Dumazet:
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
From: Patrick McHardy <hidden> Date: 2011-02-18 15:50:26
On 18.02.2011 15:58, Jiri Pirko wrote:
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Well, there are a couple of holes on 64 bit, perhaps you can rearrange
things and eliminate either iif or input_dev without increasing size
since they appear to be redundant.
From: Eric Dumazet <hidden> Date: 2011-02-18 16:14:36
Le vendredi 18 février 2011 à 16:50 +0100, Patrick McHardy a écrit :
On 18.02.2011 15:58, Jiri Pirko wrote:
quoted
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Well, there are a couple of holes on 64 bit, perhaps you can rearrange
things and eliminate either iif or input_dev without increasing size
since they appear to be redundant.
Jiri
I dont understand why netif_rx() is needed in your patch.
Can we stack 10 bond devices or so ???
If we avoid this stage and call the real thing (netif_receive_skb()),
then we dont need adding a field in each skb, since it can be carried by
a global variable (per cpu of course)
bond_handle_frame() being called from __netif_receive_skb() I believe it
can use netif_receive_skb() instead of netif_rx().
Same remark for vlan_on_bond_hook()
Fri, Feb 18, 2011 at 05:14:30PM CET, eric.dumazet@gmail.com wrote:
Le vendredi 18 février 2011 à 16:50 +0100, Patrick McHardy a écrit :
quoted
On 18.02.2011 15:58, Jiri Pirko wrote:
quoted
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Well, there are a couple of holes on 64 bit, perhaps you can rearrange
things and eliminate either iif or input_dev without increasing size
since they appear to be redundant.
Jiri
I dont understand why netif_rx() is needed in your patch.
I used netif_rx() because bridge and macvlan does that too. I did not see
a reason to not to do the same.
Can we stack 10 bond devices or so ???
If we avoid this stage and call the real thing (netif_receive_skb()),
then we dont need adding a field in each skb, since it can be carried by
a global variable (per cpu of course)
I'm probably missing something. How do netif_receive_skb() and
netif_rx() differ in this point of view, since both are calling:
"ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);"
?
Still I see a problem with the percpu global variable. We would have to
store skb pointer there as well and in each __netif_receive_skb() call it
would have to be checked if it's different from the current one.
In that case store new skb and orig_Dev.
Leaving aside that global variables are evil in general, I still think
this is not nicer solution then to add skb->input_dev (although I
understand your arguments).
bond_handle_frame() being called from __netif_receive_skb() I believe it
can use netif_receive_skb() instead of netif_rx().
Same remark for vlan_on_bond_hook()
From: Eric Dumazet <hidden> Date: 2011-02-18 19:18:02
Le vendredi 18 février 2011 à 19:47 +0100, Jiri Pirko a écrit :
Fri, Feb 18, 2011 at 05:14:30PM CET, eric.dumazet@gmail.com wrote:
quoted
Le vendredi 18 février 2011 à 16:50 +0100, Patrick McHardy a écrit :
quoted
On 18.02.2011 15:58, Jiri Pirko wrote:
quoted
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Well, there are a couple of holes on 64 bit, perhaps you can rearrange
things and eliminate either iif or input_dev without increasing size
since they appear to be redundant.
Jiri
I dont understand why netif_rx() is needed in your patch.
I used netif_rx() because bridge and macvlan does that too. I did not see
a reason to not to do the same.
quoted
Can we stack 10 bond devices or so ???
If we avoid this stage and call the real thing (netif_receive_skb()),
then we dont need adding a field in each skb, since it can be carried by
a global variable (per cpu of course)
I'm probably missing something. How do netif_receive_skb() and
netif_rx() differ in this point of view, since both are calling:
"ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);"
?
Still I see a problem with the percpu global variable. We would have to
store skb pointer there as well and in each __netif_receive_skb() call it
would have to be checked if it's different from the current one.
In that case store new skb and orig_Dev.
Leaving aside that global variables are evil in general, I still think
this is not nicer solution then to add skb->input_dev (although I
understand your arguments).
Really I must miss something about "global variables" thing/fear.
Kernel is full of global variables, they are not evil if properly used.
Take a look at net/core/dev.c :
static DEFINE_PER_CPU(int, xmit_recursion);
For an example of what I have in mind.
Fri, Feb 18, 2011 at 08:17:37PM CET, eric.dumazet@gmail.com wrote:
Le vendredi 18 février 2011 à 19:47 +0100, Jiri Pirko a écrit :
quoted
Fri, Feb 18, 2011 at 05:14:30PM CET, eric.dumazet@gmail.com wrote:
quoted
Le vendredi 18 février 2011 à 16:50 +0100, Patrick McHardy a écrit :
quoted
On 18.02.2011 15:58, Jiri Pirko wrote:
quoted
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Well, there are a couple of holes on 64 bit, perhaps you can rearrange
things and eliminate either iif or input_dev without increasing size
since they appear to be redundant.
Jiri
I dont understand why netif_rx() is needed in your patch.
I used netif_rx() because bridge and macvlan does that too. I did not see
a reason to not to do the same.
quoted
Can we stack 10 bond devices or so ???
If we avoid this stage and call the real thing (netif_receive_skb()),
then we dont need adding a field in each skb, since it can be carried by
a global variable (per cpu of course)
I'm probably missing something. How do netif_receive_skb() and
netif_rx() differ in this point of view, since both are calling:
"ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);"
?
Still I see a problem with the percpu global variable. We would have to
store skb pointer there as well and in each __netif_receive_skb() call it
would have to be checked if it's different from the current one.
In that case store new skb and orig_Dev.
Leaving aside that global variables are evil in general, I still think
this is not nicer solution then to add skb->input_dev (although I
understand your arguments).
Really I must miss something about "global variables" thing/fear.
Kernel is full of global variables, they are not evil if properly used.
I know. But that doesn't mean it's ok. But I see your point.
Take a look at net/core/dev.c :
static DEFINE_PER_CPU(int, xmit_recursion);
For an example of what I have in mind.
Yes I saw this. We would have to do something like:
struct skb_rx_context {
struct sk_buff *skb;
struct net_device *orig_dev;
};
static DEFINE_PER_CPU(struct skb_rx_context, skb_rx_context);
and then in __netif_receive_skb():
struct skb_rx_context *cont = __this_cpu_read(skb_rx_context);
if (cont->skb != skb) {
cont->skb = skb;
orig_dev = cont->orig_dev = skb->dev;
} else {
orig_dev = cont->orig_dev;
}
Does this make sense?
From: Eric Dumazet <hidden> Date: 2011-02-18 19:58:31
Le vendredi 18 février 2011 à 20:28 +0100, Jiri Pirko a écrit :
Yes I saw this. We would have to do something like:
struct skb_rx_context {
struct sk_buff *skb;
struct net_device *orig_dev;
};
static DEFINE_PER_CPU(struct skb_rx_context, skb_rx_context);
and then in __netif_receive_skb():
struct skb_rx_context *cont = __this_cpu_read(skb_rx_context);
if (cont->skb != skb) {
cont->skb = skb;
orig_dev = cont->orig_dev = skb->dev;
} else {
orig_dev = cont->orig_dev;
}
Does this make sense?
Well, yes, something like that, but I think you dont need to keep a
pointer to current skb. (It would not work if one handled/freed, same
'skb pointer' is reused a bit later)
Sorry, I wont have time to look at this right now, its now 21h00 in
France, time to get some time with family ;)
See you !
Fri, Feb 18, 2011 at 08:58:26PM CET, eric.dumazet@gmail.com wrote:
Le vendredi 18 février 2011 à 20:28 +0100, Jiri Pirko a écrit :
quoted
Yes I saw this. We would have to do something like:
struct skb_rx_context {
struct sk_buff *skb;
struct net_device *orig_dev;
};
static DEFINE_PER_CPU(struct skb_rx_context, skb_rx_context);
and then in __netif_receive_skb():
struct skb_rx_context *cont = __this_cpu_read(skb_rx_context);
if (cont->skb != skb) {
cont->skb = skb;
orig_dev = cont->orig_dev = skb->dev;
} else {
orig_dev = cont->orig_dev;
}
Does this make sense?
Well, yes, something like that, but I think you dont need to keep a
pointer to current skb. (It would not work if one handled/freed, same
'skb pointer' is reused a bit later)
Well I think I need. How else should I distinguish that new skb (first
time in __netif_receive_skb) is there and I need to remember orig_dev?
Sorry, I wont have time to look at this right now, its now 21h00 in
France, time to get some time with family ;)
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
Fri, Feb 18, 2011 at 03:46:45PM CET, kaber@trash.net wrote:
quoted
Am 18.02.2011 15:27, schrieb Eric Dumazet:
quoted
Le vendredi 18 février 2011 à 15:14 +0100, Jiri Pirko a écrit :
quoted
Do not know how to do it better. As for percpu variable, not only
origdev would have to be remembered but also probably skb pointer to
know if it's the first run on the skb or not. Can't really figure out a
better solution. Can you?
I'll try and let you know.
Why not simply do a lookup on skb->iif?
Well I was trying to avoid iterating over list of devices for each
incoming frame.
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original device
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++++++++-
net/core/dev.c | 111 ++++++++-------------------------------
2 files changed, 97 insertions(+), 89 deletions(-)
@@ -1423,6 +1423,68 @@ static void bond_setup_by_slave(struct net_device *bond_dev,bond->setup_by_slave=1;}+/* On bonding slaves other than the currently active slave, suppress+*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and+*ARPonactive-backupslaveswitharp_validateenabled.+*/+staticboolbond_should_deliver_exact_match(structsk_buff*skb,+structnet_device*slave_dev,+structnet_device*bond_dev)+{+if(slave_dev->priv_flags&IFF_SLAVE_INACTIVE){+if(slave_dev->priv_flags&IFF_SLAVE_NEEDARP&&+skb->protocol==__cpu_to_be16(ETH_P_ARP))+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+skb->pkt_type!=PACKET_BROADCAST&&+skb->pkt_type!=PACKET_MULTICAST)+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_8023AD&&+skb->protocol==__cpu_to_be16(ETH_P_SLOW))+returnfalse;++returntrue;+}+returnfalse;+}++staticstructsk_buff*bond_handle_frame(structsk_buff*skb)+{+structnet_device*slave_dev;+structnet_device*bond_dev;++skb=skb_share_check(skb,GFP_ATOMIC);+if(unlikely(!skb))+returnNULL;+slave_dev=skb->dev;+bond_dev=ACCESS_ONCE(slave_dev->master);+if(unlikely(!bond_dev))+returnskb;++if(bond_dev->priv_flags&IFF_MASTER_ARPMON)+slave_dev->last_rx=jiffies;++if(bond_should_deliver_exact_match(skb,slave_dev,bond_dev)){+skb->deliver_no_wcard=1;+returnskb;+}++skb->dev=bond_dev;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+bond_dev->priv_flags&IFF_BRIDGE_PORT&&+skb->pkt_type==PACKET_HOST){+u16*dest=(u16*)eth_hdr(skb)->h_dest;++memcpy(dest,bond_dev->dev_addr,ETH_ALEN);+}++netif_rx(skb);+returnNULL;+}+/* enslave device <slave> to bond device <master> */intbond_enslave(structnet_device*bond_dev,structnet_device*slave_dev){
@@ -1599,11 +1661,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)pr_debug("Error %d calling netdev_set_bond_master\n",res);gotoerr_restore_mac;}+res=netdev_rx_handler_register(slave_dev,bond_handle_frame,NULL);+if(res){+pr_debug("Error %d calling netdev_rx_handler_register\n",res);+gotoerr_unset_master;+}+/* open the slave since the application closed it */res=dev_open(slave_dev);if(res){pr_debug("Opening slave %s failed\n",slave_dev->name);-gotoerr_unset_master;+gotoerr_unreg_rxhandler;}new_slave->dev=slave_dev;
@@ -2114,6 +2186,7 @@ static int bond_release_all(struct net_device *bond_dev)netif_addr_unlock_bh(bond_dev);}+netdev_rx_handler_unregister(slave_dev);netdev_set_bond_master(slave_dev,NULL);/* close slave before restoring its mac address */
@@ -3092,63 +3092,31 @@ void netdev_rx_handler_unregister(struct net_device *dev)}EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);-staticinlinevoidskb_bond_set_mac_by_master(structsk_buff*skb,-structnet_device*master)+staticvoidvlan_on_bond_hook(structsk_buff*skb){-if(skb->pkt_type==PACKET_HOST){-u16*dest=(u16*)eth_hdr(skb)->h_dest;--memcpy(dest,master->dev_addr,ETH_ALEN);-}-}--/* On bonding slaves other than the currently active slave, suppress-*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and-*ARPonactive-backupslaveswitharp_validateenabled.-*/-staticint__skb_bond_should_drop(structsk_buff*skb,-structnet_device*master)-{-structnet_device*dev=skb->dev;--if(master->priv_flags&IFF_MASTER_ARPMON)-dev->last_rx=jiffies;--if((master->priv_flags&IFF_MASTER_ALB)&&-(master->priv_flags&IFF_BRIDGE_PORT)){-/* Do address unmangle. The local destination address-*willbealwaystheonemasterhas.Providestheright-*functionalityinabridge.-*/-skb_bond_set_mac_by_master(skb,master);-}--if(dev->priv_flags&IFF_SLAVE_INACTIVE){-if((dev->priv_flags&IFF_SLAVE_NEEDARP)&&-skb->protocol==__cpu_to_be16(ETH_P_ARP))-return0;--if(master->priv_flags&IFF_MASTER_ALB){-if(skb->pkt_type!=PACKET_BROADCAST&&-skb->pkt_type!=PACKET_MULTICAST)-return0;-}-if(master->priv_flags&IFF_MASTER_8023AD&&-skb->protocol==__cpu_to_be16(ETH_P_SLOW))-return0;+/*+*MakesureARPframesreceivedonVLANinterfacesstackedon+*bondinginterfacesstillmaketheirwaytoanybasebonding+*devicethatmayhaveregisteredforaspecificptype.+*/+if(skb->dev->priv_flags&IFF_802_1Q_VLAN&&+vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING&&+skb->protocol==htons(ETH_P_ARP)){+structsk_buff*skb2=skb_clone(skb,GFP_ATOMIC);-return1;+if(!skb2)+return;+skb2->dev=vlan_dev_real_dev(skb->dev);+netif_rx(skb2);}-return0;}staticint__netif_receive_skb(structsk_buff*skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*null_or_dev;structnet_device*orig_dev;-structnet_device*null_or_orig;-structnet_device*orig_or_bond;intret=NET_RX_DROP;__be16type;
@@ -3164,30 +3132,6 @@ static int __netif_receive_skb(struct sk_buff *skb)if(!skb->skb_iif)skb->skb_iif=skb->dev->ifindex;-/*-*bondingnote:skbsreceivedoninactiveslavesshouldonly-*bedeliveredtopkthandlersthatareexactmatches.Also-*thedeliver_no_wcardflagwillbeset.Ifpackethandlers-*aresensitivetoduplicatepacketstheseskbswillneedto-*bedroppedatthehandler.-*/-null_or_orig=NULL;-orig_dev=skb->dev;-if(skb->deliver_no_wcard)-null_or_orig=orig_dev;-elseif(netif_is_bond_slave(orig_dev)){-structnet_device*bond_master=ACCESS_ONCE(orig_dev->master);--if(likely(bond_master)){-if(__skb_bond_should_drop(skb,bond_master)){-skb->deliver_no_wcard=1;-/* deliver only exact match */-null_or_orig=orig_dev;-}else-skb->dev=bond_master;-}-}-__this_cpu_inc(softnet_data.processed);skb_reset_network_header(skb);skb_reset_transport_header(skb);
@@ -3196,6 +3140,7 @@ static int __netif_receive_skb(struct sk_buff *skb)pt_prev=NULL;rcu_read_lock();+orig_dev=dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);#ifdef CONFIG_NET_CLS_ACTif(skb->tc_verd&TC_NCLS){
@@ -3205,8 +3150,7 @@ static int __netif_receive_skb(struct sk_buff *skb)#endiflist_for_each_entry_rcu(ptype,&ptype_all,list){-if(ptype->dev==null_or_orig||ptype->dev==skb->dev||-ptype->dev==orig_dev){+if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
@@ -3220,7 +3164,6 @@ static int __netif_receive_skb(struct sk_buff *skb)ncls:#endif-/* Handle special case of bridge or macvlan */rx_handler=rcu_dereference(skb->dev->rx_handler);if(rx_handler){if(pt_prev){
@@ -3244,24 +3187,16 @@ ncls:gotoout;}-/*-*MakesureframesreceivedonVLANinterfacesstackedon-*bondinginterfacesstillmaketheirwaytoanybasebonding-*devicethatmayhaveregisteredforaspecificptype.The-*handlermayhavetoadjustskb->devandorig_dev.-*/-orig_or_bond=orig_dev;-if((skb->dev->priv_flags&IFF_802_1Q_VLAN)&&-(vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING)){-orig_or_bond=vlan_dev_real_dev(skb->dev);-}+vlan_on_bond_hook(skb);++/* deliver only exact match when indicated */+null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&(ptype->dev==null_or_orig||-ptype->dev==skb->dev||ptype->dev==orig_dev||-ptype->dev==orig_or_bond)){+if(ptype->type==type&&+(ptype->dev==null_or_dev||ptype->dev==skb->dev)){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
From: Jay Vosburgh <hidden> Date: 2011-02-18 23:06:20
Jiri Pirko [off-list ref] wrote:
quoted hunk
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original device
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++++++++-
net/core/dev.c | 111 ++++++++-------------------------------
2 files changed, 97 insertions(+), 89 deletions(-)
bond->setup_by_slave = 1;
}
+/* On bonding slaves other than the currently active slave, suppress
+ * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
+ * ARP on active-backup slaves with arp_validate enabled.
+ */
+static bool bond_should_deliver_exact_match(struct sk_buff *skb,
+ struct net_device *slave_dev,
+ struct net_device *bond_dev)
+{
+ if (slave_dev->priv_flags & IFF_SLAVE_INACTIVE) {
+ if (slave_dev->priv_flags & IFF_SLAVE_NEEDARP &&
+ skb->protocol == __cpu_to_be16(ETH_P_ARP))
+ return false;
+
+ if (bond_dev->priv_flags & IFF_MASTER_ALB &&
+ skb->pkt_type != PACKET_BROADCAST &&
+ skb->pkt_type != PACKET_MULTICAST)
+ return false;
+
+ if (bond_dev->priv_flags & IFF_MASTER_8023AD &&
+ skb->protocol == __cpu_to_be16(ETH_P_SLOW))
+ return false;
Since this is all in the bonding code now, it should be possible
to do away with using priv_flags for all (or at least most) of this.
Perhaps in a follow-on patch.
The last_rx field could probably move into bonding as well,
although it looks like there are a couple of drivers using last_rx for
something (more than just setting it).
@@ -2114,6 +2186,7 @@ static int bond_release_all(struct net_device *bond_dev)
netif_addr_unlock_bh(bond_dev);
}
+ netdev_rx_handler_unregister(slave_dev);
netdev_set_bond_master(slave_dev, NULL);
/* close slave before restoring its mac address */
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
-static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
- struct net_device *master)
+static void vlan_on_bond_hook(struct sk_buff *skb)
{
- if (skb->pkt_type == PACKET_HOST) {
- u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
-
- memcpy(dest, master->dev_addr, ETH_ALEN);
- }
-}
-
-/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
- * ARP on active-backup slaves with arp_validate enabled.
- */
-static int __skb_bond_should_drop(struct sk_buff *skb,
- struct net_device *master)
-{
- struct net_device *dev = skb->dev;
-
- if (master->priv_flags & IFF_MASTER_ARPMON)
- dev->last_rx = jiffies;
-
- if ((master->priv_flags & IFF_MASTER_ALB) &&
- (master->priv_flags & IFF_BRIDGE_PORT)) {
- /* Do address unmangle. The local destination address
- * will be always the one master has. Provides the right
- * functionality in a bridge.
- */
- skb_bond_set_mac_by_master(skb, master);
- }
-
- if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
- if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
- skb->protocol == __cpu_to_be16(ETH_P_ARP))
- return 0;
-
- if (master->priv_flags & IFF_MASTER_ALB) {
- if (skb->pkt_type != PACKET_BROADCAST &&
- skb->pkt_type != PACKET_MULTICAST)
- return 0;
- }
- if (master->priv_flags & IFF_MASTER_8023AD &&
- skb->protocol == __cpu_to_be16(ETH_P_SLOW))
- return 0;
+ /*
+ * Make sure ARP frames received on VLAN interfaces stacked on
+ * bonding interfaces still make their way to any base bonding
+ * device that may have registered for a specific ptype.
+ */
+ if (skb->dev->priv_flags & IFF_802_1Q_VLAN &&
+ vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING &&
+ skb->protocol == htons(ETH_P_ARP)) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
- return 1;
+ if (!skb2)
+ return;
+ skb2->dev = vlan_dev_real_dev(skb->dev);
+ netif_rx(skb2);
}
- return 0;
}
static int __netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
rx_handler_func_t *rx_handler;
+ struct net_device *null_or_dev;
struct net_device *orig_dev;
- struct net_device *null_or_orig;
- struct net_device *orig_or_bond;
int ret = NET_RX_DROP;
__be16 type;
@@ -3164,30 +3132,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
if (!skb->skb_iif)
skb->skb_iif = skb->dev->ifindex;
- /*
- * bonding note: skbs received on inactive slaves should only
- * be delivered to pkt handlers that are exact matches. Also
- * the deliver_no_wcard flag will be set. If packet handlers
- * are sensitive to duplicate packets these skbs will need to
- * be dropped at the handler.
- */
- null_or_orig = NULL;
- orig_dev = skb->dev;
- if (skb->deliver_no_wcard)
- null_or_orig = orig_dev;
- else if (netif_is_bond_slave(orig_dev)) {
- struct net_device *bond_master = ACCESS_ONCE(orig_dev->master);
-
- if (likely(bond_master)) {
- if (__skb_bond_should_drop(skb, bond_master)) {
- skb->deliver_no_wcard = 1;
- /* deliver only exact match */
- null_or_orig = orig_dev;
- } else
- skb->dev = bond_master;
- }
- }
-
__this_cpu_inc(softnet_data.processed);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
@@ -3196,6 +3140,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
Aren't most packets going to have orig_dev == skb->dev at this
point? Can this be combined with the skb_iif test a few lines above
this in __netif_receive_skb, looking something like:
if (!skb->skb_iif) {
skb->skb_iif = skb->dev->ifindex;
orig_dev = skb->dev;
else {
orig_dev = dev_get_by_index_rcu(...);
}
Presumably moving the whole thing down inside the rcu_read_lock.
VLAN packets should come through here twice, but the first time
through is before the call to vlan_hwaccel_do_receive, so skb->dev
hasn't been set to the VLAN's dev yet.
Unless, of course, you find a place to store the orig_dev.
-J
quoted hunk
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) {
@@ -3205,8 +3150,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
#endif
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
- ptype->dev == orig_dev) {
+ if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
@@ -3220,7 +3164,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
ncls:
#endif
- /* Handle special case of bridge or macvlan */
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3244,24 +3187,16 @@ ncls:
goto out;
}
- /*
- * Make sure frames received on VLAN interfaces stacked on
- * bonding interfaces still make their way to any base bonding
- * device that may have registered for a specific ptype. The
- * handler may have to adjust skb->dev and orig_dev.
- */
- orig_or_bond = orig_dev;
- if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
- (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
- orig_or_bond = vlan_dev_real_dev(skb->dev);
- }
+ vlan_on_bond_hook(skb);
+
+ /* deliver only exact match when indicated */
+ null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
- if (ptype->type == type && (ptype->dev == null_or_orig ||
- ptype->dev == skb->dev || ptype->dev == orig_dev ||
- ptype->dev == orig_or_bond)) {
+ if (ptype->type == type &&
+ (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
--
1.7.3.4
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
Sat, Feb 19, 2011 at 12:06:11AM CET, fubar@us.ibm.com wrote:
Jiri Pirko [off-list ref] wrote:
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also bond-specific
work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original device
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++++++++-
net/core/dev.c | 111 ++++++++-------------------------------
2 files changed, 97 insertions(+), 89 deletions(-)
bond->setup_by_slave = 1;
}
+/* On bonding slaves other than the currently active slave, suppress
+ * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
+ * ARP on active-backup slaves with arp_validate enabled.
+ */
+static bool bond_should_deliver_exact_match(struct sk_buff *skb,
+ struct net_device *slave_dev,
+ struct net_device *bond_dev)
+{
+ if (slave_dev->priv_flags & IFF_SLAVE_INACTIVE) {
+ if (slave_dev->priv_flags & IFF_SLAVE_NEEDARP &&
+ skb->protocol == __cpu_to_be16(ETH_P_ARP))
+ return false;
+
+ if (bond_dev->priv_flags & IFF_MASTER_ALB &&
+ skb->pkt_type != PACKET_BROADCAST &&
+ skb->pkt_type != PACKET_MULTICAST)
+ return false;
+
+ if (bond_dev->priv_flags & IFF_MASTER_8023AD &&
+ skb->protocol == __cpu_to_be16(ETH_P_SLOW))
+ return false;
Since this is all in the bonding code now, it should be possible
to do away with using priv_flags for all (or at least most) of this.
Perhaps in a follow-on patch.
follow-on patch was exatly my intension to do this in.
The last_rx field could probably move into bonding as well,
although it looks like there are a couple of drivers using last_rx for
something (more than just setting it).
@@ -2114,6 +2186,7 @@ static int bond_release_all(struct net_device *bond_dev)
netif_addr_unlock_bh(bond_dev);
}
+ netdev_rx_handler_unregister(slave_dev);
netdev_set_bond_master(slave_dev, NULL);
/* close slave before restoring its mac address */
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
-static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
- struct net_device *master)
+static void vlan_on_bond_hook(struct sk_buff *skb)
{
- if (skb->pkt_type == PACKET_HOST) {
- u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
-
- memcpy(dest, master->dev_addr, ETH_ALEN);
- }
-}
-
-/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
- * ARP on active-backup slaves with arp_validate enabled.
- */
-static int __skb_bond_should_drop(struct sk_buff *skb,
- struct net_device *master)
-{
- struct net_device *dev = skb->dev;
-
- if (master->priv_flags & IFF_MASTER_ARPMON)
- dev->last_rx = jiffies;
-
- if ((master->priv_flags & IFF_MASTER_ALB) &&
- (master->priv_flags & IFF_BRIDGE_PORT)) {
- /* Do address unmangle. The local destination address
- * will be always the one master has. Provides the right
- * functionality in a bridge.
- */
- skb_bond_set_mac_by_master(skb, master);
- }
-
- if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
- if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
- skb->protocol == __cpu_to_be16(ETH_P_ARP))
- return 0;
-
- if (master->priv_flags & IFF_MASTER_ALB) {
- if (skb->pkt_type != PACKET_BROADCAST &&
- skb->pkt_type != PACKET_MULTICAST)
- return 0;
- }
- if (master->priv_flags & IFF_MASTER_8023AD &&
- skb->protocol == __cpu_to_be16(ETH_P_SLOW))
- return 0;
+ /*
+ * Make sure ARP frames received on VLAN interfaces stacked on
+ * bonding interfaces still make their way to any base bonding
+ * device that may have registered for a specific ptype.
+ */
+ if (skb->dev->priv_flags & IFF_802_1Q_VLAN &&
+ vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING &&
+ skb->protocol == htons(ETH_P_ARP)) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
- return 1;
+ if (!skb2)
+ return;
+ skb2->dev = vlan_dev_real_dev(skb->dev);
+ netif_rx(skb2);
}
- return 0;
}
static int __netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
rx_handler_func_t *rx_handler;
+ struct net_device *null_or_dev;
struct net_device *orig_dev;
- struct net_device *null_or_orig;
- struct net_device *orig_or_bond;
int ret = NET_RX_DROP;
__be16 type;
@@ -3164,30 +3132,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
if (!skb->skb_iif)
skb->skb_iif = skb->dev->ifindex;
- /*
- * bonding note: skbs received on inactive slaves should only
- * be delivered to pkt handlers that are exact matches. Also
- * the deliver_no_wcard flag will be set. If packet handlers
- * are sensitive to duplicate packets these skbs will need to
- * be dropped at the handler.
- */
- null_or_orig = NULL;
- orig_dev = skb->dev;
- if (skb->deliver_no_wcard)
- null_or_orig = orig_dev;
- else if (netif_is_bond_slave(orig_dev)) {
- struct net_device *bond_master = ACCESS_ONCE(orig_dev->master);
-
- if (likely(bond_master)) {
- if (__skb_bond_should_drop(skb, bond_master)) {
- skb->deliver_no_wcard = 1;
- /* deliver only exact match */
- null_or_orig = orig_dev;
- } else
- skb->dev = bond_master;
- }
- }
-
__this_cpu_inc(softnet_data.processed);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
@@ -3196,6 +3140,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
Aren't most packets going to have orig_dev == skb->dev at this
point? Can this be combined with the skb_iif test a few lines above
this in __netif_receive_skb, looking something like:
if (!skb->skb_iif) {
skb->skb_iif = skb->dev->ifindex;
orig_dev = skb->dev;
else {
orig_dev = dev_get_by_index_rcu(...);
}
Presumably moving the whole thing down inside the rcu_read_lock.
Yep, that's reasonable. Thanks.
VLAN packets should come through here twice, but the first time
through is before the call to vlan_hwaccel_do_receive, so skb->dev
hasn't been set to the VLAN's dev yet.
Unless, of course, you find a place to store the orig_dev.
-J
quoted
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd & TC_NCLS) {
@@ -3205,8 +3150,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
#endif
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
- ptype->dev == orig_dev) {
+ if (!ptype->dev || ptype->dev == skb->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
@@ -3220,7 +3164,6 @@ static int __netif_receive_skb(struct sk_buff *skb)
ncls:
#endif
- /* Handle special case of bridge or macvlan */
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3244,24 +3187,16 @@ ncls:
goto out;
}
- /*
- * Make sure frames received on VLAN interfaces stacked on
- * bonding interfaces still make their way to any base bonding
- * device that may have registered for a specific ptype. The
- * handler may have to adjust skb->dev and orig_dev.
- */
- orig_or_bond = orig_dev;
- if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
- (vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
- orig_or_bond = vlan_dev_real_dev(skb->dev);
- }
+ vlan_on_bond_hook(skb);
+
+ /* deliver only exact match when indicated */
+ null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
- if (ptype->type == type && (ptype->dev == null_or_orig ||
- ptype->dev == skb->dev || ptype->dev == orig_dev ||
- ptype->dev == orig_or_bond)) {
+ if (ptype->type == type &&
+ (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
--
1.7.3.4
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
---
drivers/net/bonding/bond_main.c | 75 ++++++++++++++++++++++++-
net/core/dev.c | 120 +++++++++-----------------------------
2 files changed, 103 insertions(+), 92 deletions(-)
@@ -1423,6 +1423,68 @@ static void bond_setup_by_slave(struct net_device *bond_dev,bond->setup_by_slave=1;}+/* On bonding slaves other than the currently active slave, suppress+*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and+*ARPonactive-backupslaveswitharp_validateenabled.+*/+staticboolbond_should_deliver_exact_match(structsk_buff*skb,+structnet_device*slave_dev,+structnet_device*bond_dev)+{+if(slave_dev->priv_flags&IFF_SLAVE_INACTIVE){+if(slave_dev->priv_flags&IFF_SLAVE_NEEDARP&&+skb->protocol==__cpu_to_be16(ETH_P_ARP))+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+skb->pkt_type!=PACKET_BROADCAST&&+skb->pkt_type!=PACKET_MULTICAST)+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_8023AD&&+skb->protocol==__cpu_to_be16(ETH_P_SLOW))+returnfalse;++returntrue;+}+returnfalse;+}++staticstructsk_buff*bond_handle_frame(structsk_buff*skb)+{+structnet_device*slave_dev;+structnet_device*bond_dev;++skb=skb_share_check(skb,GFP_ATOMIC);+if(unlikely(!skb))+returnNULL;+slave_dev=skb->dev;+bond_dev=ACCESS_ONCE(slave_dev->master);+if(unlikely(!bond_dev))+returnskb;++if(bond_dev->priv_flags&IFF_MASTER_ARPMON)+slave_dev->last_rx=jiffies;++if(bond_should_deliver_exact_match(skb,slave_dev,bond_dev)){+skb->deliver_no_wcard=1;+returnskb;+}++skb->dev=bond_dev;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+bond_dev->priv_flags&IFF_BRIDGE_PORT&&+skb->pkt_type==PACKET_HOST){+u16*dest=(u16*)eth_hdr(skb)->h_dest;++memcpy(dest,bond_dev->dev_addr,ETH_ALEN);+}++netif_rx(skb);+returnNULL;+}+/* enslave device <slave> to bond device <master> */intbond_enslave(structnet_device*bond_dev,structnet_device*slave_dev){
@@ -1599,11 +1661,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)pr_debug("Error %d calling netdev_set_bond_master\n",res);gotoerr_restore_mac;}+res=netdev_rx_handler_register(slave_dev,bond_handle_frame,NULL);+if(res){+pr_debug("Error %d calling netdev_rx_handler_register\n",res);+gotoerr_unset_master;+}+/* open the slave since the application closed it */res=dev_open(slave_dev);if(res){pr_debug("Opening slave %s failed\n",slave_dev->name);-gotoerr_unset_master;+gotoerr_unreg_rxhandler;}new_slave->dev=slave_dev;
@@ -2114,6 +2186,7 @@ static int bond_release_all(struct net_device *bond_dev)netif_addr_unlock_bh(bond_dev);}+netdev_rx_handler_unregister(slave_dev);netdev_set_bond_master(slave_dev,NULL);/* close slave before restoring its mac address */
@@ -3092,54 +3092,23 @@ void netdev_rx_handler_unregister(struct net_device *dev)}EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);-staticinlinevoidskb_bond_set_mac_by_master(structsk_buff*skb,-structnet_device*master)+staticvoidvlan_on_bond_hook(structsk_buff*skb){-if(skb->pkt_type==PACKET_HOST){-u16*dest=(u16*)eth_hdr(skb)->h_dest;--memcpy(dest,master->dev_addr,ETH_ALEN);-}-}--/* On bonding slaves other than the currently active slave, suppress-*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and-*ARPonactive-backupslaveswitharp_validateenabled.-*/-staticint__skb_bond_should_drop(structsk_buff*skb,-structnet_device*master)-{-structnet_device*dev=skb->dev;--if(master->priv_flags&IFF_MASTER_ARPMON)-dev->last_rx=jiffies;--if((master->priv_flags&IFF_MASTER_ALB)&&-(master->priv_flags&IFF_BRIDGE_PORT)){-/* Do address unmangle. The local destination address-*willbealwaystheonemasterhas.Providestheright-*functionalityinabridge.-*/-skb_bond_set_mac_by_master(skb,master);-}--if(dev->priv_flags&IFF_SLAVE_INACTIVE){-if((dev->priv_flags&IFF_SLAVE_NEEDARP)&&-skb->protocol==__cpu_to_be16(ETH_P_ARP))-return0;--if(master->priv_flags&IFF_MASTER_ALB){-if(skb->pkt_type!=PACKET_BROADCAST&&-skb->pkt_type!=PACKET_MULTICAST)-return0;-}-if(master->priv_flags&IFF_MASTER_8023AD&&-skb->protocol==__cpu_to_be16(ETH_P_SLOW))-return0;+/*+*MakesureARPframesreceivedonVLANinterfacesstackedon+*bondinginterfacesstillmaketheirwaytoanybasebonding+*devicethatmayhaveregisteredforaspecificptype.+*/+if(skb->dev->priv_flags&IFF_802_1Q_VLAN&&+vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING&&+skb->protocol==htons(ETH_P_ARP)){+structsk_buff*skb2=skb_clone(skb,GFP_ATOMIC);-return1;+if(!skb2)+return;+skb2->dev=vlan_dev_real_dev(skb->dev);+netif_rx(skb2);}-return0;}staticint__netif_receive_skb(structsk_buff*skb)
@@ -3147,8 +3116,7 @@ static int __netif_receive_skb(struct sk_buff *skb)structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;structnet_device*orig_dev;-structnet_device*null_or_orig;-structnet_device*orig_or_bond;+structnet_device*null_or_dev;intret=NET_RX_DROP;__be16type;
@@ -3161,33 +3129,6 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-if(!skb->skb_iif)-skb->skb_iif=skb->dev->ifindex;--/*-*bondingnote:skbsreceivedoninactiveslavesshouldonly-*bedeliveredtopkthandlersthatareexactmatches.Also-*thedeliver_no_wcardflagwillbeset.Ifpackethandlers-*aresensitivetoduplicatepacketstheseskbswillneedto-*bedroppedatthehandler.-*/-null_or_orig=NULL;-orig_dev=skb->dev;-if(skb->deliver_no_wcard)-null_or_orig=orig_dev;-elseif(netif_is_bond_slave(orig_dev)){-structnet_device*bond_master=ACCESS_ONCE(orig_dev->master);--if(likely(bond_master)){-if(__skb_bond_should_drop(skb,bond_master)){-skb->deliver_no_wcard=1;-/* deliver only exact match */-null_or_orig=orig_dev;-}else-skb->dev=bond_master;-}-}-__this_cpu_inc(softnet_data.processed);skb_reset_network_header(skb);skb_reset_transport_header(skb);
@@ -3197,6 +3138,13 @@ static int __netif_receive_skb(struct sk_buff *skb)rcu_read_lock();+if(!skb->skb_iif){+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;+}else{+orig_dev=dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);+}+#ifdef CONFIG_NET_CLS_ACTif(skb->tc_verd&TC_NCLS){skb->tc_verd=CLR_TC_NCLS(skb->tc_verd);
@@ -3205,8 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb)#endiflist_for_each_entry_rcu(ptype,&ptype_all,list){-if(ptype->dev==null_or_orig||ptype->dev==skb->dev||-ptype->dev==orig_dev){+if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
@@ -3220,7 +3167,6 @@ static int __netif_receive_skb(struct sk_buff *skb)ncls:#endif-/* Handle special case of bridge or macvlan */rx_handler=rcu_dereference(skb->dev->rx_handler);if(rx_handler){if(pt_prev){
@@ -3244,24 +3190,16 @@ ncls:gotoout;}-/*-*MakesureframesreceivedonVLANinterfacesstackedon-*bondinginterfacesstillmaketheirwaytoanybasebonding-*devicethatmayhaveregisteredforaspecificptype.The-*handlermayhavetoadjustskb->devandorig_dev.-*/-orig_or_bond=orig_dev;-if((skb->dev->priv_flags&IFF_802_1Q_VLAN)&&-(vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING)){-orig_or_bond=vlan_dev_real_dev(skb->dev);-}+vlan_on_bond_hook(skb);++/* deliver only exact match when indicated */+null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&(ptype->dev==null_or_orig||-ptype->dev==skb->dev||ptype->dev==orig_dev||-ptype->dev==orig_or_bond)){+if(ptype->type==type&&+(ptype->dev==null_or_dev||ptype->dev==skb->dev)){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
From: Eric Dumazet <hidden> Date: 2011-02-19 08:38:01
Le samedi 19 février 2011 à 09:05 +0100, Jiri Pirko a écrit :
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Seems much better ;)
Do you have some performance numbers ?
Sat, Feb 19, 2011 at 09:37:55AM CET, eric.dumazet@gmail.com wrote:
Le samedi 19 février 2011 à 09:05 +0100, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Seems much better ;)
Do you have some performance numbers ?
I don't. I can surely obtain some. What's the best way to measure this?
From: Eric Dumazet <hidden> Date: 2011-02-19 09:22:57
Le samedi 19 février 2011 à 09:58 +0100, Jiri Pirko a écrit :
Sat, Feb 19, 2011 at 09:37:55AM CET, eric.dumazet@gmail.com wrote:
quoted
Le samedi 19 février 2011 à 09:05 +0100, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Seems much better ;)
Do you have some performance numbers ?
I don't. I can surely obtain some. What's the best way to measure this?
Hmm, since its receive path :
Two machines, one sending (pktgen) a flood, one receiving it and
check/count how many frames hit destination, before/after patch.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-19 10:56:32
Le 19/02/2011 09:05, Jiri Pirko a écrit :
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing skb->dev with skb->dev->master.
Time has passed and we eventually added many special processing for bonding into
__netif_receive_skb(), but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver whatever need to be delivered, to
whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on top on bonding, bridge on top
on bonding, ...
That way, we can probably keep the list of crossed devices inside a local array, and call
deliver_skb() with the current "orig_dev" when appropriate. No need to overload sk_buff nor to use a
global variable.
Of course, this might be a very simplistic view.
Any comments?
Nicolas.
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
That way, we can probably keep the list of crossed devices inside a
local array, and call deliver_skb() with the current "orig_dev" when
appropriate. No need to overload sk_buff nor to use a global
variable.
Of course, this might be a very simplistic view.
Any comments?
Nicolas.
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-19 13:23:51
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted hunk
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously crossed device", while following the
path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for &ptype_all and for
&ptype_base[ntohs(type) & PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type &&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
- if (ptype->type == type &&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type && !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the list_for_each_entry_rcu() loops. And because we
match only ptype->dev == dev inside the loop and !ptype->dev outside the loop, this should avoid
duplicate delivery.
Also, for performance reason, exact match protocol handler lists might be moved from ptype_base or
ptype_all to a per net_device list. That way, the list_for_each_entry_rcu() inside the loop could be
empty if no protocol handler bind on the current dev.
inside loop:
list_for_each_entry_rcu(ptype, dev->ptype_all, list) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
list_for_each_entry_rcu(ptype,
dev->ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
Outside loop :
list_for_each_entry_rcu(ptype, &ptype_all, list) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would require several changes into ptype_all and ptype_base handling, but should be faster.
quoted hunk
@@ -3167,7 +3167,7 @@ static int __netif_receive_skb(struct sk_buff *skb) ncls: #endif- rx_handler = rcu_dereference(skb->dev->rx_handler);+ rx_handler = rcu_dereference(dev->rx_handler); if (rx_handler) { if (pt_prev) { ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3176,6 +3176,8 @@ ncls: skb = rx_handler(skb); if (!skb) goto out;+ if (dev != skb->dev)
I would use "if (skb->dev != dev)" for clarity, because skb->dev is expected to have changed, not dev.
+ goto another_round;
}
if (vlan_tx_tag_present(skb)) {
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously
crossed device", while following the path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for
&ptype_all and for &ptype_base[ntohs(type) & PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type &&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
- if (ptype->type == type &&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type && !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-19 14:32:49
Le 19/02/2011 14:46, Jiri Pirko a écrit :
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
[snip]
quoted
Inside the loop, we should only do exact match delivery, for
&ptype_all and for&ptype_base[ntohs(type)& PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-19 20:27:43
Le 19/02/2011 14:46, Jiri Pirko a écrit :
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously
crossed device", while following the path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for
&ptype_all and for&ptype_base[ntohs(type)& PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
Here is what I have in mind. It is based on your previous DRAFT patch, and don't modify rx_handlers yet.
Only compile tested !!
I don't know if every pieces are at the right place. I wonder what to do with CONFIG_NET_CLS_ACT
part, that currently is between ptype_all and ptype_base processing.
Anyway, the general idea is there.
Nicolas.
net/core/dev.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 60 insertions(+), 10 deletions(-)
@@ -3192,16 +3225,33 @@ ncls:gotoout;}+/*+*FIXME:Can'tthisbemovedintotherx_handlerforbonding,+*orintoafuturrx_handlerforvlan?+*/+vlan_on_bond_hook(skb);-/* deliver only exact match when indicated */-null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;+/*+*Delivertowildcardptype_allprotocolhandlers.+*/++list_for_each_entry_rcu(ptype,&ptype_all,list){+if(!ptype->dev){+if(pt_prev)+ret=deliver_skb(skb,pt_prev,orig_dev);+pt_prev=ptype;+}+}++/*+*Delivertowildcardptype_allprotocolhandlers.+*/type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&-(ptype->dev==null_or_dev||ptype->dev==skb->dev)){+if(ptype->type==type&&!ptype->dev){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
Sat, Feb 19, 2011 at 09:27:37PM CET, nicolas.2p.debian@gmail.com wrote:
quoted hunk
Le 19/02/2011 14:46, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously
crossed device", while following the path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for
&ptype_all and for&ptype_base[ntohs(type)& PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
Here is what I have in mind. It is based on your previous DRAFT patch, and don't modify rx_handlers yet.
Only compile tested !!
I don't know if every pieces are at the right place. I wonder what to
do with CONFIG_NET_CLS_ACT part, that currently is between ptype_all
and ptype_base processing.
Anyway, the general idea is there.
Nicolas.
net/core/dev.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 60 insertions(+), 10 deletions(-)
orig_dev should be set at the end of the loop. Now you are going to have
it always the same as dev and skb->dev.
quoted hunk
dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
@@ -3152,8 +3150,13 @@ another_round:
}
#endif
+ /*
+ * Deliver to ptype_all protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
list_for_each_entry_rcu(ptype, &ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
@@ -3167,6 +3170,31 @@ another_round:
ncls:
#endif
+ /*
+ * Deliver to ptype_base protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
+ type = skb->protocol;
+ list_for_each_entry_rcu(ptype,
+ &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
+ if (ptype->type == type && ptype->dev == skb->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
I'm not sure it is ok to deliver ptype_base here. See comment above
ptype_head() (I'm not sure I understand that correctly)
+
+ /*
+ * Call rx_handler for current device.
+ * If rx_handler return NULL, skip wilcard protocol handler delivery.
+ * Else, if skb->dev changed, restart the whole delivery process, to
+ * allow for device nesting.
+ *
+ * Warning:
+ * rx_handlers must kfree_skb(skb) if they return NULL.
Well this is not true. They can return NULL and call netif_rx as they
have before. No changes necessary I believe.
quoted hunk
+ */
+
rx_handler = rcu_dereference(dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3176,10 +3204,15 @@ ncls:
skb = rx_handler(skb);
if (!skb)
goto out;
- if (dev != skb->dev)
+ if (skb->dev != dev)
goto another_round;
}
+ /*
+ * FIXME: The part below should use rx_handler instead of being hard
+ * coded here.
I'm not sure it is doable atm. For bridge and bond it should not be a
problem, but for macvlan, there is possible to have macvlans and vlans
on the same dev. This possibility should persist.
/me scratches head on the idea to have multiple rx_handlers although it
was his original idea....
quoted hunk
+ */
+
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3192,16 +3225,33 @@ ncls:
goto out;
}
+ /*
+ * FIXME: Can't this be moved into the rx_handler for bonding,
+ * or into a futur rx_handler for vlan?
This hook is something I do not like at all :/ But anyway if should be in vlan
part I think.
+ */
+
vlan_on_bond_hook(skb);
- /* deliver only exact match when indicated */
- null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
+
+ list_for_each_entry_rcu(ptype, &ptype_all, list) {
+ if (!ptype->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
+
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
- if (ptype->type == type &&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type && !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
--
1.7.2.3
From: Nicolas de Pesloüan <hidden> Date: 2011-02-20 12:12:05
Le 20/02/2011 11:36, Jiri Pirko a écrit :
Sat, Feb 19, 2011 at 09:27:37PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 14:46, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously
crossed device", while following the path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for
&ptype_all and for&ptype_base[ntohs(type)& PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
Here is what I have in mind. It is based on your previous DRAFT patch, and don't modify rx_handlers yet.
Only compile tested !!
I don't know if every pieces are at the right place. I wonder what to
do with CONFIG_NET_CLS_ACT part, that currently is between ptype_all
and ptype_base processing.
Anyway, the general idea is there.
Nicolas.
net/core/dev.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 60 insertions(+), 10 deletions(-)
orig_dev should be set at the end of the loop. Now you are going to have
it always the same as dev and skb->dev.
Yes, you are right.
I thinking about all this, I wonder what the protocol handlers expect as the orig_dev value ?
Lest imagine the following configuration: eth0 -> bond0 -> br0.
What does a protocol handler listening on br0 expect for orig_dev ? bond0 or eth0 ? Current
implementation give eth0, but I think bond0 should be the right value, for proper nesting.
quoted
dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
@@ -3152,8 +3150,13 @@ another_round:
}
#endif
+ /*
+ * Deliver to ptype_all protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
@@ -3167,6 +3170,31 @@ another_round:
ncls:
#endif
+ /*
+ * Deliver to ptype_base protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
+ type = skb->protocol;
+ list_for_each_entry_rcu(ptype,
+ &ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
+ if (ptype->type == type&& ptype->dev == skb->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
I'm not sure it is ok to deliver ptype_base here. See comment above
ptype_head() (I'm not sure I understand that correctly)
Anyway, all this is probably plain wrong: Delivering the skb to protocol handlers while still
changing the skb is guaranteed to cause strange behaviors.
If we want to be able to deliver the skb to different protocol handlers and give all of them the
right values for dev->skb and orig_dev (or previous_dev), we might end up with copying the skb. I
hate the idea, but currently can't find a cleaner way to do so.
We first need to clarify what orig_dev should be, as stated above.
quoted
+
+ /*
+ * Call rx_handler for current device.
+ * If rx_handler return NULL, skip wilcard protocol handler delivery.
+ * Else, if skb->dev changed, restart the whole delivery process, to
+ * allow for device nesting.
+ *
+ * Warning:
+ * rx_handlers must kfree_skb(skb) if they return NULL.
Well this is not true. They can return NULL and call netif_rx as they
have before. No changes necessary I believe.
I don't really know. This needs to be double checked, anyway.
quoted
+ */
+
rx_handler = rcu_dereference(dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3176,10 +3204,15 @@ ncls:
skb = rx_handler(skb);
if (!skb)
goto out;
- if (dev != skb->dev)
+ if (skb->dev != dev)
goto another_round;
}
+ /*
+ * FIXME: The part below should use rx_handler instead of being hard
+ * coded here.
I'm not sure it is doable atm. For bridge and bond it should not be a
problem, but for macvlan, there is possible to have macvlans and vlans
on the same dev. This possibility should persist.
/me scratches head on the idea to have multiple rx_handlers although it
was his original idea....
I think your original proposal of having several rx_handlers per device was right.
At the time you introduced the rx_handler system, only bridge and macvlan used it. Even if using
bridge and macvlan on the same base device might be useless, this is not true for every possible
rx_handler configuration.
Now that we want to move bonding and vlan to the rx_handler system, it becomes obvious that we need
several rx_handlers per device. At least, vlan should properly mix with bridge. And who know what
would be the fifth rx_handler...
quoted
+ */
+
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3192,16 +3225,33 @@ ncls:
goto out;
}
+ /*
+ * FIXME: Can't this be moved into the rx_handler for bonding,
+ * or into a futur rx_handler for vlan?
This hook is something I do not like at all :/ But anyway if should be in vlan
part I think.
Yes, and in order for the future rx_handler for vlan to properly handle it, it needs to know the
device just below it, not the pure original device. Hence, my question about the exact meaning of
orig_dev...
Nicolas.
quoted
+ */
+
vlan_on_bond_hook(skb);
- /* deliver only exact match when indicated */
- null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
+
+ list_for_each_entry_rcu(ptype,&ptype_all, list) {
+ if (!ptype->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
+
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
--
1.7.2.3
Sun, Feb 20, 2011 at 01:12:01PM CET, nicolas.2p.debian@gmail.com wrote:
Le 20/02/2011 11:36, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 09:27:37PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 14:46, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 02:18:00PM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 12:28, Jiri Pirko a écrit :
quoted
Sat, Feb 19, 2011 at 12:08:31PM CET, jpirko@redhat.com wrote:
quoted
Sat, Feb 19, 2011 at 11:56:23AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 19/02/2011 09:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
set orig_dev = skb->dev if skb_iif is set
Why do we need to let the rx_handlers call netif_rx() or __netif_receive_skb()?
Bonding used to be handled with very few overhead, simply replacing
skb->dev with skb->dev->master. Time has passed and we eventually
added many special processing for bonding into __netif_receive_skb(),
but the overhead remained very light.
Calling netif_rx() (or __netif_receive_skb()) to allow nesting would probably lead to some overhead.
Can't we, instead, loop inside __netif_receive_skb(), and deliver
whatever need to be delivered, to whoever need, inside the loop ?
rx_handler = rcu_dereference(skb->dev->rx_handler);
while (rx_handler) {
/* ... */
orig_dev = skb->dev;
skb = rx_handler(skb);
/* ... */
rx_handler = (skb->dev != orig_dev) ? rcu_dereference(skb->dev->rx_handler) : NULL;
}
This would reduce the overhead, while still allowing nesting: vlan on
top on bonding, bridge on top on bonding, ...
I see your point. Makes sense to me. But the loop would have to include
at least processing of ptype_all too. I'm going to cook a follow-up
patch.
@@ -3115,6 +3115,7 @@ static int __netif_receive_skb(struct sk_buff *skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;+structnet_device*dev;structnet_device*orig_dev;structnet_device*null_or_dev;intret=NET_RX_DROP;
@@ -3129,7 +3130,9 @@ static int __netif_receive_skb(struct sk_buff *skb)if(netpoll_receive_skb(skb))returnNET_RX_DROP;-__this_cpu_inc(softnet_data.processed);+skb->skb_iif=skb->dev->ifindex;+orig_dev=skb->dev;
orig_dev should be set inside the loop, to reflect "previously
crossed device", while following the path:
eth0 -> bond0 -> br0.
First step inside loop:
orig_dev = eth0
skb->dev = bond0 (at the end of the loop).
Second step inside loop:
orig_dev = bond0
skb->dev = br0 (et the end of the loop).
This would allow for exact match delivery to bond0 if someone bind there.
+another_round:
+ __this_cpu_inc(softnet_data.processed);
+ dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
if (skb->tc_verd& TC_NCLS) {
@@ -3153,7 +3153,7 @@ static int __netif_receive_skb(struct sk_buff *skb) #endif list_for_each_entry_rcu(ptype,&ptype_all, list) {- if (!ptype->dev || ptype->dev == skb->dev) {+ if (!ptype->dev || ptype->dev == dev) { if (pt_prev) ret = deliver_skb(skb, pt_prev, orig_dev); pt_prev = ptype;
Inside the loop, we should only do exact match delivery, for
&ptype_all and for&ptype_base[ntohs(type)& PTYPE_HASH_MASK]:
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ (ptype->dev == skb->dev)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
After leaving the loop, we can do wilcard delivery, if skb is not NULL.
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (!ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
}
}
This would reduce the number of tests inside the
list_for_each_entry_rcu() loops. And because we match only ptype->dev
== dev inside the loop and !ptype->dev outside the loop, this should
avoid duplicate delivery.
Would you care to put this into patch so I can see the whole picture?
Thanks.
Here is what I have in mind. It is based on your previous DRAFT patch, and don't modify rx_handlers yet.
Only compile tested !!
I don't know if every pieces are at the right place. I wonder what to
do with CONFIG_NET_CLS_ACT part, that currently is between ptype_all
and ptype_base processing.
Anyway, the general idea is there.
Nicolas.
net/core/dev.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 60 insertions(+), 10 deletions(-)
orig_dev should be set at the end of the loop. Now you are going to have
it always the same as dev and skb->dev.
Yes, you are right.
I thinking about all this, I wonder what the protocol handlers expect as the orig_dev value ?
Lest imagine the following configuration: eth0 -> bond0 -> br0.
What does a protocol handler listening on br0 expect for orig_dev ?
bond0 or eth0 ? Current implementation give eth0, but I think bond0
should be the right value, for proper nesting.
I agree with you.
quoted
quoted
dev = skb->dev;
#ifdef CONFIG_NET_CLS_ACT
@@ -3152,8 +3150,13 @@ another_round:
}
#endif
+ /*
+ * Deliver to ptype_all protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
list_for_each_entry_rcu(ptype,&ptype_all, list) {
- if (!ptype->dev || ptype->dev == dev) {
+ if (ptype->dev == dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
@@ -3167,6 +3170,31 @@ another_round:
ncls:
#endif
+ /*
+ * Deliver to ptype_base protocol handlers that match current dev.
+ * This happens before rx_handler is given a chance to change skb->dev.
+ */
+
+ type = skb->protocol;
+ list_for_each_entry_rcu(ptype,
+ &ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
+ if (ptype->type == type&& ptype->dev == skb->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
I'm not sure it is ok to deliver ptype_base here. See comment above
ptype_head() (I'm not sure I understand that correctly)
Anyway, all this is probably plain wrong: Delivering the skb to
protocol handlers while still changing the skb is guaranteed to cause
strange behaviors.
If we want to be able to deliver the skb to different protocol
handlers and give all of them the right values for dev->skb and
orig_dev (or previous_dev), we might end up with copying the skb. I
hate the idea, but currently can't find a cleaner way to do so.
That would be unfortunate :/
We first need to clarify what orig_dev should be, as stated above.
quoted
quoted
+
+ /*
+ * Call rx_handler for current device.
+ * If rx_handler return NULL, skip wilcard protocol handler delivery.
+ * Else, if skb->dev changed, restart the whole delivery process, to
+ * allow for device nesting.
+ *
+ * Warning:
+ * rx_handlers must kfree_skb(skb) if they return NULL.
Well this is not true. They can return NULL and call netif_rx as they
have before. No changes necessary I believe.
I don't really know. This needs to be double checked, anyway.
quoted
quoted
+ */
+
rx_handler = rcu_dereference(dev->rx_handler);
if (rx_handler) {
if (pt_prev) {
@@ -3176,10 +3204,15 @@ ncls:
skb = rx_handler(skb);
if (!skb)
goto out;
- if (dev != skb->dev)
+ if (skb->dev != dev)
goto another_round;
}
+ /*
+ * FIXME: The part below should use rx_handler instead of being hard
+ * coded here.
I'm not sure it is doable atm. For bridge and bond it should not be a
problem, but for macvlan, there is possible to have macvlans and vlans
on the same dev. This possibility should persist.
/me scratches head on the idea to have multiple rx_handlers although it
was his original idea....
I think your original proposal of having several rx_handlers per device was right.
At the time you introduced the rx_handler system, only bridge and
macvlan used it. Even if using bridge and macvlan on the same base
device might be useless, this is not true for every possible
rx_handler configuration.
Now that we want to move bonding and vlan to the rx_handler system,
it becomes obvious that we need several rx_handlers per device. At
least, vlan should properly mix with bridge. And who know what would
be the fifth rx_handler...
quoted
quoted
+ */
+
if (vlan_tx_tag_present(skb)) {
if (pt_prev) {
ret = deliver_skb(skb, pt_prev, orig_dev);
@@ -3192,16 +3225,33 @@ ncls:
goto out;
}
+ /*
+ * FIXME: Can't this be moved into the rx_handler for bonding,
+ * or into a futur rx_handler for vlan?
This hook is something I do not like at all :/ But anyway if should be in vlan
part I think.
Yes, and in order for the future rx_handler for vlan to properly
handle it, it needs to know the device just below it, not the pure
original device. Hence, my question about the exact meaning of
orig_dev...
Nicolas.
quoted
quoted
+ */
+
vlan_on_bond_hook(skb);
- /* deliver only exact match when indicated */
- null_or_dev = skb->deliver_no_wcard ? skb->dev : NULL;
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
+
+ list_for_each_entry_rcu(ptype,&ptype_all, list) {
+ if (!ptype->dev) {
+ if (pt_prev)
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = ptype;
+ }
+ }
+
+ /*
+ * Deliver to wildcard ptype_all protocol handlers.
+ */
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type)& PTYPE_HASH_MASK], list) {
- if (ptype->type == type&&
- (ptype->dev == null_or_dev || ptype->dev == skb->dev)) {
+ if (ptype->type == type&& !ptype->dev) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
--
1.7.2.3
From: Nicolas de Pesloüan <hidden> Date: 2011-02-21 23:20:09
Le 20/02/2011 16:07, Jiri Pirko a écrit :
Sun, Feb 20, 2011 at 01:12:01PM CET, nicolas.2p.debian@gmail.com wrote:
[snip]
quoted
And thinking about all this, I wonder what the protocol handlers expect as the orig_dev value ?
Lets imagine the following configuration: eth0 -> bond0 -> br0.
What does a protocol handler listening on br0 expect for orig_dev ?
bond0 or eth0 ? Current implementation give eth0, but I think bond0
should be the right value, for proper nesting.
I agree with you.
[snip}
quoted
quoted
This hook is something I do not like at all :/ But anyway if should be in vlan
part I think.
Yes, and in order for the future rx_handler for vlan to properly
handle it, it needs to know the device just below it, not the pure
original device. Hence, my question about the exact meaning of
orig_dev...
After checking every protocol handlers installed by dev_add_pack(), it appears that only 4 of them
really use the orig_dev parameter given by __netif_receive_skb():
- bond_3ad_lacpdu_recv() @ drivers/net/bonding/bond_3ad.c
- bond_arp_recv() @ drivers/net/bonding/bond_main.c
- packet_rcv() @ net/packet/af_packet.c
- tpacket_rcv() @ net/packet/af_packet.c
From the bonding point of view, the meaning of orig_dev is obviously "the device one layer below
the bonding device, through which the packet reached the bonding device". It is used by
bond_3ad_lacpdu_recv() and bond_arp_recv(), to find the underlying slave device through which the
LACPDU or ARP was received. (The protocol handler is registered at the bonding device level).
From the af_packet point of view, the meaning is documented (in commit "[AF_PACKET]: Add option to
return orig_dev to userspace") as the "physical device [that] actually received the traffic, instead
of having the encapsulating device hide that information."
When the bonding device is just one level above the physical device, the two meanings happen to
match the same device, by chance.
So, currently, a bonding device cannot stack properly on top of anything but physical devices. It
might not be a problem today, but may change in the future...
Nicolas.
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko <redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/bonding/bond_main.c | 74 ++++++++++++++++++++++++-
net/core/dev.c | 119 ++++++++++-----------------------------
2 files changed, 104 insertions(+), 89 deletions(-)
@@ -1423,6 +1423,67 @@ static void bond_setup_by_slave(struct net_device *bond_dev,bond->setup_by_slave=1;}+/* On bonding slaves other than the currently active slave, suppress+*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and+*ARPonactive-backupslaveswitharp_validateenabled.+*/+staticboolbond_should_deliver_exact_match(structsk_buff*skb,+structnet_device*slave_dev,+structnet_device*bond_dev)+{+if(slave_dev->priv_flags&IFF_SLAVE_INACTIVE){+if(slave_dev->priv_flags&IFF_SLAVE_NEEDARP&&+skb->protocol==__cpu_to_be16(ETH_P_ARP))+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+skb->pkt_type!=PACKET_BROADCAST&&+skb->pkt_type!=PACKET_MULTICAST)+returnfalse;++if(bond_dev->priv_flags&IFF_MASTER_8023AD&&+skb->protocol==__cpu_to_be16(ETH_P_SLOW))+returnfalse;++returntrue;+}+returnfalse;+}++staticstructsk_buff*bond_handle_frame(structsk_buff*skb)+{+structnet_device*slave_dev;+structnet_device*bond_dev;++skb=skb_share_check(skb,GFP_ATOMIC);+if(unlikely(!skb))+returnNULL;+slave_dev=skb->dev;+bond_dev=ACCESS_ONCE(slave_dev->master);+if(unlikely(!bond_dev))+returnskb;++if(bond_dev->priv_flags&IFF_MASTER_ARPMON)+slave_dev->last_rx=jiffies;++if(bond_should_deliver_exact_match(skb,slave_dev,bond_dev)){+skb->deliver_no_wcard=1;+returnskb;+}++skb->dev=bond_dev;++if(bond_dev->priv_flags&IFF_MASTER_ALB&&+bond_dev->priv_flags&IFF_BRIDGE_PORT&&+skb->pkt_type==PACKET_HOST){+u16*dest=(u16*)eth_hdr(skb)->h_dest;++memcpy(dest,bond_dev->dev_addr,ETH_ALEN);+}++returnskb;+}+/* enslave device <slave> to bond device <master> */intbond_enslave(structnet_device*bond_dev,structnet_device*slave_dev){
@@ -1599,11 +1660,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)pr_debug("Error %d calling netdev_set_bond_master\n",res);gotoerr_restore_mac;}+res=netdev_rx_handler_register(slave_dev,bond_handle_frame,NULL);+if(res){+pr_debug("Error %d calling netdev_rx_handler_register\n",res);+gotoerr_unset_master;+}+/* open the slave since the application closed it */res=dev_open(slave_dev);if(res){pr_debug("Opening slave %s failed\n",slave_dev->name);-gotoerr_unset_master;+gotoerr_unreg_rxhandler;}new_slave->dev=slave_dev;
@@ -2114,6 +2185,7 @@ static int bond_release_all(struct net_device *bond_dev)netif_addr_unlock_bh(bond_dev);}+netdev_rx_handler_unregister(slave_dev);netdev_set_bond_master(slave_dev,NULL);/* close slave before restoring its mac address */
@@ -3096,63 +3096,31 @@ void netdev_rx_handler_unregister(struct net_device *dev)}EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);-staticinlinevoidskb_bond_set_mac_by_master(structsk_buff*skb,-structnet_device*master)+staticvoidvlan_on_bond_hook(structsk_buff*skb){-if(skb->pkt_type==PACKET_HOST){-u16*dest=(u16*)eth_hdr(skb)->h_dest;+/*+*MakesureARPframesreceivedonVLANinterfacesstackedon+*bondinginterfacesstillmaketheirwaytoanybasebonding+*devicethatmayhaveregisteredforaspecificptype.+*/+if(skb->dev->priv_flags&IFF_802_1Q_VLAN&&+vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING&&+skb->protocol==htons(ETH_P_ARP)){+structsk_buff*skb2=skb_clone(skb,GFP_ATOMIC);-memcpy(dest,master->dev_addr,ETH_ALEN);+if(!skb2)+return;+skb2->dev=vlan_dev_real_dev(skb->dev);+netif_rx(skb2);}}-/* On bonding slaves other than the currently active slave, suppress-*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and-*ARPonactive-backupslaveswitharp_validateenabled.-*/-staticint__skb_bond_should_drop(structsk_buff*skb,-structnet_device*master)-{-structnet_device*dev=skb->dev;--if(master->priv_flags&IFF_MASTER_ARPMON)-dev->last_rx=jiffies;--if((master->priv_flags&IFF_MASTER_ALB)&&-(master->priv_flags&IFF_BRIDGE_PORT)){-/* Do address unmangle. The local destination address-*willbealwaystheonemasterhas.Providestheright-*functionalityinabridge.-*/-skb_bond_set_mac_by_master(skb,master);-}--if(dev->priv_flags&IFF_SLAVE_INACTIVE){-if((dev->priv_flags&IFF_SLAVE_NEEDARP)&&-skb->protocol==__cpu_to_be16(ETH_P_ARP))-return0;--if(master->priv_flags&IFF_MASTER_ALB){-if(skb->pkt_type!=PACKET_BROADCAST&&-skb->pkt_type!=PACKET_MULTICAST)-return0;-}-if(master->priv_flags&IFF_MASTER_8023AD&&-skb->protocol==__cpu_to_be16(ETH_P_SLOW))-return0;--return1;-}-return0;-}-staticint__netif_receive_skb(structsk_buff*skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;structnet_device*orig_dev;-structnet_device*null_or_orig;-structnet_device*orig_or_bond;+structnet_device*null_or_dev;intret=NET_RX_DROP;__be16type;
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)if(!skb->skb_iif)skb->skb_iif=skb->dev->ifindex;--/*-*bondingnote:skbsreceivedoninactiveslavesshouldonly-*bedeliveredtopkthandlersthatareexactmatches.Also-*thedeliver_no_wcardflagwillbeset.Ifpackethandlers-*aresensitivetoduplicatepacketstheseskbswillneedto-*bedroppedatthehandler.-*/-null_or_orig=NULL;orig_dev=skb->dev;-if(skb->deliver_no_wcard)-null_or_orig=orig_dev;-elseif(netif_is_bond_slave(orig_dev)){-structnet_device*bond_master=ACCESS_ONCE(orig_dev->master);--if(likely(bond_master)){-if(__skb_bond_should_drop(skb,bond_master)){-skb->deliver_no_wcard=1;-/* deliver only exact match */-null_or_orig=orig_dev;-}else-skb->dev=bond_master;-}-}-__this_cpu_inc(softnet_data.processed);skb_reset_network_header(skb);skb_reset_transport_header(skb);skb->mac_len=skb->network_header-skb->mac_header;
@@ -3201,6 +3145,10 @@ static int __netif_receive_skb(struct sk_buff *skb)rcu_read_lock();+another_round:++__this_cpu_inc(softnet_data.processed);+#ifdef CONFIG_NET_CLS_ACTif(skb->tc_verd&TC_NCLS){skb->tc_verd=CLR_TC_NCLS(skb->tc_verd);
@@ -3209,8 +3157,7 @@ static int __netif_receive_skb(struct sk_buff *skb)#endiflist_for_each_entry_rcu(ptype,&ptype_all,list){-if(ptype->dev==null_or_orig||ptype->dev==skb->dev||-ptype->dev==orig_dev){+if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
@@ -3224,16 +3171,20 @@ static int __netif_receive_skb(struct sk_buff *skb)ncls:#endif-/* Handle special case of bridge or macvlan */rx_handler=rcu_dereference(skb->dev->rx_handler);if(rx_handler){+structnet_device*prev_dev;+if(pt_prev){ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=NULL;}+prev_dev=skb->dev;skb=rx_handler(skb);if(!skb)gotoout;+if(skb->dev!=prev_dev)+gotoanother_round;}if(vlan_tx_tag_present(skb)){
@@ -3248,24 +3199,16 @@ ncls:gotoout;}-/*-*MakesureframesreceivedonVLANinterfacesstackedon-*bondinginterfacesstillmaketheirwaytoanybasebonding-*devicethatmayhaveregisteredforaspecificptype.The-*handlermayhavetoadjustskb->devandorig_dev.-*/-orig_or_bond=orig_dev;-if((skb->dev->priv_flags&IFF_802_1Q_VLAN)&&-(vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING)){-orig_or_bond=vlan_dev_real_dev(skb->dev);-}+vlan_on_bond_hook(skb);++/* deliver only exact match when indicated */+null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&(ptype->dev==null_or_orig||-ptype->dev==skb->dev||ptype->dev==orig_dev||-ptype->dev==orig_or_bond)){+if(ptype->type==type&&+(ptype->dev==null_or_dev||ptype->dev==skb->dev)){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
From: Nicolas de Pesloüan <hidden> Date: 2011-02-25 23:47:03
Le 23/02/2011 20:05, Jiri Pirko a écrit :
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Hi Jiri,
Eventually taking enough time for a review.
I think we should split this change :
1/ Change __netif_receive_skb() to call rx_handler for diverted net_device, until rx_handler is NULL.
2/ Convert currently existing rx_handlers (bridge and macvlan) to use this new "loop" feature,
removing the need to call netif_rx() inside their respective rx_handler and also removing the
associated overhead.
3/ Convert bonding to use rx_handlers.
Also, on step 1, we definitely need to clarify what orig_dev should be.
I now think that orig_dev should be "the device one level below the current one" or NULL if current
device was not diverted from another one. It means that we should keep an array of crossed
(diverted) devices and the associated orig_dev. This array would be used to pass the right orig_dev
to protocol handlers, depending on the device they register on :
eth0 -> bond0 -> br0
A protocol handler registered on bond0 would receive eth0 as orig_dev.
A protocol handler registered on br0 would receive bond0 as orig_dev.
[snip]
quoted hunk
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
Why do you loop to ptype_all before calling rx_handler ?
I don't understand why ptype_all and ptype_base are not handled at the same place in current
__netif_receive_skb() but I think we should take the opportunity to change that, unless someone know
of a good reason not to do so.
- /* Handle special case of bridge or macvlan */
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
Sat, Feb 26, 2011 at 12:46:53AM CET, nicolas.2p.debian@gmail.com wrote:
Le 23/02/2011 20:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Hi Jiri,
Eventually taking enough time for a review.
I think we should split this change :
1/ Change __netif_receive_skb() to call rx_handler for diverted net_device, until rx_handler is NULL.
2/ Convert currently existing rx_handlers (bridge and macvlan) to use
this new "loop" feature, removing the need to call netif_rx() inside
their respective rx_handler and also removing the associated
overhead.
This might not be possible. Macvlan uses result of called netif_rx for
counting, bridge calls netdev_receive_skb via NF_HOOK. Nevertheless,
this can be eventually handled later, not as a part of this patch.
3/ Convert bonding to use rx_handlers.
Also, on step 1, we definitely need to clarify what orig_dev should be.
I now think that orig_dev should be "the device one level below the
current one" or NULL if current device was not diverted from another
one. It means that we should keep an array of crossed (diverted)
devices and the associated orig_dev. This array would be used to pass
the right orig_dev to protocol handlers, depending on the device they
register on :
I constructed the patch in the way origdev is the same in all situations
as before the patch. I think that this decision can be ommitted at the
moment.
eth0 -> bond0 -> br0
A protocol handler registered on bond0 would receive eth0 as orig_dev.
A protocol handler registered on br0 would receive bond0 as orig_dev.
[snip]
quoted
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
Why do you loop to ptype_all before calling rx_handler ?
I don't understand why ptype_all and ptype_base are not handled at
the same place in current __netif_receive_skb() but I think we should
take the opportunity to change that, unless someone know of a good
reason not to do so.
Again, the patch tries to do as little changes as it can. So this stays
the same as before. In case you want to change it, feel free to submit
patch doing that as follow-on.
quoted
- /* Handle special case of bridge or macvlan */
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
From: Nicolas de Pesloüan <hidden> Date: 2011-02-26 11:25:22
Le 26/02/2011 08:14, Jiri Pirko a écrit :
Sat, Feb 26, 2011 at 12:46:53AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 23/02/2011 20:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Hi Jiri,
Eventually taking enough time for a review.
I think we should split this change :
1/ Change __netif_receive_skb() to call rx_handler for diverted net_device, until rx_handler is NULL.
2/ Convert currently existing rx_handlers (bridge and macvlan) to use
this new "loop" feature, removing the need to call netif_rx() inside
their respective rx_handler and also removing the associated
overhead.
This might not be possible. Macvlan uses result of called netif_rx for
counting, bridge calls netdev_receive_skb via NF_HOOK. Nevertheless,
this can be eventually handled later, not as a part of this patch.
Yes, I agree. Step 2 and step 3 can be swapped.
Anyway, we need to describe the options given to a rx_handler:
- Return skb unchanged. This would cause normal delivery (ptype->dev == NULL or ptype->dev == skb->dev).
- Return skb->dev changed. __netif_receive_skb() will loop to the new device. This would cause
extact match delivery only (ptype->dev != NULL and ptype->dev == one of the orig_dev).
- Manage the skb another way and return NULL. This would stop any protocol handlers to receive the
skb, except if the rx_handler arrange to re-inject the skb somewhere.
quoted
3/ Convert bonding to use rx_handlers.
Also, on step 1, we definitely need to clarify what orig_dev should be.
I now think that orig_dev should be "the device one level below the
current one" or NULL if current device was not diverted from another
one. It means that we should keep an array of crossed (diverted)
devices and the associated orig_dev. This array would be used to pass
the right orig_dev to protocol handlers, depending on the device they
register on :
I constructed the patch in the way origdev is the same in all situations
as before the patch. I think that this decision can be ommitted at the
moment.
Agreed, event if the current handling of orig_dev is far from bullet proof and needs to be clarified
at some time.
quoted
eth0 -> bond0 -> br0
A protocol handler registered on bond0 would receive eth0 as orig_dev.
A protocol handler registered on br0 would receive bond0 as orig_dev.
[snip]
quoted
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
Why do you loop to ptype_all before calling rx_handler ?
I don't understand why ptype_all and ptype_base are not handled at
the same place in current __netif_receive_skb() but I think we should
take the opportunity to change that, unless someone know of a good
reason not to do so.
Again, the patch tries to do as little changes as it can. So this stays
the same as before. In case you want to change it, feel free to submit
patch doing that as follow-on.
The point here is that bridge and macvlan handling used to be after the ptype_all loop (hence the
place you inserted the call to rx_handler last summer), but the bonding part is currently before the
ptype_all loop.
Moving bonding handling after the ptype_all loop will cause the ptype_all loop to be run twice:
- first time, with skb->dev == eth0 and orig_dev == eth0.
- second time, with skb->dev == bond0 and orig_dev == eth0.
The first time currently does not exists. And because bonding wasn't given a chance yet to decide
that the frame should be dropped, the packet will always be delivered to eth0, causing duplicate
deliveries. Note that this is probably true for bridge and macvlan too, and that those duplicate
deliveries probably already exists.
Also, delivering skb inside a loop that may change the skb (skb->dev at least) is guaranteed to
produce strange behaviors.
Can someone, knowing the history of ptype_all/ptype_base/bridge/macvlan/bonding/vlan handling in
__netif_receive_skb(), comment on this?
Are there any reasons not to process ptype_all and ptype_base at the same location, at the end of
__netif_receive_skb(), and to manage all divert features (bridge/macvlan/bonding/vlan) before?
Nicolas.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-26 14:24:26
Le 22/02/2011 00:20, Nicolas de Pesloüan a écrit :
After checking every protocol handlers installed by dev_add_pack(), it
appears that only 4 of them really use the orig_dev parameter given by
__netif_receive_skb():
- bond_3ad_lacpdu_recv() @ drivers/net/bonding/bond_3ad.c
- bond_arp_recv() @ drivers/net/bonding/bond_main.c
- packet_rcv() @ net/packet/af_packet.c
- tpacket_rcv() @ net/packet/af_packet.c
From the bonding point of view, the meaning of orig_dev is obviously
"the device one layer below the bonding device, through which the packet
reached the bonding device". It is used by bond_3ad_lacpdu_recv() and
bond_arp_recv(), to find the underlying slave device through which the
LACPDU or ARP was received. (The protocol handler is registered at the
bonding device level).
From the af_packet point of view, the meaning is documented (in commit
"[AF_PACKET]: Add option to return orig_dev to userspace") as the
"physical device [that] actually received the traffic, instead of having
the encapsulating device hide that information."
When the bonding device is just one level above the physical device, the
two meanings happen to match the same device, by chance.
So, currently, a bonding device cannot stack properly on top of anything
but physical devices. It might not be a problem today, but may change in
the future...
Hi Jay,
Still thinking about this orig_dev stuff, I wonder why the protocol handlers used in bonding
(bond_3ad_lacpdu_recv() and bond_arp_rcv()) are registered at the master level instead of at the
slave level ?
If they were registered at the slave level, they would simply receive skb->dev as the ingress
interface and use this value instead of needing the orig_dev value given to them when they are
registered at the master level.
As orig_dev is only used by bonding and by af_packet, but they disagree on the exact meaning of
orig_dev, one way to fix this discrepancy would be to remove one of the usage. As the af_packet
usage is exposed to user space, bonding seems the right place to stop using orig_dev, even if
orig_dev was introduced for bonding :-)
I understand that this would add one entry per slave device to the ptype_base list, but this seems
to be the only bad effect of registering at the slave level. Can you confirm that this was the
reason to register at the master level instead?
If you think registering at the slave level would cause too much impact on ptype_base, then we might
have another way to stop using orig_dev for bonding:
In __skb_bond_should_drop(), we already test for the two interesting protocols:
if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && skb->protocol == __cpu_to_be16(ETH_P_ARP))
return 0;
if (master->priv_flags & IFF_MASTER_8023AD && skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return 0;
Would it be possible to call the right handlers directly from inside __skb_bond_should_drop() then
let __skb_bond_should_drop() return 1 ("should drop") after processing the frames that are only of
interest for bonding?
Nicolas.
Sat, Feb 26, 2011 at 12:25:18PM CET, nicolas.2p.debian@gmail.com wrote:
Le 26/02/2011 08:14, Jiri Pirko a écrit :
quoted
Sat, Feb 26, 2011 at 12:46:53AM CET, nicolas.2p.debian@gmail.com wrote:
quoted
Le 23/02/2011 20:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Hi Jiri,
Eventually taking enough time for a review.
I think we should split this change :
1/ Change __netif_receive_skb() to call rx_handler for diverted net_device, until rx_handler is NULL.
2/ Convert currently existing rx_handlers (bridge and macvlan) to use
this new "loop" feature, removing the need to call netif_rx() inside
their respective rx_handler and also removing the associated
overhead.
This might not be possible. Macvlan uses result of called netif_rx for
counting, bridge calls netdev_receive_skb via NF_HOOK. Nevertheless,
this can be eventually handled later, not as a part of this patch.
Yes, I agree. Step 2 and step 3 can be swapped.
Anyway, we need to describe the options given to a rx_handler:
- Return skb unchanged. This would cause normal delivery (ptype->dev == NULL or ptype->dev == skb->dev).
- Return skb->dev changed. __netif_receive_skb() will loop to the new
device. This would cause extact match delivery only (ptype->dev !=
NULL and ptype->dev == one of the orig_dev).
- Manage the skb another way and return NULL. This would stop any
protocol handlers to receive the skb, except if the rx_handler
arrange to re-inject the skb somewhere.
quoted
quoted
3/ Convert bonding to use rx_handlers.
Also, on step 1, we definitely need to clarify what orig_dev should be.
I now think that orig_dev should be "the device one level below the
current one" or NULL if current device was not diverted from another
one. It means that we should keep an array of crossed (diverted)
devices and the associated orig_dev. This array would be used to pass
the right orig_dev to protocol handlers, depending on the device they
register on :
I constructed the patch in the way origdev is the same in all situations
as before the patch. I think that this decision can be ommitted at the
moment.
Agreed, event if the current handling of orig_dev is far from bullet
proof and needs to be clarified at some time.
quoted
quoted
eth0 -> bond0 -> br0
A protocol handler registered on bond0 would receive eth0 as orig_dev.
A protocol handler registered on br0 would receive bond0 as orig_dev.
[snip]
quoted
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)
Why do you loop to ptype_all before calling rx_handler ?
I don't understand why ptype_all and ptype_base are not handled at
the same place in current __netif_receive_skb() but I think we should
take the opportunity to change that, unless someone know of a good
reason not to do so.
Again, the patch tries to do as little changes as it can. So this stays
the same as before. In case you want to change it, feel free to submit
patch doing that as follow-on.
The point here is that bridge and macvlan handling used to be after
the ptype_all loop (hence the place you inserted the call to
rx_handler last summer), but the bonding part is currently before the
ptype_all loop.
Moving bonding handling after the ptype_all loop will cause the ptype_all loop to be run twice:
- first time, with skb->dev == eth0 and orig_dev == eth0.
- second time, with skb->dev == bond0 and orig_dev == eth0.
The first time currently does not exists. And because bonding wasn't
given a chance yet to decide that the frame should be dropped, the
packet will always be delivered to eth0, causing duplicate
deliveries. Note that this is probably true for bridge and macvlan
too, and that those duplicate deliveries probably already exists.
Yes, and in fact that was what I like about this patch, that then
deliveries are simillar to bridge.
Also, delivering skb inside a loop that may change the skb (skb->dev
at least) is guaranteed to produce strange behaviors.
Can someone, knowing the history of
ptype_all/ptype_base/bridge/macvlan/bonding/vlan handling in
__netif_receive_skb(), comment on this?
Are there any reasons not to process ptype_all and ptype_base at the
same location, at the end of __netif_receive_skb(), and to manage all
divert features (bridge/macvlan/bonding/vlan) before?
That is very good set of questions. Would like to hear answers too.
From: Jay Vosburgh <hidden> Date: 2011-02-26 19:43:04
Nicolas de Pesloüan [off-list ref] wrote:
Le 22/02/2011 00:20, Nicolas de Pesloüan a écrit :
quoted
After checking every protocol handlers installed by dev_add_pack(), it
appears that only 4 of them really use the orig_dev parameter given by
__netif_receive_skb():
- bond_3ad_lacpdu_recv() @ drivers/net/bonding/bond_3ad.c
- bond_arp_recv() @ drivers/net/bonding/bond_main.c
- packet_rcv() @ net/packet/af_packet.c
- tpacket_rcv() @ net/packet/af_packet.c
From the bonding point of view, the meaning of orig_dev is obviously
"the device one layer below the bonding device, through which the packet
reached the bonding device". It is used by bond_3ad_lacpdu_recv() and
bond_arp_recv(), to find the underlying slave device through which the
LACPDU or ARP was received. (The protocol handler is registered at the
bonding device level).
From the af_packet point of view, the meaning is documented (in commit
"[AF_PACKET]: Add option to return orig_dev to userspace") as the
"physical device [that] actually received the traffic, instead of having
the encapsulating device hide that information."
When the bonding device is just one level above the physical device, the
two meanings happen to match the same device, by chance.
So, currently, a bonding device cannot stack properly on top of anything
but physical devices. It might not be a problem today, but may change in
the future...
Hi Jay,
Still thinking about this orig_dev stuff, I wonder why the protocol
handlers used in bonding (bond_3ad_lacpdu_recv() and bond_arp_rcv()) are
registered at the master level instead of at the slave level ?
If they were registered at the slave level, they would simply receive
skb->dev as the ingress interface and use this value instead of needing
the orig_dev value given to them when they are registered at the master
level.
As orig_dev is only used by bonding and by af_packet, but they disagree on
the exact meaning of orig_dev, one way to fix this discrepancy would be to
remove one of the usage. As the af_packet usage is exposed to user space,
bonding seems the right place to stop using orig_dev, even if orig_dev was
introduced for bonding :-)
I understand that this would add one entry per slave device to the
ptype_base list, but this seems to be the only bad effect of registering
at the slave level. Can you confirm that this was the reason to register
at the master level instead?
My recollection is that it was done the way it is because there
was no "orig_dev" delivery logic at the time. A handler registered to a
slave dev would receive no packets at all because assignment of skb->dev
to the master happened first, and the "orig_dev" knowledge was lost.
When 802.3ad was added, a skb->real_dev field was created, but
it wasn't used for delivery. 802.3ad used real_dev to figure out which
slave a LACPDU arrived on. The skb->real_dev was eventually replaced
with the orig_dev business that's there now.
Later, I did the arp_validate stuff the same way as 802.3ad
because it worked and was easier than registering a handler per slave.
If you think registering at the slave level would cause too much impact on
ptype_base, then we might have another way to stop using orig_dev for
bonding:
In __skb_bond_should_drop(), we already test for the two interesting protocols:
if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && skb->protocol == __cpu_to_be16(ETH_P_ARP))
return 0;
if (master->priv_flags & IFF_MASTER_8023AD && skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return 0;
Would it be possible to call the right handlers directly from inside
__skb_bond_should_drop() then let __skb_bond_should_drop() return 1
("should drop") after processing the frames that are only of interest for
bonding?
Isn't one purpose of switching to rx_handler that there won't
need to be any skb_bond_should_drop logic in __netif_receive_skb at all?
Still, if you're just trying to simplify __netif_receive_skb
first, I don't see any reason not to register the packet handlers at the
slave level. Looking at the ptype_base hash, I don't think that the
protocols bonding is registering (ARP and SLOW) will hash collide with
IP or IPv6, so I suspect there won't be much impact.
Once an rx_handler is used, then I suspect there's no need for
the packet handlers at all, since the rx_handler is within bonding and
can just deal with the ARP or LACPDU directly.
-J
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
Sat, Feb 26, 2011 at 08:42:57PM CET, fubar@us.ibm.com wrote:
Nicolas de Pesloüan [off-list ref] wrote:
quoted
Le 22/02/2011 00:20, Nicolas de Pesloüan a écrit :
quoted
After checking every protocol handlers installed by dev_add_pack(), it
appears that only 4 of them really use the orig_dev parameter given by
__netif_receive_skb():
- bond_3ad_lacpdu_recv() @ drivers/net/bonding/bond_3ad.c
- bond_arp_recv() @ drivers/net/bonding/bond_main.c
- packet_rcv() @ net/packet/af_packet.c
- tpacket_rcv() @ net/packet/af_packet.c
From the bonding point of view, the meaning of orig_dev is obviously
"the device one layer below the bonding device, through which the packet
reached the bonding device". It is used by bond_3ad_lacpdu_recv() and
bond_arp_recv(), to find the underlying slave device through which the
LACPDU or ARP was received. (The protocol handler is registered at the
bonding device level).
From the af_packet point of view, the meaning is documented (in commit
"[AF_PACKET]: Add option to return orig_dev to userspace") as the
"physical device [that] actually received the traffic, instead of having
the encapsulating device hide that information."
When the bonding device is just one level above the physical device, the
two meanings happen to match the same device, by chance.
So, currently, a bonding device cannot stack properly on top of anything
but physical devices. It might not be a problem today, but may change in
the future...
Hi Jay,
Still thinking about this orig_dev stuff, I wonder why the protocol
handlers used in bonding (bond_3ad_lacpdu_recv() and bond_arp_rcv()) are
registered at the master level instead of at the slave level ?
If they were registered at the slave level, they would simply receive
skb->dev as the ingress interface and use this value instead of needing
the orig_dev value given to them when they are registered at the master
level.
As orig_dev is only used by bonding and by af_packet, but they disagree on
the exact meaning of orig_dev, one way to fix this discrepancy would be to
remove one of the usage. As the af_packet usage is exposed to user space,
bonding seems the right place to stop using orig_dev, even if orig_dev was
introduced for bonding :-)
I understand that this would add one entry per slave device to the
ptype_base list, but this seems to be the only bad effect of registering
at the slave level. Can you confirm that this was the reason to register
at the master level instead?
My recollection is that it was done the way it is because there
was no "orig_dev" delivery logic at the time. A handler registered to a
slave dev would receive no packets at all because assignment of skb->dev
to the master happened first, and the "orig_dev" knowledge was lost.
When 802.3ad was added, a skb->real_dev field was created, but
it wasn't used for delivery. 802.3ad used real_dev to figure out which
slave a LACPDU arrived on. The skb->real_dev was eventually replaced
with the orig_dev business that's there now.
Later, I did the arp_validate stuff the same way as 802.3ad
because it worked and was easier than registering a handler per slave.
quoted
If you think registering at the slave level would cause too much impact on
ptype_base, then we might have another way to stop using orig_dev for
bonding:
In __skb_bond_should_drop(), we already test for the two interesting protocols:
if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && skb->protocol == __cpu_to_be16(ETH_P_ARP))
return 0;
if (master->priv_flags & IFF_MASTER_8023AD && skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return 0;
Would it be possible to call the right handlers directly from inside
__skb_bond_should_drop() then let __skb_bond_should_drop() return 1
("should drop") after processing the frames that are only of interest for
bonding?
Isn't one purpose of switching to rx_handler that there won't
need to be any skb_bond_should_drop logic in __netif_receive_skb at all?
Yes, that (hopefully most) would be eventually removed.
Still, if you're just trying to simplify __netif_receive_skb
first, I don't see any reason not to register the packet handlers at the
slave level. Looking at the ptype_base hash, I don't think that the
protocols bonding is registering (ARP and SLOW) will hash collide with
IP or IPv6, so I suspect there won't be much impact.
Once an rx_handler is used, then I suspect there's no need for
the packet handlers at all, since the rx_handler is within bonding and
can just deal with the ARP or LACPDU directly.
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
So I suggest to take V3 of my patch now and do multiple follow-on
patches to get us where we want to get.
Thanks
-J
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
From: Nicolas de Pesloüan <hidden> Date: 2011-02-27 14:17:06
Le 23/02/2011 20:05, Jiri Pirko a écrit :
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Signed-off-by: Jiri Pirko<redacted>
---
+static void vlan_on_bond_hook(struct sk_buff *skb)
{
- if (skb->pkt_type == PACKET_HOST) {
- u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
+ /*
+ * Make sure ARP frames received on VLAN interfaces stacked on
+ * bonding interfaces still make their way to any base bonding
+ * device that may have registered for a specific ptype.
+ */
+ if (skb->dev->priv_flags& IFF_802_1Q_VLAN&&
+ vlan_dev_real_dev(skb->dev)->priv_flags& IFF_BONDING&&
+ skb->protocol == htons(ETH_P_ARP)) {
The vlan_on_bond case used to be cost effective. Now, we clone the skb and call netif_rx...
Sun, Feb 27, 2011 at 03:17:01PM CET, nicolas.2p.debian@gmail.com wrote:
Le 23/02/2011 20:05, Jiri Pirko a écrit :
quoted
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed. Also
bond-specific work is moved into bond code.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Signed-off-by: Jiri Pirko<redacted>
v1->v2:
using skb_iif instead of new input_dev to remember original
device
v2->v3:
do another loop in case skb->dev is changed. That way orig_dev
core can be left untouched.
Signed-off-by: Jiri Pirko<redacted>
---
+static void vlan_on_bond_hook(struct sk_buff *skb)
{
- if (skb->pkt_type == PACKET_HOST) {
- u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
+ /*
+ * Make sure ARP frames received on VLAN interfaces stacked on
+ * bonding interfaces still make their way to any base bonding
+ * device that may have registered for a specific ptype.
+ */
+ if (skb->dev->priv_flags& IFF_802_1Q_VLAN&&
+ vlan_dev_real_dev(skb->dev)->priv_flags& IFF_BONDING&&
+ skb->protocol == htons(ETH_P_ARP)) {
The vlan_on_bond case used to be cost effective. Now, we clone the skb and call netif_rx...
This should not cost too much overhead considering only few packets are
going thru this. This hook shouldn't have exited in the fisrt place. I
think introducing this functionality was a big mistake.
From: Nicolas de Pesloüan <hidden> Date: 2011-02-27 20:44:46
Le 27/02/2011 13:58, Jiri Pirko a écrit :
Sat, Feb 26, 2011 at 08:42:57PM CET, fubar@us.ibm.com wrote:
quoted
Nicolas de Pesloüan [off-list ref] wrote:
quoted
Hi Jay,
Still thinking about this orig_dev stuff, I wonder why the protocol
handlers used in bonding (bond_3ad_lacpdu_recv() and bond_arp_rcv()) are
registered at the master level instead of at the slave level ?
If they were registered at the slave level, they would simply receive
skb->dev as the ingress interface and use this value instead of needing
the orig_dev value given to them when they are registered at the master
level.
As orig_dev is only used by bonding and by af_packet, but they disagree on
the exact meaning of orig_dev, one way to fix this discrepancy would be to
remove one of the usage. As the af_packet usage is exposed to user space,
bonding seems the right place to stop using orig_dev, even if orig_dev was
introduced for bonding :-)
I understand that this would add one entry per slave device to the
ptype_base list, but this seems to be the only bad effect of registering
at the slave level. Can you confirm that this was the reason to register
at the master level instead?
My recollection is that it was done the way it is because there
was no "orig_dev" delivery logic at the time. A handler registered to a
slave dev would receive no packets at all because assignment of skb->dev
to the master happened first, and the "orig_dev" knowledge was lost.
When 802.3ad was added, a skb->real_dev field was created, but
it wasn't used for delivery. 802.3ad used real_dev to figure out which
slave a LACPDU arrived on. The skb->real_dev was eventually replaced
with the orig_dev business that's there now.
Later, I did the arp_validate stuff the same way as 802.3ad
because it worked and was easier than registering a handler per slave.
quoted
If you think registering at the slave level would cause too much impact on
ptype_base, then we might have another way to stop using orig_dev for
bonding:
In __skb_bond_should_drop(), we already test for the two interesting protocols:
if ((dev->priv_flags& IFF_SLAVE_NEEDARP)&& skb->protocol == __cpu_to_be16(ETH_P_ARP))
return 0;
if (master->priv_flags& IFF_MASTER_8023AD&& skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return 0;
Would it be possible to call the right handlers directly from inside
__skb_bond_should_drop() then let __skb_bond_should_drop() return 1
("should drop") after processing the frames that are only of interest for
bonding?
Isn't one purpose of switching to rx_handler that there won't
need to be any skb_bond_should_drop logic in __netif_receive_skb at all?
Yes, that (hopefully most) would be eventually removed.
The skb_bond_should_drop logic was simply moved from dev.c to
bond_should_deliver_exact_match@bond_main.c by Jiri's patch.
But the logic remain and is necessary to decide whether we do normal delivery or only exact match
delivery.
quoted
Still, if you're just trying to simplify __netif_receive_skb
first, I don't see any reason not to register the packet handlers at the
slave level. Looking at the ptype_base hash, I don't think that the
protocols bonding is registering (ARP and SLOW) will hash collide with
IP or IPv6, so I suspect there won't be much impact.
Once an rx_handler is used, then I suspect there's no need for
the packet handlers at all, since the rx_handler is within bonding and
can just deal with the ARP or LACPDU directly.
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
Unfortunately, after doing some more research, I'm afraid we won't be able to suppress at least the
ARP packet handler:
In commit 1f3c8804acba841b5573b953f5560d2683d2db0d (bonding: allow arp_ip_targets on separate vlans
to use arp validation), Andy solved the problem of vlan on top of bonding, when the arp_ip_target is
on one of the vlans:
eth0/eth1 -> bond0 -> bond0.100
At the time the frame is inspected by bonding, the frame is still tagged. This is true for the new
rx_handler proposed by Jiri, and is also true for the former __skb_bond_should_drop() handling).
To receive the untagged frame, we would have to wait until the vlan code remove the tag. The current
protocol handler seems to be the best way to catch the frame that late.
This is probably specific to ARP. I don't think SLOW frames can be tagged.
Anyway, Jay, thanks for you clarification.
So I suggest to take V3 of my patch now and do multiple follow-on
patches to get us where we want to get.
No we shouldn't. We need sbk to be delivered to exact match.
So, if I understand properly:
- If skb->dev changed, loop,
- else, if skb->deliver_no_wcard, do exact match delivery only,
- Else, if !skb, drop the frame, without ever exact match delivery,
- Else, do normal delivery.
Right?
quoted
The vlan_on_bond case used to be cost effective. Now, we clone the skb and call netif_rx...
This should not cost too much overhead considering only few packets are
going thru this. This hook shouldn't have exited in the fisrt place. I
think introducing this functionality was a big mistake.
What would you have proposed instead?
Anyway, I think the feature is broken, because it wouldn't provide the expected effect on the
following configuration:
eth0/eth1 -> bond0 -> br0 -> br0.100.
We probably need a more general way to fix this, after your patch have been accepted.
[snip]
quoted
I would instead consider NULL as meaning exact-match-delivery-only.
(The same effect as dev_bond_should_drop() returning true).
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
I would rather see a complete patch set submitting at a unit, thanks.
I've already marked your V3 last night as "changes requested" in
patchwork for this reason.
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
I would rather see a complete patch set submitting at a unit, thanks.
I've already marked your V3 last night as "changes requested" in
patchwork for this reason.
That's a pity. V3 is complete patch. The changes we talk about in
discussion are just taking advantage of changes in patch V3. Would be in
my opinion better to apply V3 now and followup with the rest after that.
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
I would rather see a complete patch set submitting at a unit, thanks.
I've already marked your V3 last night as "changes requested" in
patchwork for this reason.
That's a pity. V3 is complete patch. The changes we talk about in
discussion are just taking advantage of changes in patch V3. Would be in
my opinion better to apply V3 now and followup with the rest after that.
That is very true. And given that af_packet uses orig_dev to obtain
ifindex, it can be replaced by skb->skb_iif. That way we can get rid of
orig_dev parameter for good.
I would rather see a complete patch set submitting at a unit, thanks.
I've already marked your V3 last night as "changes requested" in
patchwork for this reason.
That's a pity. V3 is complete patch. The changes we talk about in
discussion are just taking advantage of changes in patch V3. Would be in
my opinion better to apply V3 now and followup with the rest after that.
Fair enough, I'll aply it now, thanks.
Applied incorrectly. net/core/dev.c part is missing
This patch converts bonding to use rx_handler. Results in cleaner
__netif_receive_skb() with much less exceptions needed.
Did performance test using pktgen and counting incoming packets by
iptables. No regression noted.
Reviewed-by: Nicolas de Pesloüan <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
net/core/dev.c | 119 ++++++++++++++-----------------------------------------
1 files changed, 31 insertions(+), 88 deletions(-)
@@ -3096,63 +3096,31 @@ void netdev_rx_handler_unregister(struct net_device *dev)}EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);-staticinlinevoidskb_bond_set_mac_by_master(structsk_buff*skb,-structnet_device*master)+staticvoidvlan_on_bond_hook(structsk_buff*skb){-if(skb->pkt_type==PACKET_HOST){-u16*dest=(u16*)eth_hdr(skb)->h_dest;+/*+*MakesureARPframesreceivedonVLANinterfacesstackedon+*bondinginterfacesstillmaketheirwaytoanybasebonding+*devicethatmayhaveregisteredforaspecificptype.+*/+if(skb->dev->priv_flags&IFF_802_1Q_VLAN&&+vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING&&+skb->protocol==htons(ETH_P_ARP)){+structsk_buff*skb2=skb_clone(skb,GFP_ATOMIC);-memcpy(dest,master->dev_addr,ETH_ALEN);+if(!skb2)+return;+skb2->dev=vlan_dev_real_dev(skb->dev);+netif_rx(skb2);}}-/* On bonding slaves other than the currently active slave, suppress-*duplicatesexceptfor802.3adETH_P_SLOW,albnon-mcast/bcast,and-*ARPonactive-backupslaveswitharp_validateenabled.-*/-staticint__skb_bond_should_drop(structsk_buff*skb,-structnet_device*master)-{-structnet_device*dev=skb->dev;--if(master->priv_flags&IFF_MASTER_ARPMON)-dev->last_rx=jiffies;--if((master->priv_flags&IFF_MASTER_ALB)&&-(master->priv_flags&IFF_BRIDGE_PORT)){-/* Do address unmangle. The local destination address-*willbealwaystheonemasterhas.Providestheright-*functionalityinabridge.-*/-skb_bond_set_mac_by_master(skb,master);-}--if(dev->priv_flags&IFF_SLAVE_INACTIVE){-if((dev->priv_flags&IFF_SLAVE_NEEDARP)&&-skb->protocol==__cpu_to_be16(ETH_P_ARP))-return0;--if(master->priv_flags&IFF_MASTER_ALB){-if(skb->pkt_type!=PACKET_BROADCAST&&-skb->pkt_type!=PACKET_MULTICAST)-return0;-}-if(master->priv_flags&IFF_MASTER_8023AD&&-skb->protocol==__cpu_to_be16(ETH_P_SLOW))-return0;--return1;-}-return0;-}-staticint__netif_receive_skb(structsk_buff*skb){structpacket_type*ptype,*pt_prev;rx_handler_func_t*rx_handler;structnet_device*orig_dev;-structnet_device*null_or_orig;-structnet_device*orig_or_bond;+structnet_device*null_or_dev;intret=NET_RX_DROP;__be16type;
@@ -3167,32 +3135,8 @@ static int __netif_receive_skb(struct sk_buff *skb)if(!skb->skb_iif)skb->skb_iif=skb->dev->ifindex;--/*-*bondingnote:skbsreceivedoninactiveslavesshouldonly-*bedeliveredtopkthandlersthatareexactmatches.Also-*thedeliver_no_wcardflagwillbeset.Ifpackethandlers-*aresensitivetoduplicatepacketstheseskbswillneedto-*bedroppedatthehandler.-*/-null_or_orig=NULL;orig_dev=skb->dev;-if(skb->deliver_no_wcard)-null_or_orig=orig_dev;-elseif(netif_is_bond_slave(orig_dev)){-structnet_device*bond_master=ACCESS_ONCE(orig_dev->master);--if(likely(bond_master)){-if(__skb_bond_should_drop(skb,bond_master)){-skb->deliver_no_wcard=1;-/* deliver only exact match */-null_or_orig=orig_dev;-}else-skb->dev=bond_master;-}-}-__this_cpu_inc(softnet_data.processed);skb_reset_network_header(skb);skb_reset_transport_header(skb);skb->mac_len=skb->network_header-skb->mac_header;
@@ -3201,6 +3145,10 @@ static int __netif_receive_skb(struct sk_buff *skb)rcu_read_lock();+another_round:++__this_cpu_inc(softnet_data.processed);+#ifdef CONFIG_NET_CLS_ACTif(skb->tc_verd&TC_NCLS){skb->tc_verd=CLR_TC_NCLS(skb->tc_verd);
@@ -3209,8 +3157,7 @@ static int __netif_receive_skb(struct sk_buff *skb)#endiflist_for_each_entry_rcu(ptype,&ptype_all,list){-if(ptype->dev==null_or_orig||ptype->dev==skb->dev||-ptype->dev==orig_dev){+if(!ptype->dev||ptype->dev==skb->dev){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;
@@ -3224,16 +3171,20 @@ static int __netif_receive_skb(struct sk_buff *skb)ncls:#endif-/* Handle special case of bridge or macvlan */rx_handler=rcu_dereference(skb->dev->rx_handler);if(rx_handler){+structnet_device*prev_dev;+if(pt_prev){ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=NULL;}+prev_dev=skb->dev;skb=rx_handler(skb);if(!skb)gotoout;+if(skb->dev!=prev_dev)+gotoanother_round;}if(vlan_tx_tag_present(skb)){
@@ -3248,24 +3199,16 @@ ncls:gotoout;}-/*-*MakesureframesreceivedonVLANinterfacesstackedon-*bondinginterfacesstillmaketheirwaytoanybasebonding-*devicethatmayhaveregisteredforaspecificptype.The-*handlermayhavetoadjustskb->devandorig_dev.-*/-orig_or_bond=orig_dev;-if((skb->dev->priv_flags&IFF_802_1Q_VLAN)&&-(vlan_dev_real_dev(skb->dev)->priv_flags&IFF_BONDING)){-orig_or_bond=vlan_dev_real_dev(skb->dev);-}+vlan_on_bond_hook(skb);++/* deliver only exact match when indicated */+null_or_dev=skb->deliver_no_wcard?skb->dev:NULL;type=skb->protocol;list_for_each_entry_rcu(ptype,&ptype_base[ntohs(type)&PTYPE_HASH_MASK],list){-if(ptype->type==type&&(ptype->dev==null_or_orig||-ptype->dev==skb->dev||ptype->dev==orig_dev||-ptype->dev==orig_or_bond)){+if(ptype->type==type&&+(ptype->dev==null_or_dev||ptype->dev==skb->dev)){if(pt_prev)ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=ptype;