Netdev List
 help / color / mirror / Atom feed
* Re: [patch net-next 00/34] net: sched: allow qdiscs to share filter block instances
From: Jiri Pirko @ 2017-10-13  6:21 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
	f.fainelli, michael.chan, ganeshgr, jeffrey.t.kirsher, saeedm,
	matanb, leonro, idosch, jakub.kicinski, ast, daniel, simon.horman,
	pieter.jansenvanvuuren, john.hurley, edumazet, dsahern,
	alexander.h.duyck, john.fastabend, willemb
In-Reply-To: <20171012.102148.580269505585324793.davem@davemloft.net>

Thu, Oct 12, 2017 at 07:21:48PM CEST, davem@davemloft.net wrote:
>
>Jiri I'm not looking at a 34 patch set, it's too large.
>
>Break this up into groups of a dozen or so patches each, no
>more.  Submit them one at a time and wait for each series
>to be fully reviewed and integrated before moving onto the
>next one.

Yeah. As I stated in the beginning of the cover letter, I did not find a
way to do it. I could split into 2 of 3 patchsets, problem is that I
would introduce interfaces in first patchset that would be only used in
patchset 2 or 3. I believe that is not ok. Do you think that I can do it
like this this time?

Thanks

^ permalink raw reply

* Re: [patch net-next 00/34] net: sched: allow qdiscs to share filter block instances
From: Jiri Pirko @ 2017-10-13  6:26 UTC (permalink / raw)
  To: David Ahern
  Cc: netdev, davem, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
	f.fainelli, michael.chan, ganeshgr, jeffrey.t.kirsher, saeedm,
	matanb, leonro, idosch, jakub.kicinski, ast, daniel, simon.horman,
	pieter.jansenvanvuuren, john.hurley, edumazet, alexander.h.duyck,
	john.fastabend, willemb
In-Reply-To: <441b4617-982e-cbc6-0747-026d4a8a0b15@gmail.com>

Thu, Oct 12, 2017 at 11:37:30PM CEST, dsahern@gmail.com wrote:
>On 10/12/17 11:17 AM, Jiri Pirko wrote:
>> So back to the example. First, we create 2 qdiscs. Both will share
>> block number 22. "22" is just an identification. If we don't pass any
>> block number, a new one will be generated by kernel:
>> 
>> $ tc qdisc add dev ens7 ingress block 22
>>                                 ^^^^^^^^
>> $ tc qdisc add dev ens8 ingress block 22
>>                                 ^^^^^^^^
>> 
>> Now if we list the qdiscs, we will see the block index in the output:
>> 
>> $ tc qdisc
>> qdisc ingress ffff: dev ens7 parent ffff:fff1 block 22 
>> qdisc ingress ffff: dev ens8 parent ffff:fff1 block 22 
>> 
>> Now we can add filter to any of qdiscs sharing the same block:
>> 
>> $ tc filter add dev ens7 parent ffff: protocol ip pref 25 flower dst_ip 192.168.0.0/16 action drop
>> 
>> 
>> We will see the same output if we list filters for ens7 and ens8, including stats:
>> 
>> $ tc -s filter show dev ens7 ingress
>> filter protocol ip pref 25 flower chain 0 
>> filter protocol ip pref 25 flower chain 0 handle 0x1 
>>   eth_type ipv4
>>   dst_ip 192.168.0.0/16
>>   not_in_hw
>>         action order 1: gact action drop
>>          random type none pass val 0
>>          index 1 ref 1 bind 1 installed 39 sec used 2 sec
>>         Action statistics:
>>         Sent 3108 bytes 37 pkt (dropped 37, overlimits 0 requeues 0) 
>>         backlog 0b 0p requeues 0 
>> 
>> $ tc -s filter show dev ens8 ingress
>> filter protocol ip pref 25 flower chain 0 
>> filter protocol ip pref 25 flower chain 0 handle 0x1 
>>   eth_type ipv4
>>   dst_ip 192.168.0.0/16
>>   not_in_hw
>>         action order 1: gact action drop
>>          random type none pass val 0
>>          index 1 ref 1 bind 1 installed 40 sec used 3 sec
>>         Action statistics:
>>         Sent 3108 bytes 37 pkt (dropped 37, overlimits 0 requeues 0) 
>>         backlog 0b 0p requeues 0
>
>This seems like really odd semantics to me ... a filter added to one
>device shows up on another.

Why is it odd? They share the same block, so it is natural that rule
added to one shows in list of rules for all devices that share the same
block.


>
>Why not make the shared block a standalone object that is configured
>through its own set of commands and then referenced by both devices?

I was thinking about that for a long time. That would require entirely
new set of netlink api and internal kernel handling just for this. Lots
of duplications. The reason is, the current API is strictly build around
ifindex. But the new API would not solve anything. As a user, I still
want so see shared rules in individial device listing, because they
would get processed for the device. So I believe that the proposed
behaviour is correct.

^ permalink raw reply

* Re: [patch net-next 06/34] net: core: use dev->ingress_queue instead of tp->q
From: Jiri Pirko @ 2017-10-13  6:30 UTC (permalink / raw)
  To: Daniel Borkmann
  Cc: netdev, davem, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
	f.fainelli, michael.chan, ganeshgr, jeffrey.t.kirsher, saeedm,
	matanb, leonro, idosch, jakub.kicinski, ast, simon.horman,
	pieter.jansenvanvuuren, john.hurley, edumazet, dsahern,
	alexander.h.duyck, john.fastabend, willemb
In-Reply-To: <59DFE287.2040400@iogearbox.net>

Thu, Oct 12, 2017 at 11:45:43PM CEST, daniel@iogearbox.net wrote:
>On 10/12/2017 07:17 PM, Jiri Pirko wrote:
>> From: Jiri Pirko <jiri@mellanox.com>
>> 
>> In sch_handle_egress and sch_handle_ingress, don't use tp->q and use
>> dev->ingress_queue which stores the same pointer instead.
>> 
>> Signed-off-by: Jiri Pirko <jiri@mellanox.com>
>> ---
>>   net/core/dev.c | 21 +++++++++++++++------
>>   1 file changed, 15 insertions(+), 6 deletions(-)
>> 
>> diff --git a/net/core/dev.c b/net/core/dev.c
>> index fcddccb..cb9e5e5 100644
>> --- a/net/core/dev.c
>> +++ b/net/core/dev.c
>> @@ -3273,14 +3273,18 @@ EXPORT_SYMBOL(dev_loopback_xmit);
>>   static struct sk_buff *
>>   sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
>>   {
>> +	struct netdev_queue *netdev_queue =
>> +				rcu_dereference_bh(dev->ingress_queue);
>>   	struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list);
>>   	struct tcf_result cl_res;
>> +	struct Qdisc *q;
>> 
>> -	if (!cl)
>> +	if (!cl || !netdev_queue)
>>   		return skb;
>> +	q = netdev_queue->qdisc;
>
>NAK, no additional overhead in the software fast-path of
>sch_handle_{ingress,egress}() like this. There are users out there
>that use tc in software only, so performance is critical here.

Okay, how else do you suggest I can avoid the need to use tp->q?
I was thinking about storing q directly to net_device, which would safe
one dereference, resulting in the same amount as current cl->q.

Thanks.

^ permalink raw reply

* Re: [patch net-next 00/34] net: sched: allow qdiscs to share filter block instances
From: David Miller @ 2017-10-13  6:31 UTC (permalink / raw)
  To: jiri
  Cc: netdev, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
	f.fainelli, michael.chan, ganeshgr, jeffrey.t.kirsher, saeedm,
	matanb, leonro, idosch, jakub.kicinski, ast, daniel, simon.horman,
	pieter.jansenvanvuuren, john.hurley, edumazet, dsahern,
	alexander.h.duyck, john.fastabend, willemb
In-Reply-To: <20171013062101.GA1952@nanopsycho.orion>

From: Jiri Pirko <jiri@resnulli.us>
Date: Fri, 13 Oct 2017 08:21:01 +0200

> Thu, Oct 12, 2017 at 07:21:48PM CEST, davem@davemloft.net wrote:
>>
>>Jiri I'm not looking at a 34 patch set, it's too large.
>>
>>Break this up into groups of a dozen or so patches each, no
>>more.  Submit them one at a time and wait for each series
>>to be fully reviewed and integrated before moving onto the
>>next one.
> 
> Yeah. As I stated in the beginning of the cover letter, I did not find a
> way to do it. I could split into 2 of 3 patchsets, problem is that I
> would introduce interfaces in first patchset that would be only used in
> patchset 2 or 3. I believe that is not ok. Do you think that I can do it
> like this this time?

Jiri, please try harder.

Thank you.

^ permalink raw reply

* Re: [RFC 1/3] devlink: Add config parameter get/set operations
From: Jiri Pirko @ 2017-10-13  7:04 UTC (permalink / raw)
  To: Andy Gospodarek
  Cc: Steve Lin, netdev, jiri, davem, michael.chan, linux-pci, linville
In-Reply-To: <20171012181248.GA66136@C02RW35GFVH8.dhcp.broadcom.net>

Thu, Oct 12, 2017 at 08:12:48PM CEST, andrew.gospodarek@broadcom.com wrote:
>On Thu, Oct 12, 2017 at 04:03:17PM +0200, Jiri Pirko wrote:
>> Thu, Oct 12, 2017 at 03:34:20PM CEST, steven.lin1@broadcom.com wrote:
>> >Add support for config parameter get/set commands. Initially used by
>> >bnxt driver, but other drivers can use the same, or new, attributes.
>> >The config_get() and config_set() operations operate as expected, but
>> >note that the driver implementation of the config_set() operation can
>> >indicate whether a restart is necessary for the setting to take
>> >effect.
>> >
>> 
>> First of all, I like this approach.
>> 
>> I would like to see this patch split into:
>> 1) config-options infrastructure introduction
>> 2) specific config options introductions - would be best to have it
>>    per-option. We need to make sure every option is very well described
>>    and explained usecases. This is needed in order vendors to share
>>    attributes among drivers.
>> 
>> More nits inlined.
>> 
>> 
>> >Signed-off-by: Steve Lin <steven.lin1@broadcom.com>
>> >Acked-by: Andy Gospodarek <gospo@broadcom.com>
>> >---
>> > include/net/devlink.h        |   4 +
>> > include/uapi/linux/devlink.h | 108 ++++++++++++++++++++++
>> > net/core/devlink.c           | 207 +++++++++++++++++++++++++++++++++++++++++++
>> > 3 files changed, 319 insertions(+)
>> >
>> > static inline void *devlink_priv(struct devlink *devlink)
>> >diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
>> >index 0cbca96..e959716 100644
>> >--- a/include/uapi/linux/devlink.h
>> >+++ b/include/uapi/linux/devlink.h
>[...]
>> >@@ -202,6 +267,49 @@ enum devlink_attr {
>> > 
>> > 	DEVLINK_ATTR_ESWITCH_ENCAP_MODE,	/* u8 */
>> > 
>> >+	/* Configuration Parameters */
>> >+	DEVLINK_ATTR_SRIOV_ENABLED,		/* u8 */
>> >+	DEVLINK_ATTR_NUM_VF_PER_PF,		/* u32 */
>> >+	DEVLINK_ATTR_MAX_NUM_PF_MSIX_VECT,	/* u32 */
>> >+	DEVLINK_ATTR_MSIX_VECTORS_PER_VF,	/* u32 */
>> >+	DEVLINK_ATTR_NPAR_NUM_PARTITIONS_PER_PORT,	/* u32 */
>> >+	DEVLINK_ATTR_NPAR_BW_IN_PERCENT,	/* u8 */
>> >+	DEVLINK_ATTR_NPAR_BW_RESERVATION,	/* u8 */
>> >+	DEVLINK_ATTR_NPAR_BW_RESERVATION_VALID,	/* u8 */
>> >+	DEVLINK_ATTR_NPAR_BW_LIMIT,		/* u8 */
>> >+	DEVLINK_ATTR_NPAR_BW_LIMIT_VALID,	/* u8 */
>> >+	DEVLINK_ATTR_DCBX_MODE,			/* u8 */
>> >+	DEVLINK_ATTR_RDMA_ENABLED,		/* u8 */
>> >+	DEVLINK_ATTR_MULTIFUNC_MODE,		/* u8 */
>> >+	DEVLINK_ATTR_SECURE_NIC_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_IGNORE_ARI_CAPABILITY,	/* u8 */
>> >+	DEVLINK_ATTR_LLDP_NEAREST_BRIDGE_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_LLDP_NEAREST_NONTPMR_BRIDGE_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_PME_CAPABILITY_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_MAGIC_PACKET_WOL_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_EEE_PWR_SAVE_ENABLED,	/* u8 */
>> >+	DEVLINK_ATTR_AUTONEG_PROTOCOL,		/* u8 */
>> >+	DEVLINK_ATTR_MEDIA_AUTO_DETECT,		/* u8 */
>> >+	DEVLINK_ATTR_PHY_SELECT,		/* u8 */
>> >+	DEVLINK_ATTR_PRE_OS_LINK_SPEED_D0,	/* u8 */
>> >+	DEVLINK_ATTR_PRE_OS_LINK_SPEED_D3,	/* u8 */
>> >+	DEVLINK_ATTR_MBA_ENABLED,		/* u8 */
>> >+	DEVLINK_ATTR_MBA_BOOT_TYPE,		/* u8 */
>> >+	DEVLINK_ATTR_MBA_DELAY_TIME,		/* u32 */
>> >+	DEVLINK_ATTR_MBA_SETUP_HOT_KEY,		/* u8 */
>> >+	DEVLINK_ATTR_MBA_HIDE_SETUP_PROMPT,	/* u8 */
>> >+	DEVLINK_ATTR_MBA_BOOT_RETRY_COUNT,	/* u32 */
>> >+	DEVLINK_ATTR_MBA_VLAN_ENABLED,		/* u8 */
>> >+	DEVLINK_ATTR_MBA_VLAN_TAG,		/* u16 */
>> >+	DEVLINK_ATTR_MBA_BOOT_PROTOCOL,		/* u8 */
>> >+	DEVLINK_ATTR_MBA_LINK_SPEED,		/* u8 */
>> 
>> Okay, I think it is about the time we should start thinking about
>> putting this new config attributes under nester attribute. What do you
>> think?
>> 
>
>Steve and I actually had a similar discussion yesterday when I was doing
>a final review of the patches.
>
>My only objection to nesting was coming up with a way to describe these
>functions that made them seem different than existing configuration
>options.  In this case of the hardware we are trying to support these
>are all permanent config options, so we would call them
>DEVLINK_ATTR_NVRAM or DEVLINK_ATTR_PERM.  Does that seem reasonable to
>others?

The name should go hand-in-hand with the names of the cmds.

^ permalink raw reply

* Re: [RFC 0/3] Adding config get/set to devlink
From: Jiri Pirko @ 2017-10-13  7:08 UTC (permalink / raw)
  To: Steve Lin
  Cc: Florian Fainelli, David Miller, Roopa Prabhu, netdev, Jiri Pirko,
	Michael Chan, linux-pci, John Linville, Andy Gospodarek
In-Reply-To: <CA+Jmh7Em0ZjN0y3FSk1yBhOtPKvFBnJCVA97oZZb7cgXXF_aUA@mail.gmail.com>

Thu, Oct 12, 2017 at 10:12:31PM CEST, steven.lin1@broadcom.com wrote:
>On Thu, Oct 12, 2017 at 3:20 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 10/12/2017 12:06 PM, David Miller wrote:
>>> From: Florian Fainelli <f.fainelli@gmail.com>
>>> Date: Thu, 12 Oct 2017 08:43:59 -0700
>>>
>>>> Once we move ethtool (or however we name its successor) over to
>>>> netlink there is an opportunity for accessing objects that do and do
>>>> not have a netdevice representor today (e.g: management ports on
>>>> switches) with the same interface, and devlink could be used for
>>>> that.
>>>
>>> That is an interesting angle for including this in devlink.
>>>
>>> I'm not so sure what to do about this.
>>>
>>> One suggestion is that devlink is used for getting ethtool stats for
>>> objects lacking netdev representor's, and a new genetlink family is
>>> used for netdev based ethtool.
>>
>> Right, I was also thinking along those lines that we we would have a new
>> generic netlink family for ethtool to support ethtool over netlink.
>>
>>>
>>> I think it's important that we don't expand the scope of devlink
>>> beyond what it was originally designed for.
>>
>> It seems to me like devlink is well defined in what it is not for: it is
>> not meant to be used for any object that is/has a net_device, but it is
>> not well defined for what it can offer to these non network devices. For
>> instance, we have a tremendous amount of operations that are extremely
>> specific to its single user(s) such as mlx5 and mlxsw.
>>
>> For instance, I am not sure how the buffer reservation scheme can be
>> generalized, and this is always the tricky part with a single user
>> facility in that you try to generalize the best you can based on the HW
>> you know. This is not a criticism or meant to be anything negative, this
>> just happens to be the case, and we did not have anything better.
>>
>> So maybe the first thing is to clarify what devlink operations can and
>> should be and what they are absolutely not allowed to cover. We should
>> also clarify whether a generic set/get that Steven is proposing is
>> something that we tolerate, or whether there should be specific function
>> pointers implemented for each attribute, which would be more in line
>> with what has been done thus far.
>
>Hi Florian,
>
>Some of this is subjective, of course, but just to clarify, it did
>seem like implementing a new devlink_op function pointer per attribute
>might be more consistent with what's been done so far.  But for code
>reuse purposes - i.e. to avoid replicating essentially the same
>function for each of the 30+ config attributes - I elected to just
>implement a single generic get and set devlink_op.

Also, it this case, unlike any existing cmds, the config options are
all permanent, written in hw. I think it is fine to have one set
of get/set cmd to handle them all at once. Same family.

^ permalink raw reply

* Re: [RFC 0/3] Adding config get/set to devlink
From: Jiri Pirko @ 2017-10-13  7:11 UTC (permalink / raw)
  To: Roopa Prabhu
  Cc: Florian Fainelli, David Miller, Steve Lin, netdev@vger.kernel.org,
	Jiri Pirko, Michael Chan, linux-pci, John W. Linville,
	Andy Gospodarek
In-Reply-To: <CAJieiUjK4CsBGT5_YidnEGk7mCVYYO_8S0xcsv+XfaW=amGCaQ@mail.gmail.com>

Thu, Oct 12, 2017 at 11:53:56PM CEST, roopa@cumulusnetworks.com wrote:
>On Thu, Oct 12, 2017 at 12:20 PM, Florian Fainelli <f.fainelli@gmail.com> wrote:
>> On 10/12/2017 12:06 PM, David Miller wrote:
>>> From: Florian Fainelli <f.fainelli@gmail.com>
>>> Date: Thu, 12 Oct 2017 08:43:59 -0700
>>>
>>>> Once we move ethtool (or however we name its successor) over to
>>>> netlink there is an opportunity for accessing objects that do and do
>>>> not have a netdevice representor today (e.g: management ports on
>>>> switches) with the same interface, and devlink could be used for
>>>> that.
>>>
>>> That is an interesting angle for including this in devlink.
>>>
>>> I'm not so sure what to do about this.
>>>
>>> One suggestion is that devlink is used for getting ethtool stats for
>>> objects lacking netdev representor's, and a new genetlink family is
>>> used for netdev based ethtool.
>>
>> Right, I was also thinking along those lines that we we would have a new
>> generic netlink family for ethtool to support ethtool over netlink.
>
>new api is fine by me. The reason for suggesting devlink was because
>some of the devlink
>port_* ops are close to ethtool ops that can operate on a port/netdev.
>eg split_port could be a netdev operation
>unless you want to split before the netdev is created.

Let me correct you. The split is always devlink_port operation. In some
cases however when there is a mapping between devlink_port and netdev,
userspace part could translate netdev->devlink_port.


>
>There are some ops in devlink which are global hw parameters and not
>specific to a port, those fit perfectly with
>devlinks original goal.

There are 2 handles from the very beginning:
1) devlink - asic-wide handle
2) devlink_port - port handle

^ permalink raw reply

* pull-request: wireless-drivers 2017-10-13
From: Kalle Valo @ 2017-10-13  7:25 UTC (permalink / raw)
  To: David Miller; +Cc: linux-wireless, netdev, linux-kernel

Hi Dave,

here's a pull request to net tree, more info in the signed tag below.
Please let me know if there are any problems.

Kalle

The following changes since commit 3e747fa18202896b5be66b88478352d5880fb8eb:

  Merge ath-current from ath.git (2017-09-25 10:06:12 +0300)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers.git tags/wireless-drivers-for-davem-2017-10-13

for you to fetch changes up to a6127b4440d1f74f26b64006b2f50c9dc6d66efc:

  Merge tag 'iwlwifi-for-kalle-2017-10-06' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-fixes (2017-10-09 17:31:39 +0300)

----------------------------------------------------------------
wireless-drivers fixes for 4.14

Nothing really special standing out, all of these are important fixes
which should go to 4.14.

iwlwifi

* fix support for 3168 device series

* fix a potential crash when using FW debugging recording;

* improve channel flags parsing to avoid warnings on too long traces

* return -ENODATA when the temperature is not available, since the
 -EIO we were returning was causing fatal errors in userspace

* avoid printing too many messages in dmesg when using monitor mode,
  since this can become very noisy and completely flood the logs

brcmsmac

* reduce stack usage to avoid frame size warnings with KASAN

brcmfmac

* add a check to avoid copying uninitialised memory

rtlwifi:

* fix a regression with rtl8821ae starting from v4.11 where
  connections was frequently lost

----------------------------------------------------------------
Arnd Bergmann (1):
      brcmsmac: make some local variables 'static const' to reduce stack size

Chaya Rachel Ivgi (1):
      iwlwifi: nvm: set the correct offsets to 3168 series

Golan Ben Ami (1):
      iwlwifi: stop dbgc recording before stopping DMA

Johannes Berg (1):
      iwlwifi: nvm-parse: unify channel flags printing

Kalle Valo (1):
      Merge tag 'iwlwifi-for-kalle-2017-10-06' of git://git.kernel.org/.../iwlwifi/iwlwifi-fixes

Kevin Cernekee (1):
      brcmfmac: Add check for short event packets

Larry Finger (1):
      rtlwifi: rtl8821ae: Fix connection lost problem

Luca Coelho (1):
      iwlwifi: mvm: return -ENODATA when reading the temperature with the FW down

Shaul Triebitz (1):
      iwlwifi: mvm: do not print security error in monitor mode

 .../wireless/broadcom/brcm80211/brcmfmac/fweh.c    |   3 +-
 .../broadcom/brcm80211/brcmsmac/phy/phy_n.c        | 197 ++++++++++-----------
 drivers/net/wireless/intel/iwlwifi/cfg/7000.c      |   1 +
 drivers/net/wireless/intel/iwlwifi/cfg/8000.c      |   2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/9000.c      |   2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/a000.c      |   2 +-
 .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h    |   2 +
 drivers/net/wireless/intel/iwlwifi/fw/dbg.c        |   7 +-
 drivers/net/wireless/intel/iwlwifi/fw/dbg.h        |  15 ++
 drivers/net/wireless/intel/iwlwifi/iwl-config.h    |  16 +-
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 137 +++++++-------
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c  |   7 +
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h       |   5 +-
 drivers/net/wireless/intel/iwlwifi/mvm/nvm.c       |  21 ++-
 drivers/net/wireless/intel/iwlwifi/mvm/rx.c        |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c      |   4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/tt.c        |   2 +-
 .../net/wireless/realtek/rtlwifi/rtl8821ae/hw.c    |   2 +-
 18 files changed, 232 insertions(+), 197 deletions(-)

^ permalink raw reply

* Not BUG, feature :) af_packet fails to TX TSO frames
From: Anton Ivanov @ 2017-10-13  7:25 UTC (permalink / raw)
  To: Willem de Bruijn; +Cc: Network Development
In-Reply-To: <CAF=yD-+SxQTHxiU5Yi2f8dm6X1s7SA6PdkbeJP-K_9ZuTMAaTA@mail.gmail.com>

Let's reset this one.

I cannot say I am happy with the current number of caveats on using 
this. We should at least throw a small page similar to the one dedicated 
to tpacket_v2 into the kernel docs (or amend the offload docs). As I do 
not know all the corner cases well enough I find it difficult to 
volunteer on this one, it should be someone more familiar with the code. 
If they are documented, we can say that this is not a bug, it is a 
feature :)

What I can volunteer on is contributing some code to the actual 
af_packet.c. When I did the digging in the source, I noticed that tap 
has an unfair advantage over raw by allowing the user to specify buffers 
from userspace. I am happy to port that, test it and contribute it.

-- 
Anton R. Ivanov

Cambridge Greys Limited, England and Wales company No 10273661
http://www.cambridgegreys.com/

^ permalink raw reply

* Re: [patch net-next 00/34] net: sched: allow qdiscs to share filter block instances
From: Jiri Pirko @ 2017-10-13  7:39 UTC (permalink / raw)
  To: David Miller
  Cc: netdev, jhs, xiyou.wangcong, mlxsw, andrew, vivien.didelot,
	f.fainelli, michael.chan, ganeshgr, jeffrey.t.kirsher, saeedm,
	matanb, leonro, idosch, jakub.kicinski, ast, daniel, simon.horman,
	pieter.jansenvanvuuren, john.hurley, edumazet, dsahern,
	alexander.h.duyck, john.fastabend, willemb
In-Reply-To: <20171012.233153.709649098069912221.davem@davemloft.net>

Fri, Oct 13, 2017 at 08:31:53AM CEST, davem@davemloft.net wrote:
>From: Jiri Pirko <jiri@resnulli.us>
>Date: Fri, 13 Oct 2017 08:21:01 +0200
>
>> Thu, Oct 12, 2017 at 07:21:48PM CEST, davem@davemloft.net wrote:
>>>
>>>Jiri I'm not looking at a 34 patch set, it's too large.
>>>
>>>Break this up into groups of a dozen or so patches each, no
>>>more.  Submit them one at a time and wait for each series
>>>to be fully reviewed and integrated before moving onto the
>>>next one.
>> 
>> Yeah. As I stated in the beginning of the cover letter, I did not find a
>> way to do it. I could split into 2 of 3 patchsets, problem is that I
>> would introduce interfaces in first patchset that would be only used in
>> patchset 2 or 3. I believe that is not ok. Do you think that I can do it
>> like this this time?
>
>Jiri, please try harder.

Hmm. Okay. The reviewer would miss the big picture. But as you wish :)

^ permalink raw reply

* [net-next:master 836/858] bcmsysport.c:undefined reference to `unregister_dsa_notifier'
From: kbuild test robot @ 2017-10-13  7:41 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: kbuild-all, netdev

[-- Attachment #1: Type: text/plain, Size: 1103 bytes --]

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head:   2d0d21c12dfa3851620f1fa9fe2d444538f1fad4
commit: d156576362c07e954dc36e07b0d7b0733a010f7d [836/858] net: systemport: Establish lower/upper queue mapping
config: x86_64-randconfig-it0-10131242 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        git checkout d156576362c07e954dc36e07b0d7b0733a010f7d
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/net/ethernet/broadcom/bcmsysport.o: In function `bcm_sysport_remove':
>> bcmsysport.c:(.text+0x2020): undefined reference to `unregister_dsa_notifier'
   drivers/net/ethernet/broadcom/bcmsysport.o: In function `bcm_sysport_probe':
>> bcmsysport.c:(.text+0x3689): undefined reference to `register_dsa_notifier'
   bcmsysport.c:(.text+0x38d1): undefined reference to `unregister_dsa_notifier'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 33591 bytes --]

^ permalink raw reply

* VPLS in Linux
From: Алексей Болдырев @ 2017-10-13  7:45 UTC (permalink / raw)
  To: netdev

There was a message with patches of VPLS in the Linux kernel. But they somehow did not fall into the next. What about the development of the Linux subsystem in Linux?

^ permalink raw reply

* Re: [PATCH] ravb: Consolidate clock handling
From: Simon Horman @ 2017-10-13  8:05 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Geert Uytterhoeven, David S . Miller, Sergei Shtylyov,
	Niklas Söderlund, netdev@vger.kernel.org, Linux-Renesas
In-Reply-To: <CAMuHMdUpvrWpyiAo2qT=5JWHU+jpbDgV8LuvF0-+pC825XQMeg@mail.gmail.com>

On Thu, Oct 12, 2017 at 02:20:45PM +0200, Geert Uytterhoeven wrote:
> Hi Simon,
> 
> On Thu, Oct 12, 2017 at 11:55 AM, Simon Horman <horms@verge.net.au> wrote:
> > On Thu, Oct 12, 2017 at 10:24:53AM +0200, Geert Uytterhoeven wrote:
> >> The module clock is used for two purposes:
> >>   - Wake-on-LAN (WoL), which is optional,
> >>   - gPTP Timer Increment (GTI) configuration, which is mandatory.
> >>
> >> As the clock is needed for GTI configuration anyway, WoL is always
> >> available.  Hence remove duplication and repeated obtaining of the clock
> >> by making GTI use the stored clock for WoL use.
> >
> > Hi Geert,
> >
> > I understand from the statements above that the clock must be present,
> > but I'm most sure that I understand why that means that WoL is always
> > available.
> 
> That refers to the part below: WoL was considered available iff the clock
> is available.
> 
> @@ -2073,10 +2058,11 @@ static int ravb_probe(struct platform_device *pdev)
> 
>         priv->chip_id = chip_id;
> 
> -       /* Get clock, if not found that's OK but Wake-On-Lan is unavailable */
>         priv->clk = devm_clk_get(&pdev->dev, NULL);
> -       if (IS_ERR(priv->clk))
> -               priv->clk = NULL;
> +       if (IS_ERR(priv->clk)) {
> +               error = PTR_ERR(priv->clk);
> +               goto out_release;
> +       }
> 
> But the clock must always be available, else GTI configuration
> would fail, and ravb initialization would return with an error.

Thanks, that was the information I had missed.

Belated:

Reviewed-by: Simon Horman <horms+renesas@verge.net.au>

^ permalink raw reply

* Re: [net-next V7 PATCH 1/5] bpf: introduce new bpf cpu map type BPF_MAP_TYPE_CPUMAP
From: Jesper Dangaard Brouer @ 2017-10-13  8:17 UTC (permalink / raw)
  To: Edward Cree
  Cc: netdev, jakub.kicinski, Michael S. Tsirkin, pavel.odintsov,
	Jason Wang, mchan, John Fastabend, peter.waskiewicz.jr, ast,
	Daniel Borkmann, Alexei Starovoitov, Andy Gospodarek, brouer
In-Reply-To: <de3a227a-da92-b905-11d0-ecc5a05f3bc0@solarflare.com>


On Thu, 12 Oct 2017 21:35:05 +0100 Edward Cree <ecree@solarflare.com> wrote:

> On 12/10/17 13:26, Jesper Dangaard Brouer wrote:
> > The 'cpumap' is primary used as a backend map for XDP BPF helper  
> s/primary/primarily.
>  [...]  
> Again, s/primary/primarily.
> > + * call bpf_redirect_map() and XDP_REDIRECT action, like 'devmap'.
> > + *
> > + * Unlike devmap which redirect XDP frames out another NIC device,
> > + * this map type redirect raw XDP frames to another CPU.  The remote  
> Also I think both of these 'redirect' should be 'redirects', just a
>  grammatical nit pick ;)
> > + * CPU will do SKB-allocation and call the normal network stack.
> > + *
> > + * This is a scalability and isolation mechanism, that allow
> > + * separating the early driver network XDP layer, from the rest of the
> > + * netstack, and assigning dedicated CPUs for this stage.  This
> > + * basically allows for 10G wirespeed pre-filtering via bpf.
> > + */
> > +#include <linux/bpf.h>
> > +#include <linux/filter.h>
> > +#include <linux/ptr_ring.h>
> > +
> > +#include <linux/sched.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/kthread.h>
> > +#include <linux/capability.h>
> > +
> > +/* General idea: XDP packets getting XDP redirected to another CPU,
> > + * will maximum be stored/queued for one driver ->poll() call.  It is
> > + * guaranteed that setting flush bit and flush operation happen on
> > + * same CPU.  Thus, cpu_map_flush operation can deduct via this_cpu_ptr()
> > + * which queue in bpf_cpu_map_entry contains packets.
> > + */
> > +
> > +#define CPU_MAP_BULK_SIZE 8  /* 8 == one cacheline on 64-bit archs */
> > +struct xdp_bulk_queue {
> > +	void *q[CPU_MAP_BULK_SIZE];
> > +	unsigned int count;
> > +};  
>
> I realise it's a bit late to say this on a v7, but it might be better to
>  use a linked-list (list_heads) here instead of an array.  Then, the
>  struct xdp_pkt you store in the packet headroom could contain the
>  list_head, there's no arbitrary bulking limit, and the flush just has
>  to link the newly-created elements into the receiving CPU's list.
> Is there an obvious reason why this wouldn't work / can't perform as
>  well, or should I try it and benchmark it?

No, I've tried to explain this before.  I do want a bulking limit for
several reasons. (1) This is connected to how ptr_ring works. I do want
to have a full cache-line to transfer/enqueue into the ptr_ring.  The
ptr_ring is the key to making the transfer between CPUs work so
efficiently (I even reject my own alf_queue in favor of ptr_ring).
(2) Due to latency concerns, I don't want to "wait" for 64 packets before
the remote CPU get a chance to see these. I want to transfer/enqueue
packets to the remote CPU as soon as possible, and due to cacheline
constraints this is 8 packets.

The ptr_ring goes to great lengths to avoid cache-line bouncing. Like
fb9de9704775 ("ptr_ring: batch ring zeroing") which helps avoid cache
line bouncing when queue is full. When queue is almost empty,
cache-line bouncing still occurs.  Which is what I'm trying to minimize
here by transfering/enqueueing a full cacheline.

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: VPLS in Linux
From: Amine Kherbouche @ 2017-10-13  8:32 UTC (permalink / raw)
  To: Алексей Болдырев,
	netdev
  Cc: Roopa Prabhu, David Lamparter
In-Reply-To: <5615811507880743@web42o.yandex.ru>

Hi,

I was pleased to try to get the patch in and to include my comments, but 
David was having better ideas. However, we do not hear news from David 
for a while.

David, please, are you still on it? If not, I'll try to find time to 
work on it, please share with us your intents.

Thanks,

Amine

On 10/13/2017 09:45 AM, Алексей Болдырев wrote:
> There was a message with patches of VPLS in the Linux kernel. But
 > they somehow did not fall into the next. What about the development
 > of the Linux subsystem in Linux?
>

^ permalink raw reply

* [net-next v2 00/18] tipc: Introduce Communcation Group feature
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion

With this commit series we introduce a 'Group Communication' feature in
order to resolve the datagram and multicast flow control problem. This 
new feature makes it possible for a user to instantiate multiple private
virtual brokerless message buses by just creating and joining member 
sockets.

The main features are as follows:
---------------------------------
- Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN.
  If it is the first socket of the group this implies creation of the
  group. This call takes four parameters: 'type' serves as group 
  identifier, 'instance' serves as member identifier, and 'scope' 
  indicates the visibility of the group (node/cluster/zone). Finally,
  'flags' indicates different options for the socket joining the group. 
  For the time being, there are only two such flags: 1) 'LOOPBACK'
  indicates if the creator of the socket wants to receive a copy of 
  broadcast or multicast messages it sends to the group, 2) EVENTS 
  indicates if it wants to receive membership (JOINED/LEFT) events for
  the other members of the group.

- Groups are closed, i.e., sockets which have not joined a group will
  not be able to send messages to or receive messages from members of
  the group, and vice versa. A socket can only be member of one group
  at a time.

- There are four transmission modes.
  1: Unicast. The sender transmits a message using the port identity
     (node:port tuple) of the receiving socket.
  2: Anycast. The sender transmits a message using a port name (type:
     instance:scope) of one of the receiving sockets. If more than
     one member socket matches the given address a destination is 
     selected according to a round-robin algorithm, but also considering
     the destination load (advertised window size) as an additional
     criteria.
  3: Multicast. The sender transmits a message using a port name 
     (type:instance:scope) of one or more of the receiving sockets.
     All sockets in the group matching the given address will receive
     a copy of the message. 
  4: Broadcast. The sender transmits a message using the primtive
     send(). All members of the group, irrespective of their member
     identity (instance) number receive a copy of the message.

- TIPC broadcast is used for carrying messages in mode 3 or 4 when
  this is deemed more efficient, i.e., depending on number of actual
  destinations.

- All transmission modes are flow controlled, so that messages never
  are dropped or rejected, just like we are used to from connection
  oriented communication. A special algorithm guarantees that this is
  true even for multipoint-to-point communication, i.e., at occasions
  where many source sockets may decide to send simultaneously towards
  the same  destination socket.

- Sequence order is always guaranteed, even between the different
  transmission modes.

- Member join/leave events are received in all other member sockets
  in guaranteed order. I.e., a 'JOINED' (an empty message with the OOB
  bit set) will always be received before the first data message from
  a new member, and a 'LEAVE' (like 'JOINED', but with EOR bit set) will
  always arrive after the last data message from a leaving member.

-----
v2: Reordered variable declarations in descending length order, as per
    feedback from David Miller. This was done as far as permitted by the
    the initialization order.

Jon Maloy (18):
  tipc: add ability to order and receive topology events in driver
  tipc: improve address sanity check in tipc_connect()
  tipc: add ability to obtain node availability status from other files
  tipc: refactor function filter_rcv()
  tipc: add new function for sending multiple small messages
  tipc: improve destination linked list
  tipc: introduce communication groups
  tipc: add second source address to recvmsg()/recvfrom()
  tipc: receive group membership events via member socket
  tipc: introduce flow control for group broadcast messages
  tipc: introduce group unicast messaging
  tipc: introduce group anycast messaging
  tipc: introduce group multicast messaging
  tipc: guarantee group unicast doesn't bypass group broadcast
  tipc: guarantee that group broadcast doesn't bypass group unicast
  tipc: guarantee delivery of UP event before first broadcast
  tipc: guarantee delivery of last broadcast before DOWN event
  tipc: add multipoint-to-point flow control

 include/uapi/linux/tipc.h |  15 +
 net/tipc/Makefile         |   2 +-
 net/tipc/bcast.c          |  18 +-
 net/tipc/core.h           |   5 +
 net/tipc/group.c          | 871 ++++++++++++++++++++++++++++++++++++++++++++++
 net/tipc/group.h          |  73 ++++
 net/tipc/link.c           |   9 +-
 net/tipc/msg.c            |   7 +
 net/tipc/msg.h            | 118 ++++++-
 net/tipc/name_table.c     | 174 ++++++---
 net/tipc/name_table.h     |  28 +-
 net/tipc/node.c           |  42 ++-
 net/tipc/node.h           |   5 +-
 net/tipc/server.c         | 121 +++++--
 net/tipc/server.h         |   5 +-
 net/tipc/socket.c         | 787 ++++++++++++++++++++++++++++++++---------
 16 files changed, 1997 insertions(+), 283 deletions(-)
 create mode 100644 net/tipc/group.c
 create mode 100644 net/tipc/group.h

-- 
2.1.4

^ permalink raw reply

* [net-next v2 01/18] tipc: add ability to order and receive topology events in driver
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

As preparation for introducing communication groups, we add the ability
to issue topology subscriptions and receive topology events from kernel
space. This will make it possible for group member sockets to keep track
of other group members.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/core.h   |   5 +++
 net/tipc/msg.h    |   1 +
 net/tipc/server.c | 121 ++++++++++++++++++++++++++++++++++++++++++------------
 net/tipc/server.h |   5 ++-
 net/tipc/socket.c |  32 +++++++++------
 5 files changed, 124 insertions(+), 40 deletions(-)

diff --git a/net/tipc/core.h b/net/tipc/core.h
index 5cc5398..9643426 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -132,6 +132,11 @@ static inline struct list_head *tipc_nodes(struct net *net)
 	return &tipc_net(net)->node_list;
 }
 
+static inline struct tipc_server *tipc_topsrv(struct net *net)
+{
+	return tipc_net(net)->topsrv;
+}
+
 static inline unsigned int tipc_hashfn(u32 addr)
 {
 	return addr & (NODE_HTABLE_SIZE - 1);
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index c843fd2..d058b1c 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -78,6 +78,7 @@ struct plist;
 #define  MSG_FRAGMENTER       12
 #define  LINK_CONFIG          13
 #define  SOCK_WAKEUP          14       /* pseudo user */
+#define  TOP_SRV              15       /* pseudo user */
 
 /*
  * Message header sizes
diff --git a/net/tipc/server.c b/net/tipc/server.c
index 3cd6402..7130775 100644
--- a/net/tipc/server.c
+++ b/net/tipc/server.c
@@ -36,6 +36,8 @@
 #include "server.h"
 #include "core.h"
 #include "socket.h"
+#include "addr.h"
+#include "msg.h"
 #include <net/sock.h>
 #include <linux/module.h>
 
@@ -105,13 +107,11 @@ static void tipc_conn_kref_release(struct kref *kref)
 		kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
 		sock_release(sock);
 		con->sock = NULL;
-
-		spin_lock_bh(&s->idr_lock);
-		idr_remove(&s->conn_idr, con->conid);
-		s->idr_in_use--;
-		spin_unlock_bh(&s->idr_lock);
 	}
-
+	spin_lock_bh(&s->idr_lock);
+	idr_remove(&s->conn_idr, con->conid);
+	s->idr_in_use--;
+	spin_unlock_bh(&s->idr_lock);
 	tipc_clean_outqueues(con);
 	kfree(con);
 }
@@ -197,7 +197,8 @@ static void tipc_close_conn(struct tipc_conn *con)
 	struct tipc_server *s = con->server;
 
 	if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
-		tipc_unregister_callbacks(con);
+		if (con->sock)
+			tipc_unregister_callbacks(con);
 
 		if (con->conid)
 			s->tipc_conn_release(con->conid, con->usr_data);
@@ -207,8 +208,8 @@ static void tipc_close_conn(struct tipc_conn *con)
 		 * are harmless for us here as we have already deleted this
 		 * connection from server connection list.
 		 */
-		kernel_sock_shutdown(con->sock, SHUT_RDWR);
-
+		if (con->sock)
+			kernel_sock_shutdown(con->sock, SHUT_RDWR);
 		conn_put(con);
 	}
 }
@@ -487,38 +488,104 @@ void tipc_conn_terminate(struct tipc_server *s, int conid)
 	}
 }
 
+bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type,
+			     u32 lower, u32 upper, int *conid)
+{
+	struct tipc_subscriber *scbr;
+	struct tipc_subscr sub;
+	struct tipc_server *s;
+	struct tipc_conn *con;
+
+	sub.seq.type = type;
+	sub.seq.lower = lower;
+	sub.seq.upper = upper;
+	sub.timeout = TIPC_WAIT_FOREVER;
+	sub.filter = TIPC_SUB_PORTS;
+	*(u32 *)&sub.usr_handle = port;
+
+	con = tipc_alloc_conn(tipc_topsrv(net));
+	if (!con)
+		return false;
+
+	*conid = con->conid;
+	s = con->server;
+	scbr = s->tipc_conn_new(*conid);
+	if (!scbr) {
+		tipc_close_conn(con);
+		return false;
+	}
+
+	con->usr_data = scbr;
+	con->sock = NULL;
+	s->tipc_conn_recvmsg(net, *conid, NULL, scbr, &sub, sizeof(sub));
+	return true;
+}
+
+void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
+{
+	struct tipc_conn *con;
+
+	con = tipc_conn_lookup(tipc_topsrv(net), conid);
+	if (!con)
+		return;
+	tipc_close_conn(con);
+	conn_put(con);
+}
+
+static void tipc_send_kern_top_evt(struct net *net, struct tipc_event *evt)
+{
+	u32 port = *(u32 *)&evt->s.usr_handle;
+	u32 self = tipc_own_addr(net);
+	struct sk_buff_head evtq;
+	struct sk_buff *skb;
+
+	skb = tipc_msg_create(TOP_SRV, 0, INT_H_SIZE, sizeof(*evt),
+			      self, self, port, port, 0);
+	if (!skb)
+		return;
+	msg_set_dest_droppable(buf_msg(skb), true);
+	memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt));
+	skb_queue_head_init(&evtq);
+	__skb_queue_tail(&evtq, skb);
+	tipc_sk_rcv(net, &evtq);
+}
+
 static void tipc_send_to_sock(struct tipc_conn *con)
 {
-	int count = 0;
 	struct tipc_server *s = con->server;
 	struct outqueue_entry *e;
+	struct tipc_event *evt;
 	struct msghdr msg;
+	int count = 0;
 	int ret;
 
 	spin_lock_bh(&con->outqueue_lock);
 	while (test_bit(CF_CONNECTED, &con->flags)) {
-		e = list_entry(con->outqueue.next, struct outqueue_entry,
-			       list);
+		e = list_entry(con->outqueue.next, struct outqueue_entry, list);
 		if ((struct list_head *) e == &con->outqueue)
 			break;
-		spin_unlock_bh(&con->outqueue_lock);
 
-		memset(&msg, 0, sizeof(msg));
-		msg.msg_flags = MSG_DONTWAIT;
+		spin_unlock_bh(&con->outqueue_lock);
 
-		if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
-			msg.msg_name = &e->dest;
-			msg.msg_namelen = sizeof(struct sockaddr_tipc);
-		}
-		ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
-				     e->iov.iov_len);
-		if (ret == -EWOULDBLOCK || ret == 0) {
-			cond_resched();
-			goto out;
-		} else if (ret < 0) {
-			goto send_err;
+		if (con->sock) {
+			memset(&msg, 0, sizeof(msg));
+			msg.msg_flags = MSG_DONTWAIT;
+			if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
+				msg.msg_name = &e->dest;
+				msg.msg_namelen = sizeof(struct sockaddr_tipc);
+			}
+			ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
+					     e->iov.iov_len);
+			if (ret == -EWOULDBLOCK || ret == 0) {
+				cond_resched();
+				goto out;
+			} else if (ret < 0) {
+				goto send_err;
+			}
+		} else {
+			evt = e->iov.iov_base;
+			tipc_send_kern_top_evt(s->net, evt);
 		}
-
 		/* Don't starve users filling buffers */
 		if (++count >= MAX_SEND_MSG_COUNT) {
 			cond_resched();
diff --git a/net/tipc/server.h b/net/tipc/server.h
index 34f8055..2113c91 100644
--- a/net/tipc/server.h
+++ b/net/tipc/server.h
@@ -83,13 +83,16 @@ struct tipc_server {
 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
 		      struct sockaddr_tipc *addr, void *data, size_t len);
 
+bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type,
+			     u32 lower, u32 upper, int *conid);
+void tipc_topsrv_kern_unsubscr(struct net *net, int conid);
+
 /**
  * tipc_conn_terminate - terminate connection with server
  *
  * Note: Must call it in process context since it might sleep
  */
 void tipc_conn_terminate(struct tipc_server *s, int conid);
-
 int tipc_server_start(struct tipc_server *s);
 
 void tipc_server_stop(struct tipc_server *s);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d50edd6..9a7e7b5c 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -896,6 +896,10 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
 	kfree_skb(skb);
 }
 
+static void tipc_sk_top_evt(struct tipc_sock *tsk, struct tipc_event *evt)
+{
+}
+
 /**
  * tipc_sendmsg - send message in connectionless manner
  * @sock: socket structure
@@ -1671,20 +1675,24 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
 	struct tipc_msg *hdr = buf_msg(skb);
 	unsigned int limit = rcvbuf_limit(sk, skb);
 	int err = TIPC_OK;
-	int usr = msg_user(hdr);
-	u32 onode;
-
-	if (unlikely(msg_user(hdr) == CONN_MANAGER)) {
-		tipc_sk_proto_rcv(tsk, skb, xmitq);
-		return false;
-	}
 
-	if (unlikely(usr == SOCK_WAKEUP)) {
-		onode = msg_orignode(hdr);
+	if (unlikely(!msg_isdata(hdr))) {
+		switch (msg_user(hdr)) {
+		case CONN_MANAGER:
+			tipc_sk_proto_rcv(tsk, skb, xmitq);
+			return false;
+		case SOCK_WAKEUP:
+			u32_del(&tsk->cong_links, msg_orignode(hdr));
+			tsk->cong_link_cnt--;
+			sk->sk_write_space(sk);
+			break;
+		case TOP_SRV:
+			tipc_sk_top_evt(tsk, (void *)msg_data(hdr));
+			break;
+		default:
+			break;
+		}
 		kfree_skb(skb);
-		u32_del(&tsk->cong_links, onode);
-		tsk->cong_link_cnt--;
-		sk->sk_write_space(sk);
 		return false;
 	}
 
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 04/18] tipc: refactor function filter_rcv()
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

In the following commits we will need to handle multiple incoming and
rejected/returned buffers in the function socket.c::filter_rcv().
As a preparation for this, we generalize the function by handling
buffer queues instead of individual buffers. We also introduce a
help function tipc_skb_reject(), and rename filter_rcv() to
tipc_sk_filter_rcv() in line with other functions in socket.c.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/msg.c    |   7 +++
 net/tipc/msg.h    |   2 +
 net/tipc/socket.c | 161 +++++++++++++++++++++++++++---------------------------
 3 files changed, 89 insertions(+), 81 deletions(-)

diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 17146c1..1649d45 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -666,3 +666,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
 	}
 	kfree_skb(skb);
 }
+
+void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
+		     struct sk_buff_head *xmitq)
+{
+	if (tipc_msg_reverse(tipc_own_addr(net), &skb, err))
+		__skb_queue_tail(xmitq, skb);
+}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index d058b1c..be3e38a 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -819,6 +819,8 @@ static inline bool msg_is_reset(struct tipc_msg *hdr)
 struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
 bool tipc_msg_validate(struct sk_buff *skb);
 bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
+void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
+		     struct sk_buff_head *xmitq);
 void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
 		   u32 hsize, u32 destnode);
 struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 7659e79..bc226f5 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -111,7 +111,7 @@ struct tipc_sock {
 	struct rcu_head rcu;
 };
 
-static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
+static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 static void tipc_data_ready(struct sock *sk);
 static void tipc_write_space(struct sock *sk);
 static void tipc_sock_destruct(struct sock *sk);
@@ -453,7 +453,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
 	msg_set_origport(msg, tsk->portid);
 	setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk);
 	sk->sk_shutdown = 0;
-	sk->sk_backlog_rcv = tipc_backlog_rcv;
+	sk->sk_backlog_rcv = tipc_sk_backlog_rcv;
 	sk->sk_rcvbuf = sysctl_tipc_rmem[1];
 	sk->sk_data_ready = tipc_data_ready;
 	sk->sk_write_space = tipc_write_space;
@@ -850,16 +850,16 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
 }
 
 /**
- * tipc_sk_proto_rcv - receive a connection mng protocol message
+ * tipc_sk_conn_proto_rcv - receive a connection mng protocol message
  * @tsk: receiving socket
  * @skb: pointer to message buffer.
  */
-static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
-			      struct sk_buff_head *xmitq)
+static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
+				   struct sk_buff_head *xmitq)
 {
-	struct sock *sk = &tsk->sk;
-	u32 onode = tsk_own_node(tsk);
 	struct tipc_msg *hdr = buf_msg(skb);
+	u32 onode = tsk_own_node(tsk);
+	struct sock *sk = &tsk->sk;
 	int mtyp = msg_type(hdr);
 	bool conn_cong;
 
@@ -1536,14 +1536,41 @@ static void tipc_sock_destruct(struct sock *sk)
 	__skb_queue_purge(&sk->sk_receive_queue);
 }
 
+static void tipc_sk_proto_rcv(struct sock *sk,
+			      struct sk_buff_head *inputq,
+			      struct sk_buff_head *xmitq)
+{
+	struct sk_buff *skb = __skb_dequeue(inputq);
+	struct tipc_sock *tsk = tipc_sk(sk);
+	struct tipc_msg *hdr = buf_msg(skb);
+
+	switch (msg_user(hdr)) {
+	case CONN_MANAGER:
+		tipc_sk_conn_proto_rcv(tsk, skb, xmitq);
+		return;
+	case SOCK_WAKEUP:
+		u32_del(&tsk->cong_links, msg_orignode(hdr));
+		tsk->cong_link_cnt--;
+		sk->sk_write_space(sk);
+		break;
+	case TOP_SRV:
+		tipc_sk_top_evt(tsk, (void *)msg_data(hdr));
+		break;
+	default:
+		break;
+	}
+
+	kfree_skb(skb);
+}
+
 /**
- * filter_connect - Handle all incoming messages for a connection-based socket
+ * tipc_filter_connect - Handle incoming message for a connection-based socket
  * @tsk: TIPC socket
  * @skb: pointer to message buffer. Set to NULL if buffer is consumed
  *
  * Returns true if everything ok, false otherwise
  */
-static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
+static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
 {
 	struct sock *sk = &tsk->sk;
 	struct net *net = sock_net(sk);
@@ -1657,7 +1684,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb)
 }
 
 /**
- * filter_rcv - validate incoming message
+ * tipc_sk_filter_rcv - validate incoming message
  * @sk: socket
  * @skb: pointer to message.
  *
@@ -1666,75 +1693,49 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb)
  *
  * Called with socket lock already taken
  *
- * Returns true if message was added to socket receive queue, otherwise false
  */
-static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
-		       struct sk_buff_head *xmitq)
+static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,
+			       struct sk_buff_head *xmitq)
 {
+	bool sk_conn = !tipc_sk_type_connectionless(sk);
 	struct tipc_sock *tsk = tipc_sk(sk);
 	struct tipc_msg *hdr = buf_msg(skb);
-	unsigned int limit = rcvbuf_limit(sk, skb);
-	int err = TIPC_OK;
+	struct net *net = sock_net(sk);
+	struct sk_buff_head inputq;
+	int limit, err = TIPC_OK;
 
-	if (unlikely(!msg_isdata(hdr))) {
-		switch (msg_user(hdr)) {
-		case CONN_MANAGER:
-			tipc_sk_proto_rcv(tsk, skb, xmitq);
-			return false;
-		case SOCK_WAKEUP:
-			u32_del(&tsk->cong_links, msg_orignode(hdr));
-			tsk->cong_link_cnt--;
-			sk->sk_write_space(sk);
-			break;
-		case TOP_SRV:
-			tipc_sk_top_evt(tsk, (void *)msg_data(hdr));
-			break;
-		default:
-			break;
-		}
-		kfree_skb(skb);
-		return false;
-	}
+	TIPC_SKB_CB(skb)->bytes_read = 0;
+	__skb_queue_head_init(&inputq);
+	__skb_queue_tail(&inputq, skb);
 
-	/* Drop if illegal message type */
-	if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) {
-		kfree_skb(skb);
-		return false;
-	}
+	if (unlikely(!msg_isdata(hdr)))
+		tipc_sk_proto_rcv(sk, &inputq, xmitq);
+	else if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG))
+		return kfree_skb(skb);
 
-	/* Reject if wrong message type for current socket state */
-	if (tipc_sk_type_connectionless(sk)) {
-		if (msg_connected(hdr)) {
+	/* Validate and add to receive buffer if there is space */
+	while ((skb = __skb_dequeue(&inputq))) {
+		hdr = buf_msg(skb);
+		limit = rcvbuf_limit(sk, skb);
+		if ((sk_conn && !tipc_sk_filter_connect(tsk, skb)) ||
+		    (!sk_conn && msg_connected(hdr)))
 			err = TIPC_ERR_NO_PORT;
-			goto reject;
-		}
-	} else if (unlikely(!filter_connect(tsk, skb))) {
-		err = TIPC_ERR_NO_PORT;
-		goto reject;
-	}
+		else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit)
+			err = TIPC_ERR_OVERLOAD;
 
-	/* Reject message if there isn't room to queue it */
-	if (unlikely(sk_rmem_alloc_get(sk) + skb->truesize >= limit)) {
-		err = TIPC_ERR_OVERLOAD;
-		goto reject;
+		if (unlikely(err)) {
+			tipc_skb_reject(net, err, skb, xmitq);
+			err = TIPC_OK;
+			continue;
+		}
+		__skb_queue_tail(&sk->sk_receive_queue, skb);
+		skb_set_owner_r(skb, sk);
+		sk->sk_data_ready(sk);
 	}
-
-	/* Enqueue message */
-	TIPC_SKB_CB(skb)->bytes_read = 0;
-	__skb_queue_tail(&sk->sk_receive_queue, skb);
-	skb_set_owner_r(skb, sk);
-
-	sk->sk_data_ready(sk);
-	return true;
-
-reject:
-	if (tipc_msg_reverse(tsk_own_node(tsk), &skb, err))
-		__skb_queue_tail(xmitq, skb);
-	return false;
 }
 
 /**
- * tipc_backlog_rcv - handle incoming message from backlog queue
+ * tipc_sk_backlog_rcv - handle incoming message from backlog queue
  * @sk: socket
  * @skb: message
  *
@@ -1742,27 +1743,25 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,
  *
  * Returns 0
  */
-static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
-	unsigned int truesize = skb->truesize;
+	unsigned int before = sk_rmem_alloc_get(sk);
 	struct sk_buff_head xmitq;
 	u32 dnode, selector;
+	unsigned int added;
 
 	__skb_queue_head_init(&xmitq);
 
-	if (likely(filter_rcv(sk, skb, &xmitq))) {
-		atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt);
-		return 0;
-	}
-
-	if (skb_queue_empty(&xmitq))
-		return 0;
+	tipc_sk_filter_rcv(sk, skb, &xmitq);
+	added = sk_rmem_alloc_get(sk) - before;
+	atomic_add(added, &tipc_sk(sk)->dupl_rcvcnt);
 
-	/* Send response/rejected message */
-	skb = __skb_dequeue(&xmitq);
-	dnode = msg_destnode(buf_msg(skb));
-	selector = msg_origport(buf_msg(skb));
-	tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
+	/* Send pending response/rejected messages, if any */
+	while ((skb = __skb_dequeue(&xmitq))) {
+		selector = msg_origport(buf_msg(skb));
+		dnode = msg_destnode(buf_msg(skb));
+		tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
+	}
 	return 0;
 }
 
@@ -1794,7 +1793,7 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
 
 		/* Add message directly to receive queue if possible */
 		if (!sock_owned_by_user(sk)) {
-			filter_rcv(sk, skb, xmitq);
+			tipc_sk_filter_rcv(sk, skb, xmitq);
 			continue;
 		}
 
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 06/18] tipc: improve destination linked list
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

We often see a need for a linked list of destination identities,
sometimes containing a port number, sometimes a node identity, and
sometimes both. The currently defined struct u32_list is not generic
enough to cover all cases, so we extend it to contain two u32 integers
and rename it to struct tipc_dest_list.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/bcast.c      | 18 +++++------
 net/tipc/name_table.c | 89 ++++++++++++++++++++++++++-------------------------
 net/tipc/name_table.h | 22 ++++++++-----
 net/tipc/socket.c     | 12 +++----
 4 files changed, 74 insertions(+), 67 deletions(-)

diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index a140dd4..329325bd 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -258,20 +258,20 @@ static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
 static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,
 			   struct tipc_nlist *dests, u16 *cong_link_cnt)
 {
+	struct tipc_dest *dst, *tmp;
 	struct sk_buff_head _pkts;
-	struct u32_item *n, *tmp;
-	u32 dst, selector;
+	u32 dnode, selector;
 
 	selector = msg_link_selector(buf_msg(skb_peek(pkts)));
 	skb_queue_head_init(&_pkts);
 
-	list_for_each_entry_safe(n, tmp, &dests->list, list) {
-		dst = n->value;
-		if (!tipc_msg_pskb_copy(dst, pkts, &_pkts))
+	list_for_each_entry_safe(dst, tmp, &dests->list, list) {
+		dnode = dst->node;
+		if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts))
 			return -ENOMEM;
 
 		/* Any other return value than -ELINKCONG is ignored */
-		if (tipc_node_xmit(net, &_pkts, dst, selector) == -ELINKCONG)
+		if (tipc_node_xmit(net, &_pkts, dnode, selector) == -ELINKCONG)
 			(*cong_link_cnt)++;
 	}
 	return 0;
@@ -554,7 +554,7 @@ void tipc_nlist_add(struct tipc_nlist *nl, u32 node)
 {
 	if (node == nl->self)
 		nl->local = true;
-	else if (u32_push(&nl->list, node))
+	else if (tipc_dest_push(&nl->list, node, 0))
 		nl->remote++;
 }
 
@@ -562,13 +562,13 @@ void tipc_nlist_del(struct tipc_nlist *nl, u32 node)
 {
 	if (node == nl->self)
 		nl->local = false;
-	else if (u32_del(&nl->list, node))
+	else if (tipc_dest_del(&nl->list, node, 0))
 		nl->remote--;
 }
 
 void tipc_nlist_purge(struct tipc_nlist *nl)
 {
-	u32_list_purge(&nl->list);
+	tipc_dest_list_purge(&nl->list);
 	nl->remote = 0;
 	nl->local = 0;
 }
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index bd0aac8..76bd277 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -634,7 +634,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
 		info = sseq->info;
 		list_for_each_entry(publ, &info->node_list, node_list) {
 			if (publ->scope <= limit)
-				u32_push(dports, publ->ref);
+				tipc_dest_push(dports, 0, publ->ref);
 		}
 
 		if (info->cluster_list_size != info->node_list_size)
@@ -1057,78 +1057,79 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
-bool u32_find(struct list_head *l, u32 value)
+struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port)
 {
-	struct u32_item *item;
+	u64 value = (u64)node << 32 | port;
+	struct tipc_dest *dst;
 
-	list_for_each_entry(item, l, list) {
-		if (item->value == value)
-			return true;
+	list_for_each_entry(dst, l, list) {
+		if (dst->value != value)
+			continue;
+		return dst;
 	}
-	return false;
+	return NULL;
 }
 
-bool u32_push(struct list_head *l, u32 value)
+bool tipc_dest_push(struct list_head *l, u32 node, u32 port)
 {
-	struct u32_item *item;
+	u64 value = (u64)node << 32 | port;
+	struct tipc_dest *dst;
 
-	list_for_each_entry(item, l, list) {
-		if (item->value == value)
-			return false;
-	}
-	item = kmalloc(sizeof(*item), GFP_ATOMIC);
-	if (unlikely(!item))
+	if (tipc_dest_find(l, node, port))
 		return false;
 
-	item->value = value;
-	list_add(&item->list, l);
+	dst = kmalloc(sizeof(*dst), GFP_ATOMIC);
+	if (unlikely(!dst))
+		return false;
+	dst->value = value;
+	list_add(&dst->list, l);
 	return true;
 }
 
-u32 u32_pop(struct list_head *l)
+bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port)
 {
-	struct u32_item *item;
-	u32 value = 0;
+	struct tipc_dest *dst;
 
 	if (list_empty(l))
-		return 0;
-	item = list_first_entry(l, typeof(*item), list);
-	value = item->value;
-	list_del(&item->list);
-	kfree(item);
-	return value;
+		return false;
+	dst = list_first_entry(l, typeof(*dst), list);
+	if (port)
+		*port = dst->port;
+	if (node)
+		*node = dst->node;
+	list_del(&dst->list);
+	kfree(dst);
+	return true;
 }
 
-bool u32_del(struct list_head *l, u32 value)
+bool tipc_dest_del(struct list_head *l, u32 node, u32 port)
 {
-	struct u32_item *item, *tmp;
+	struct tipc_dest *dst;
 
-	list_for_each_entry_safe(item, tmp, l, list) {
-		if (item->value != value)
-			continue;
-		list_del(&item->list);
-		kfree(item);
-		return true;
-	}
-	return false;
+	dst = tipc_dest_find(l, node, port);
+	if (!dst)
+		return false;
+	list_del(&dst->list);
+	kfree(dst);
+	return true;
 }
 
-void u32_list_purge(struct list_head *l)
+void tipc_dest_list_purge(struct list_head *l)
 {
-	struct u32_item *item, *tmp;
+	struct tipc_dest *dst, *tmp;
 
-	list_for_each_entry_safe(item, tmp, l, list) {
-		list_del(&item->list);
-		kfree(item);
+	list_for_each_entry_safe(dst, tmp, l, list) {
+		list_del(&dst->list);
+		kfree(dst);
 	}
 }
 
-int u32_list_len(struct list_head *l)
+int tipc_dest_list_len(struct list_head *l)
 {
-	struct u32_item *item;
+	struct tipc_dest *dst;
 	int i = 0;
 
-	list_for_each_entry(item, l, list) {
+	list_for_each_entry(dst, l, list) {
 		i++;
 	}
 	return i;
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
index 6ebdeb1..d121175 100644
--- a/net/tipc/name_table.h
+++ b/net/tipc/name_table.h
@@ -120,16 +120,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
 int tipc_nametbl_init(struct net *net);
 void tipc_nametbl_stop(struct net *net);
 
-struct u32_item {
+struct tipc_dest {
 	struct list_head list;
-	u32 value;
+	union {
+		struct {
+			u32 port;
+			u32 node;
+		};
+		u64 value;
+	};
 };
 
-bool u32_push(struct list_head *l, u32 value);
-u32 u32_pop(struct list_head *l);
-bool u32_find(struct list_head *l, u32 value);
-bool u32_del(struct list_head *l, u32 value);
-void u32_list_purge(struct list_head *l);
-int u32_list_len(struct list_head *l);
+struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port);
+bool tipc_dest_push(struct list_head *l, u32 node, u32 port);
+bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port);
+bool tipc_dest_del(struct list_head *l, u32 node, u32 port);
+void tipc_dest_list_purge(struct list_head *l);
+int tipc_dest_list_len(struct list_head *l);
 
 #endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index c7c6749..daf7c4d 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -565,7 +565,7 @@ static int tipc_release(struct socket *sock)
 
 	/* Reject any messages that accumulated in backlog queue */
 	release_sock(sk);
-	u32_list_purge(&tsk->cong_links);
+	tipc_dest_list_purge(&tsk->cong_links);
 	tsk->cong_link_cnt = 0;
 	call_rcu(&tsk->rcu, tipc_sk_callback);
 	sock->sk = NULL;
@@ -826,8 +826,7 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
 		tipc_nametbl_mc_translate(net,
 					  msg_nametype(msg), msg_namelower(msg),
 					  msg_nameupper(msg), scope, &dports);
-		portid = u32_pop(&dports);
-		for (; portid; portid = u32_pop(&dports)) {
+		while (tipc_dest_pop(&dports, NULL, &portid)) {
 			_skb = __pskb_copy(skb, hsz, GFP_ATOMIC);
 			if (_skb) {
 				msg_set_destport(buf_msg(_skb), portid);
@@ -1000,7 +999,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
 	}
 
 	/* Block or return if destination link is congested */
-	rc = tipc_wait_for_cond(sock, &timeout, !u32_find(clinks, dnode));
+	rc = tipc_wait_for_cond(sock, &timeout,
+				!tipc_dest_find(clinks, dnode, 0));
 	if (unlikely(rc))
 		return rc;
 
@@ -1012,7 +1012,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
 
 	rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
 	if (unlikely(rc == -ELINKCONG)) {
-		u32_push(clinks, dnode);
+		tipc_dest_push(clinks, dnode, 0);
 		tsk->cong_link_cnt++;
 		rc = 0;
 	}
@@ -1549,7 +1549,7 @@ static void tipc_sk_proto_rcv(struct sock *sk,
 		tipc_sk_conn_proto_rcv(tsk, skb, xmitq);
 		return;
 	case SOCK_WAKEUP:
-		u32_del(&tsk->cong_links, msg_orignode(hdr));
+		tipc_dest_del(&tsk->cong_links, msg_orignode(hdr), 0);
 		tsk->cong_link_cnt--;
 		sk->sk_write_space(sk);
 		break;
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 02/18] tipc: improve address sanity check in tipc_connect()
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

The address given to tipc_connect() is not completely sanity checked,
under the assumption that this will be done later in the function
__tipc_sendmsg() when the address is used there.

However, the latter functon will in the next commits serve as caller
to several other send functions, so we want to move the corresponding
sanity check there to the beginning of that function, before we possibly
need to grab the address stored by tipc_connect(). We must therefore
be able to trust that this address already has been thoroughly checked.

We do this in this commit.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/socket.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 9a7e7b5c..7659e79 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1911,28 +1911,27 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest,
 	int previous;
 	int res = 0;
 
+	if (destlen != sizeof(struct sockaddr_tipc))
+		return -EINVAL;
+
 	lock_sock(sk);
 
-	/* DGRAM/RDM connect(), just save the destaddr */
-	if (tipc_sk_type_connectionless(sk)) {
-		if (dst->family == AF_UNSPEC) {
-			memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc));
-		} else if (destlen != sizeof(struct sockaddr_tipc)) {
+	if (dst->family == AF_UNSPEC) {
+		memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc));
+		if (!tipc_sk_type_connectionless(sk))
 			res = -EINVAL;
-		} else {
-			memcpy(&tsk->peer, dest, destlen);
-		}
 		goto exit;
+	} else if (dst->family != AF_TIPC) {
+		res = -EINVAL;
 	}
-
-	/*
-	 * Reject connection attempt using multicast address
-	 *
-	 * Note: send_msg() validates the rest of the address fields,
-	 *       so there's no need to do it here
-	 */
-	if (dst->addrtype == TIPC_ADDR_MCAST) {
+	if (dst->addrtype != TIPC_ADDR_ID && dst->addrtype != TIPC_ADDR_NAME)
 		res = -EINVAL;
+	if (res)
+		goto exit;
+
+	/* DGRAM/RDM connect(), just save the destaddr */
+	if (tipc_sk_type_connectionless(sk)) {
+		memcpy(&tsk->peer, dest, destlen);
 		goto exit;
 	}
 
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 03/18] tipc: add ability to obtain node availability status from other files
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

In the coming commits, functions at the socket level will need the
ability to read the availability status of a given node. We therefore
introduce a new function for this purpose, while renaming the existing
static function currently having the wanted name.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/node.c | 26 +++++++++++++++++++++-----
 net/tipc/node.h |  1 +
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/net/tipc/node.c b/net/tipc/node.c
index 198dbc7..6cc1ae6 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -157,7 +157,7 @@ static void tipc_node_timeout(unsigned long data);
 static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
 static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
 static void tipc_node_put(struct tipc_node *node);
-static bool tipc_node_is_up(struct tipc_node *n);
+static bool node_is_up(struct tipc_node *n);
 
 struct tipc_sock_conn {
 	u32 port;
@@ -657,7 +657,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
 		*slot1 = i;
 	}
 
-	if (!tipc_node_is_up(n)) {
+	if (!node_is_up(n)) {
 		if (tipc_link_peer_is_down(l))
 			tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);
 		tipc_node_fsm_evt(n, SELF_LOST_CONTACT_EVT);
@@ -717,11 +717,27 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
 	tipc_sk_rcv(n->net, &le->inputq);
 }
 
-static bool tipc_node_is_up(struct tipc_node *n)
+static bool node_is_up(struct tipc_node *n)
 {
 	return n->active_links[0] != INVALID_BEARER_ID;
 }
 
+bool tipc_node_is_up(struct net *net, u32 addr)
+{
+	struct tipc_node *n;
+	bool retval = false;
+
+	if (in_own_node(net, addr))
+		return true;
+
+	n = tipc_node_find(net, addr);
+	if (!n)
+		return false;
+	retval = node_is_up(n);
+	tipc_node_put(n);
+	return retval;
+}
+
 void tipc_node_check_dest(struct net *net, u32 onode,
 			  struct tipc_bearer *b,
 			  u16 capabilities, u32 signature,
@@ -1149,7 +1165,7 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
 
 	if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr))
 		goto attr_msg_full;
-	if (tipc_node_is_up(node))
+	if (node_is_up(node))
 		if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP))
 			goto attr_msg_full;
 
@@ -1249,7 +1265,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
 		dst = n->addr;
 		if (in_own_node(net, dst))
 			continue;
-		if (!tipc_node_is_up(n))
+		if (!node_is_up(n))
 			continue;
 		txskb = pskb_copy(skb, GFP_ATOMIC);
 		if (!txskb)
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 898c229..8db59fe 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -76,6 +76,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb);
 int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port);
 void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);
 int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel);
+bool tipc_node_is_up(struct net *net, u32 addr);
 u16 tipc_node_get_capabilities(struct net *net, u32 addr);
 int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb);
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 08/18] tipc: add second source address to recvmsg()/recvfrom()
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

With group communication, it becomes important for a message receiver to
identify not only from which socket (identfied by a node:port tuple) the
message was sent, but also the logical identity (type:instance) of the
sending member.

We fix this by adding a second instance of struct sockaddr_tipc to the
source address area when a message is read. The extra address struct
is filled in with data found in the received message header (type,) and
in the local member representation struct (instance.)

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/group.c  |  3 +++
 net/tipc/msg.h    |  1 +
 net/tipc/socket.c | 53 +++++++++++++++++++++++++++++++++++------------------
 3 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/net/tipc/group.c b/net/tipc/group.c
index 3f0e1ce..beb214a 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -61,6 +61,7 @@ struct tipc_member {
 	struct list_head list;
 	u32 node;
 	u32 port;
+	u32 instance;
 	enum mbr_state state;
 	u16 bc_rcv_nxt;
 };
@@ -282,6 +283,7 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
 	if (!tipc_group_is_receiver(m))
 		goto drop;
 
+	TIPC_SKB_CB(skb)->orig_member = m->instance;
 	__skb_queue_tail(inputq, skb);
 
 	m->bc_rcv_nxt = msg_grp_bc_seqno(hdr) + 1;
@@ -388,6 +390,7 @@ void tipc_group_member_evt(struct tipc_group *grp,
 			m->state = MBR_PUBLISHED;
 		else
 			m->state = MBR_JOINED;
+		m->instance = evt->found_lower;
 		tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
 	} else if (evt->event == TIPC_WITHDRAWN) {
 		if (!m)
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index dad4009..e438716 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -100,6 +100,7 @@ struct plist;
 
 struct tipc_skb_cb {
 	u32 bytes_read;
+	u32 orig_member;
 	struct sk_buff *tail;
 	bool validated;
 	u16 chain_imp;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 64bbf9d..25ecf12 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -62,6 +62,11 @@ enum {
 	TIPC_CONNECTING = TCP_SYN_SENT,
 };
 
+struct sockaddr_pair {
+	struct sockaddr_tipc sock;
+	struct sockaddr_tipc member;
+};
+
 /**
  * struct tipc_sock - TIPC socket structure
  * @sk: socket - interacts with 'port' and with user via the socket API
@@ -1222,26 +1227,38 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
 }
 
 /**
- * set_orig_addr - capture sender's address for received message
+ * tipc_sk_set_orig_addr - capture sender's address for received message
  * @m: descriptor for message info
- * @msg: received message header
+ * @hdr: received message header
  *
  * Note: Address is not captured if not requested by receiver.
  */
-static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
-{
-	DECLARE_SOCKADDR(struct sockaddr_tipc *, addr, m->msg_name);
-
-	if (addr) {
-		addr->family = AF_TIPC;
-		addr->addrtype = TIPC_ADDR_ID;
-		memset(&addr->addr, 0, sizeof(addr->addr));
-		addr->addr.id.ref = msg_origport(msg);
-		addr->addr.id.node = msg_orignode(msg);
-		addr->addr.name.domain = 0;	/* could leave uninitialized */
-		addr->scope = 0;		/* could leave uninitialized */
-		m->msg_namelen = sizeof(struct sockaddr_tipc);
-	}
+static void tipc_sk_set_orig_addr(struct msghdr *m, struct sk_buff *skb)
+{
+	DECLARE_SOCKADDR(struct sockaddr_pair *, srcaddr, m->msg_name);
+	struct tipc_msg *hdr = buf_msg(skb);
+
+	if (!srcaddr)
+		return;
+
+	srcaddr->sock.family = AF_TIPC;
+	srcaddr->sock.addrtype = TIPC_ADDR_ID;
+	srcaddr->sock.addr.id.ref = msg_origport(hdr);
+	srcaddr->sock.addr.id.node = msg_orignode(hdr);
+	srcaddr->sock.addr.name.domain = 0;
+	srcaddr->sock.scope = 0;
+	m->msg_namelen = sizeof(struct sockaddr_tipc);
+
+	if (!msg_in_group(hdr))
+		return;
+
+	/* Group message users may also want to know sending member's id */
+	srcaddr->member.family = AF_TIPC;
+	srcaddr->member.addrtype = TIPC_ADDR_NAME;
+	srcaddr->member.addr.name.name.type = msg_nametype(hdr);
+	srcaddr->member.addr.name.name.instance = TIPC_SKB_CB(skb)->orig_member;
+	srcaddr->member.addr.name.domain = 0;
+	m->msg_namelen = sizeof(*srcaddr);
 }
 
 /**
@@ -1432,7 +1449,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
 	} while (1);
 
 	/* Collect msg meta data, including error code and rejected data */
-	set_orig_addr(m, hdr);
+	tipc_sk_set_orig_addr(m, skb);
 	rc = tipc_sk_anc_data_recv(m, hdr, tsk);
 	if (unlikely(rc))
 		goto exit;
@@ -1526,7 +1543,7 @@ static int tipc_recvstream(struct socket *sock, struct msghdr *m,
 
 		/* Collect msg meta data, incl. error code and rejected data */
 		if (!copied) {
-			set_orig_addr(m, hdr);
+			tipc_sk_set_orig_addr(m, skb);
 			rc = tipc_sk_anc_data_recv(m, hdr, tsk);
 			if (rc)
 				break;
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 16/18] tipc: guarantee delivery of UP event before first broadcast
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

The following scenario is possible:
- A user joins a group, and immediately sends out a broadcast message
  to its members.
- The broadcast message, following a different data path than the
  initial JOIN message sent out during the joining procedure, arrives
  to a receiver before the latter..
- The receiver drops the message, since it is not ready to accept any
  messages until the JOIN has arrived.

We avoid this by treating group protocol JOIN messages like unicast
messages.
- We let them pass through the recipient's multicast input queue, just
  like ordinary unicasts.
- We force the first following broadacst to be sent as replicated
  unicast and being acknowledged by the recipient before accepting
  any more broadcast transmissions.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/link.c   | 7 +++++--
 net/tipc/socket.c | 4 ++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/tipc/link.c b/net/tipc/link.c
index 70a2149..723dd69 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1039,6 +1039,7 @@ int tipc_link_retrans(struct tipc_link *l, struct tipc_link *nacker,
 static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
 			    struct sk_buff_head *inputq)
 {
+	struct sk_buff_head *mc_inputq = l->bc_rcvlink->inputq;
 	struct tipc_msg *hdr = buf_msg(skb);
 
 	switch (msg_user(hdr)) {
@@ -1047,12 +1048,14 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
 	case TIPC_HIGH_IMPORTANCE:
 	case TIPC_CRITICAL_IMPORTANCE:
 		if (unlikely(msg_in_group(hdr) || msg_mcast(hdr))) {
-			skb_queue_tail(l->bc_rcvlink->inputq, skb);
+			skb_queue_tail(mc_inputq, skb);
 			return true;
 		}
-	case GROUP_PROTOCOL:
 	case CONN_MANAGER:
 		return true;
+	case GROUP_PROTOCOL:
+		skb_queue_tail(mc_inputq, skb);
+		return true;
 	case NAME_DISTRIBUTOR:
 		l->bc_rcvlink->state = LINK_ESTABLISHED;
 		skb_queue_tail(l->namedq, skb);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index b1f1c3c..2bbab4f 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2762,6 +2762,10 @@ static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq)
 	rc = tipc_sk_publish(tsk, mreq->scope, &seq);
 	if (rc)
 		tipc_group_delete(net, grp);
+
+	/* Eliminate any risk that a broadcast overtakes the sent JOIN */
+	tsk->mc_method.rcast = true;
+	tsk->mc_method.mandatory = true;
 	return rc;
 }
 
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 09/18] tipc: receive group membership events via member socket
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

Like with any other service, group members' availability can be
subscribed for by connecting to be topology server. However, because
the events arrive via a different socket than the member socket, there
is a real risk that membership events my arrive out of synch with the
actual JOIN/LEAVE action. I.e., it is possible to receive the first
messages from a new member before the corresponding JOIN event arrives,
just as it is possible to receive the last messages from a leaving
member after the LEAVE event has already been received.

Since each member socket is internally also subscribing for membership
events, we now fix this problem by passing those events on to the user
via the member socket. We leverage the already present member synch-
ronization protocol to guarantee correct message/event order. An event
is delivered to the user as an empty message where the two source
addresses identify the new/lost member. Furthermore, we set the MSG_OOB
bit in the message flags to mark it as an event. If the event is an
indication about a member loss we also set the MSG_EOR bit, so it can
be distinguished from a member addition event.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 include/uapi/linux/tipc.h |  1 +
 net/tipc/group.c          | 60 +++++++++++++++++++++++++++++++++++++----------
 net/tipc/group.h          |  2 ++
 net/tipc/msg.h            | 22 +++++++++++++++--
 net/tipc/socket.c         | 49 ++++++++++++++++++++++++--------------
 5 files changed, 101 insertions(+), 33 deletions(-)

diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h
index 5f7b2c4..ef41c11 100644
--- a/include/uapi/linux/tipc.h
+++ b/include/uapi/linux/tipc.h
@@ -238,6 +238,7 @@ struct sockaddr_tipc {
  * Flag values
  */
 #define TIPC_GROUP_LOOPBACK     0x1  /* Receive copy of sent msg when match */
+#define TIPC_GROUP_MEMBER_EVTS  0x2  /* Receive membership events in socket */
 
 struct tipc_group_req {
 	__u32 type;      /* group id */
diff --git a/net/tipc/group.c b/net/tipc/group.c
index beb214a..1bfa934 100644
--- a/net/tipc/group.c
+++ b/net/tipc/group.c
@@ -59,6 +59,7 @@ enum mbr_state {
 struct tipc_member {
 	struct rb_node tree_node;
 	struct list_head list;
+	struct sk_buff *event_msg;
 	u32 node;
 	u32 port;
 	u32 instance;
@@ -79,6 +80,7 @@ struct tipc_group {
 	u16 member_cnt;
 	u16 bc_snd_nxt;
 	bool loopback;
+	bool events;
 };
 
 static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
@@ -117,6 +119,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid,
 	grp->instance = mreq->instance;
 	grp->scope = mreq->scope;
 	grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
+	grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
 	if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, &grp->subid))
 		return grp;
 	kfree(grp);
@@ -279,6 +282,13 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
 	if (!msg_in_group(hdr))
 		goto drop;
 
+	if (mtyp == TIPC_GRP_MEMBER_EVT) {
+		if (!grp->events)
+			goto drop;
+		__skb_queue_tail(inputq, skb);
+		return;
+	}
+
 	m = tipc_group_find_member(grp, node, port);
 	if (!tipc_group_is_receiver(m))
 		goto drop;
@@ -311,6 +321,7 @@ static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
 }
 
 void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
+			  struct sk_buff_head *inputq,
 			  struct sk_buff_head *xmitq)
 {
 	u32 node = msg_orignode(hdr);
@@ -332,10 +343,12 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
 		m->bc_rcv_nxt = msg_grp_bc_syncpt(hdr);
 
 		/* Wait until PUBLISH event is received */
-		if (m->state == MBR_DISCOVERED)
+		if (m->state == MBR_DISCOVERED) {
 			m->state = MBR_JOINING;
-		else if (m->state == MBR_PUBLISHED)
+		} else if (m->state == MBR_PUBLISHED) {
 			m->state = MBR_JOINED;
+			__skb_queue_tail(inputq, m->event_msg);
+		}
 		return;
 	case GRP_LEAVE_MSG:
 		if (!m)
@@ -347,6 +360,7 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
 			return;
 		}
 		/* Otherwise deliver already received WITHDRAW event */
+		__skb_queue_tail(inputq, m->event_msg);
 		tipc_group_delete_member(grp, m);
 		return;
 	default:
@@ -354,16 +368,17 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
 	}
 }
 
-/* tipc_group_member_evt() - receive and handle a member up/down event
- */
 void tipc_group_member_evt(struct tipc_group *grp,
 			   struct sk_buff *skb,
+			   struct sk_buff_head *inputq,
 			   struct sk_buff_head *xmitq)
 {
 	struct tipc_msg *hdr = buf_msg(skb);
 	struct tipc_event *evt = (void *)msg_data(hdr);
+	u32 instance = evt->found_lower;
 	u32 node = evt->port.node;
 	u32 port = evt->port.ref;
+	int event = evt->event;
 	struct tipc_member *m;
 	struct net *net;
 	u32 self;
@@ -376,32 +391,51 @@ void tipc_group_member_evt(struct tipc_group *grp,
 	if (!grp->loopback && node == self && port == grp->portid)
 		goto drop;
 
+	/* Convert message before delivery to user */
+	msg_set_hdr_sz(hdr, GROUP_H_SIZE);
+	msg_set_user(hdr, TIPC_CRITICAL_IMPORTANCE);
+	msg_set_type(hdr, TIPC_GRP_MEMBER_EVT);
+	msg_set_origport(hdr, port);
+	msg_set_orignode(hdr, node);
+	msg_set_nametype(hdr, grp->type);
+	msg_set_grp_evt(hdr, event);
+
 	m = tipc_group_find_member(grp, node, port);
 
-	if (evt->event == TIPC_PUBLISHED) {
+	if (event == TIPC_PUBLISHED) {
 		if (!m)
 			m = tipc_group_create_member(grp, node, port,
 						     MBR_DISCOVERED);
 		if (!m)
 			goto drop;
 
-		/* Wait if JOIN message not yet received */
-		if (m->state == MBR_DISCOVERED)
+		/* Hold back event if JOIN message not yet received */
+		if (m->state == MBR_DISCOVERED) {
+			m->event_msg = skb;
 			m->state = MBR_PUBLISHED;
-		else
+		} else {
+			__skb_queue_tail(inputq, skb);
 			m->state = MBR_JOINED;
-		m->instance = evt->found_lower;
+		}
+		m->instance = instance;
+		TIPC_SKB_CB(skb)->orig_member = m->instance;
 		tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
-	} else if (evt->event == TIPC_WITHDRAWN) {
+	} else if (event == TIPC_WITHDRAWN) {
 		if (!m)
 			goto drop;
 
-		/* Keep back event if more messages might be expected */
-		if (m->state != MBR_LEAVING && tipc_node_is_up(net, node))
+		TIPC_SKB_CB(skb)->orig_member = m->instance;
+
+		/* Hold back event if more messages might be expected */
+		if (m->state != MBR_LEAVING && tipc_node_is_up(net, node)) {
+			m->event_msg = skb;
 			m->state = MBR_LEAVING;
-		else
+		} else {
+			__skb_queue_tail(inputq, skb);
 			tipc_group_delete_member(grp, m);
+		}
 	}
+	return;
 drop:
 	kfree_skb(skb);
 }
diff --git a/net/tipc/group.h b/net/tipc/group.h
index 9bdf447..5d3f10d 100644
--- a/net/tipc/group.h
+++ b/net/tipc/group.h
@@ -54,9 +54,11 @@ void tipc_group_filter_msg(struct tipc_group *grp,
 			   struct sk_buff_head *xmitq);
 void tipc_group_member_evt(struct tipc_group *grp,
 			   struct sk_buff *skb,
+			   struct sk_buff_head *inputq,
 			   struct sk_buff_head *xmitq);
 void tipc_group_proto_rcv(struct tipc_group *grp,
 			  struct tipc_msg *hdr,
+			  struct sk_buff_head *inputq,
 			  struct sk_buff_head *xmitq);
 void tipc_group_update_bc_members(struct tipc_group *grp);
 u16 tipc_group_bc_snd_nxt(struct tipc_group *grp);
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index e438716..1b527b1 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -65,7 +65,8 @@ struct plist;
 #define TIPC_MCAST_MSG          1
 #define TIPC_NAMED_MSG          2
 #define TIPC_DIRECT_MSG         3
-#define TIPC_GRP_BCAST_MSG      4
+#define TIPC_GRP_MEMBER_EVT     4
+#define TIPC_GRP_BCAST_MSG      5
 
 /*
  * Internal message users
@@ -258,7 +259,14 @@ static inline void msg_set_type(struct tipc_msg *m, u32 n)
 
 static inline int msg_in_group(struct tipc_msg *m)
 {
-	return (msg_type(m) == TIPC_GRP_BCAST_MSG);
+	int mtyp = msg_type(m);
+
+	return (mtyp == TIPC_GRP_BCAST_MSG) || (mtyp == TIPC_GRP_MEMBER_EVT);
+}
+
+static inline bool msg_is_grp_evt(struct tipc_msg *m)
+{
+	return msg_type(m) == TIPC_GRP_MEMBER_EVT;
 }
 
 static inline u32 msg_named(struct tipc_msg *m)
@@ -824,6 +832,16 @@ static inline void msg_set_grp_bc_syncpt(struct tipc_msg *m, u16 n)
 
 /* Word 10
  */
+static inline u16 msg_grp_evt(struct tipc_msg *m)
+{
+	return msg_bits(m, 10, 0, 0x3);
+}
+
+static inline void msg_set_grp_evt(struct tipc_msg *m, int n)
+{
+	msg_set_bits(m, 10, 0, 0x3, n);
+}
+
 static inline u16 msg_grp_bc_seqno(struct tipc_msg *m)
 {
 	return msg_bits(m, 10, 16, 0xffff);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 25ecf12..0a2eac30 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -709,41 +709,43 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
 			      poll_table *wait)
 {
 	struct sock *sk = sock->sk;
+	struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
 	struct tipc_sock *tsk = tipc_sk(sk);
 	struct tipc_group *grp = tsk->group;
-	u32 mask = 0;
+	u32 revents = 0;
 
 	sock_poll_wait(file, sk_sleep(sk), wait);
 
 	if (sk->sk_shutdown & RCV_SHUTDOWN)
-		mask |= POLLRDHUP | POLLIN | POLLRDNORM;
+		revents |= POLLRDHUP | POLLIN | POLLRDNORM;
 	if (sk->sk_shutdown == SHUTDOWN_MASK)
-		mask |= POLLHUP;
+		revents |= POLLHUP;
 
 	switch (sk->sk_state) {
 	case TIPC_ESTABLISHED:
 		if (!tsk->cong_link_cnt && !tsk_conn_cong(tsk))
-			mask |= POLLOUT;
+			revents |= POLLOUT;
 		/* fall thru' */
 	case TIPC_LISTEN:
 	case TIPC_CONNECTING:
-		if (!skb_queue_empty(&sk->sk_receive_queue))
-			mask |= (POLLIN | POLLRDNORM);
+		if (skb)
+			revents |= POLLIN | POLLRDNORM;
 		break;
 	case TIPC_OPEN:
 		if (!grp || tipc_group_size(grp))
 			if (!tsk->cong_link_cnt)
-				mask |= POLLOUT;
-		if (tipc_sk_type_connectionless(sk) &&
-		    (!skb_queue_empty(&sk->sk_receive_queue)))
-			mask |= (POLLIN | POLLRDNORM);
+				revents |= POLLOUT;
+		if (!tipc_sk_type_connectionless(sk))
+			break;
+		if (!skb)
+			break;
+		revents |= POLLIN | POLLRDNORM;
 		break;
 	case TIPC_DISCONNECTING:
-		mask = (POLLIN | POLLRDNORM | POLLHUP);
+		revents = POLLIN | POLLRDNORM | POLLHUP;
 		break;
 	}
-
-	return mask;
+	return revents;
 }
 
 /**
@@ -1415,11 +1417,12 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
 			size_t buflen,	int flags)
 {
 	struct sock *sk = sock->sk;
-	struct tipc_sock *tsk = tipc_sk(sk);
-	struct sk_buff *skb;
-	struct tipc_msg *hdr;
 	bool connected = !tipc_sk_type_connectionless(sk);
+	struct tipc_sock *tsk = tipc_sk(sk);
 	int rc, err, hlen, dlen, copy;
+	struct tipc_msg *hdr;
+	struct sk_buff *skb;
+	bool grp_evt;
 	long timeout;
 
 	/* Catch invalid receive requests */
@@ -1443,6 +1446,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
 		dlen = msg_data_sz(hdr);
 		hlen = msg_hdr_sz(hdr);
 		err = msg_errcode(hdr);
+		grp_evt = msg_is_grp_evt(hdr);
 		if (likely(dlen || err))
 			break;
 		tsk_advance_rx_queue(sk);
@@ -1469,11 +1473,20 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m,
 	if (unlikely(rc))
 		goto exit;
 
+	/* Mark message as group event if applicable */
+	if (unlikely(grp_evt)) {
+		if (msg_grp_evt(hdr) == TIPC_WITHDRAWN)
+			m->msg_flags |= MSG_EOR;
+		m->msg_flags |= MSG_OOB;
+		copy = 0;
+	}
+
 	/* Caption of data or error code/rejected data was successful */
 	if (unlikely(flags & MSG_PEEK))
 		goto exit;
 
 	tsk_advance_rx_queue(sk);
+
 	if (likely(!connected))
 		goto exit;
 
@@ -1648,10 +1661,10 @@ static void tipc_sk_proto_rcv(struct sock *sk,
 		sk->sk_write_space(sk);
 		break;
 	case GROUP_PROTOCOL:
-		tipc_group_proto_rcv(grp, hdr, xmitq);
+		tipc_group_proto_rcv(grp, hdr, inputq, xmitq);
 		break;
 	case TOP_SRV:
-		tipc_group_member_evt(tsk->group, skb, xmitq);
+		tipc_group_member_evt(tsk->group, skb, inputq, xmitq);
 		skb = NULL;
 		break;
 	default:
-- 
2.1.4

^ permalink raw reply related

* [net-next v2 05/18] tipc: add new function for sending multiple small messages
From: Jon Maloy @ 2017-10-13  9:04 UTC (permalink / raw)
  To: davem, netdev; +Cc: parthasarathy.bhuvaragan, ying.xue, tipc-discussion
In-Reply-To: <1507885474-11213-1-git-send-email-jon.maloy@ericsson.com>

We see an increasing need to send multiple single-buffer messages
of TIPC_SYSTEM_IMPORTANCE to different individual destination nodes.
Instead of looping over the send queue and sending each buffer
individually, as we do now, we add a new help function
tipc_node_distr_xmit() to do this.

Signed-off-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
---
 net/tipc/node.c   | 16 ++++++++++++++++
 net/tipc/node.h   |  1 +
 net/tipc/socket.c | 14 ++------------
 3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/net/tipc/node.c b/net/tipc/node.c
index 6cc1ae6..89f8ac73 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1254,6 +1254,22 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
 	return 0;
 }
 
+/* tipc_node_distr_xmit(): send single buffer msgs to individual destinations
+ * Note: this is only for SYSTEM_IMPORTANCE messages, which cannot be rejected
+ */
+int tipc_node_distr_xmit(struct net *net, struct sk_buff_head *xmitq)
+{
+	struct sk_buff *skb;
+	u32 selector, dnode;
+
+	while ((skb = __skb_dequeue(xmitq))) {
+		selector = msg_origport(buf_msg(skb));
+		dnode = msg_destnode(buf_msg(skb));
+		tipc_node_xmit_skb(net, skb, dnode, selector);
+	}
+	return 0;
+}
+
 void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
 {
 	struct sk_buff *txskb;
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 8db59fe..df2f219 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -68,6 +68,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
 			   char *linkname, size_t len);
 int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
 		   int selector);
+int tipc_node_distr_xmit(struct net *net, struct sk_buff_head *list);
 int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,
 		       u32 selector);
 void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index bc226f5..c7c6749 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1740,14 +1740,11 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb,
  * @skb: message
  *
  * Caller must hold socket lock
- *
- * Returns 0
  */
 static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	unsigned int before = sk_rmem_alloc_get(sk);
 	struct sk_buff_head xmitq;
-	u32 dnode, selector;
 	unsigned int added;
 
 	__skb_queue_head_init(&xmitq);
@@ -1757,11 +1754,7 @@ static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 	atomic_add(added, &tipc_sk(sk)->dupl_rcvcnt);
 
 	/* Send pending response/rejected messages, if any */
-	while ((skb = __skb_dequeue(&xmitq))) {
-		selector = msg_origport(buf_msg(skb));
-		dnode = msg_destnode(buf_msg(skb));
-		tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector);
-	}
+	tipc_node_distr_xmit(sock_net(sk), &xmitq);
 	return 0;
 }
 
@@ -1840,10 +1833,7 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq)
 				spin_unlock_bh(&sk->sk_lock.slock);
 			}
 			/* Send pending response/rejected messages, if any */
-			while ((skb = __skb_dequeue(&xmitq))) {
-				dnode = msg_destnode(buf_msg(skb));
-				tipc_node_xmit_skb(net, skb, dnode, dport);
-			}
+			tipc_node_distr_xmit(sock_net(sk), &xmitq);
 			sock_put(sk);
 			continue;
 		}
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox