* Re: [PATCH net-next v5 1/2] net: add support for Cavium PTP coprocessor
From: Richard Cochran @ 2017-12-11 22:59 UTC (permalink / raw)
To: Aleksey Makarov
Cc: netdev, linux-arm-kernel, linux-kernel, Goutham, Sunil,
Radoslaw Biernacki, Robert Richter, David Daney,
Philippe Ombredanne
In-Reply-To: <20171211141435.2915-2-aleksey.makarov@cavium.com>
Sorry I didn't finish reviewing before...
On Mon, Dec 11, 2017 at 05:14:30PM +0300, Aleksey Makarov wrote:
> +/**
> + * cavium_ptp_adjfreq() - Adjust ptp frequency
> + * @ptp: PTP clock info
> + * @ppb: how much to adjust by, in parts-per-billion
> + */
> +static int cavium_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
adjfreq() is deprecated. See ptp_clock_kernel.h. Please re-work this
to implement the adjfine() method instead.
> +/**
> + * cavium_ptp_enable() - Check if PTP is enabled
Nit - comment is not correct. This method is for the auxiliary PHC
functions.
> + * @ptp: PTP clock info
> + * @rq: request
> + * @on: is it on
> + */
> +static int cavium_ptp_enable(struct ptp_clock_info *ptp_info,
> + struct ptp_clock_request *rq, int on)
> +{
> + return -EOPNOTSUPP;
> +}
...
> +static int cavium_ptp_probe(struct pci_dev *pdev,
> + const struct pci_device_id *ent)
> +{
> + struct device *dev = &pdev->dev;
> + struct cavium_ptp *clock;
> + struct cyclecounter *cc;
> + u64 clock_cfg;
> + u64 clock_comp;
> + int err;
> +
> + clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
> + if (!clock)
> + return -ENOMEM;
> +
> + clock->pdev = pdev;
> +
> + err = pcim_enable_device(pdev);
> + if (err)
> + return err;
> +
> + err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
> + if (err)
> + return err;
> +
> + clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
> +
> + spin_lock_init(&clock->spin_lock);
> +
> + cc = &clock->cycle_counter;
> + cc->read = cavium_ptp_cc_read;
> + cc->mask = CYCLECOUNTER_MASK(64);
> + cc->mult = 1;
> + cc->shift = 0;
> +
> + timecounter_init(&clock->time_counter, &clock->cycle_counter,
> + ktime_to_ns(ktime_get_real()));
> +
> + clock->clock_rate = ptp_cavium_clock_get();
> +
> + clock->ptp_info = (struct ptp_clock_info) {
> + .owner = THIS_MODULE,
> + .name = "ThunderX PTP",
> + .max_adj = 1000000000ull,
> + .n_ext_ts = 0,
> + .n_pins = 0,
> + .pps = 0,
> + .adjfreq = cavium_ptp_adjfreq,
> + .adjtime = cavium_ptp_adjtime,
> + .gettime64 = cavium_ptp_gettime,
> + .settime64 = cavium_ptp_settime,
> + .enable = cavium_ptp_enable,
> + };
> +
> + clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
> + clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
> + writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
> +
> + clock_comp = ((u64)1000000000ull << 32) / clock->clock_rate;
> + writeq(clock_comp, clock->reg_base + PTP_CLOCK_COMP);
> +
> + clock->ptp_clock = ptp_clock_register(&clock->ptp_info, dev);
> + if (IS_ERR(clock->ptp_clock)) {
You need to handle the case when ptp_clock_register() returns NULL.
from ptp_clock_kernel.h:
/**
* ptp_clock_register() - register a PTP hardware clock driver
*
* @info: Structure describing the new clock.
* @parent: Pointer to the parent device of the new clock.
*
* Returns a valid pointer on success or PTR_ERR on failure. If PHC
* support is missing at the configuration level, this function
* returns NULL, and drivers are expected to gracefully handle that
* case separately.
*/
> + clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
> + clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
> + writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
> + return PTR_ERR(clock->ptp_clock);
> + }
> +
> + pci_set_drvdata(pdev, clock);
> + return 0;
> +}
Thanks,
Richard
^ permalink raw reply
* Re: [PATCH 1/3] PCI: introduce a device-managed version of pci_set_mwi
From: Bjorn Helgaas @ 2017-12-11 23:00 UTC (permalink / raw)
To: Heiner Kallweit
Cc: Realtek linux nic maintainers, Bjorn Helgaas,
netdev@vger.kernel.org, linux-pci@vger.kernel.org
In-Reply-To: <3e560e2b-7f11-74e2-6db5-60c8479dc59b@gmail.com>
On Sun, Dec 10, 2017 at 12:43:48AM +0100, Heiner Kallweit wrote:
> Introduce a device-managed version of pci_set_mwi. First user is the
> Realtek r8169 driver.
>
> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
With the subject and changelog as follows and the code reordering below,
PCI: Add pcim_set_mwi(), a device-managed pci_set_mwi()
Add pcim_set_mwi(), a device-managed version of pci_set_mwi(). First user
is the Realtek r8169 driver.
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
With these changes, feel free to merge with the series via the netdev
tree.
> ---
> drivers/pci/pci.c | 29 +++++++++++++++++++++++++++++
> include/linux/pci.h | 1 +
> 2 files changed, 30 insertions(+)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 4a7c6864f..fc57c378d 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1458,6 +1458,7 @@ struct pci_devres {
> unsigned int pinned:1;
> unsigned int orig_intx:1;
> unsigned int restore_intx:1;
> + unsigned int mwi:1;
> u32 region_mask;
> };
>
> @@ -1476,6 +1477,9 @@ static void pcim_release(struct device *gendev, void *res)
> if (this->region_mask & (1 << i))
> pci_release_region(dev, i);
>
> + if (this->mwi)
> + pci_clear_mwi(dev);
> +
> if (this->restore_intx)
> pci_intx(dev, this->orig_intx);
>
> @@ -3760,6 +3764,31 @@ int pci_set_mwi(struct pci_dev *dev)
> }
> EXPORT_SYMBOL(pci_set_mwi);
>
> +/**
> + * pcim_set_mwi - Managed pci_set_mwi()
> + * @dev: the PCI device for which MWI is enabled
> + *
> + * Managed pci_set_mwi().
> + *
> + * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
> + */
> +int pcim_set_mwi(struct pci_dev *dev)
> +{
> + struct pci_devres *dr;
> + int ret;
> +
> + ret = pci_set_mwi(dev);
> + if (ret)
> + return ret;
> +
> + dr = find_pci_dr(dev);
> + if (dr)
> + dr->mwi = 1;
> +
> + return 0;
I would rather look up the pci_devres first, e.g.,
dr = find_pci_dr(dev);
if (!dr)
return -ENOMEM;
dr->mwi = 1;
return pci_set_mwi(dev);
That way we won't enable MWI and be unable to disable it at release-time.
> +}
> +EXPORT_SYMBOL(pcim_set_mwi);
> +
> /**
> * pci_try_set_mwi - enables memory-write-invalidate PCI transaction
> * @dev: the PCI device for which MWI is enabled
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 978aad784..0a7ac863a 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1064,6 +1064,7 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
> int pci_set_cacheline_size(struct pci_dev *dev);
> #define HAVE_PCI_SET_MWI
> int __must_check pci_set_mwi(struct pci_dev *dev);
> +int __must_check pcim_set_mwi(struct pci_dev *dev);
> int pci_try_set_mwi(struct pci_dev *dev);
> void pci_clear_mwi(struct pci_dev *dev);
> void pci_intx(struct pci_dev *dev, int enable);
> --
> 2.15.1
>
>
^ permalink raw reply
* [PATCH v3] net: ethernet: arc: fix error handling in emac_rockchip_probe
From: Branislav Radocaj @ 2017-12-11 23:13 UTC (permalink / raw)
To: heiko, netdev
Cc: linux-arm-kernel, linux-rockchip, linux-kernel, Branislav Radocaj
If clk_set_rate() fails, we should disable clk before return.
Found by Linux Driver Verification project (linuxtesting.org).
Changes since v2 [1]:
* Merged with latest code changes
Changes since v1:
Update made thanks to David's review, much appreciated David.
* Improved inconsistent failure handling of clock rate setting
* For completeness of usecase, added arc_emac_probe error handling
Signed-off-by: Branislav Radocaj <branislav@radocaj.org>
---
[1] https://marc.info/?l=linux-netdev&m=151301239802445&w=2
---
drivers/net/ethernet/arc/emac_rockchip.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
index c6163874e4e7..16f9bee992fe 100644
--- a/drivers/net/ethernet/arc/emac_rockchip.c
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -199,9 +199,11 @@ static int emac_rockchip_probe(struct platform_device *pdev)
/* RMII interface needs always a rate of 50MHz */
err = clk_set_rate(priv->refclk, 50000000);
- if (err)
+ if (err) {
dev_err(dev,
"failed to change reference clock rate (%d)\n", err);
+ goto out_regulator_disable;
+ }
if (priv->soc_data->need_div_macclk) {
priv->macclk = devm_clk_get(dev, "macclk");
@@ -230,12 +232,14 @@ static int emac_rockchip_probe(struct platform_device *pdev)
err = arc_emac_probe(ndev, interface);
if (err) {
dev_err(dev, "failed to probe arc emac (%d)\n", err);
- goto out_regulator_disable;
+ goto out_clk_disable_macclk;
}
return 0;
+
out_clk_disable_macclk:
- clk_disable_unprepare(priv->macclk);
+ if (priv->soc_data->need_div_macclk)
+ clk_disable_unprepare(priv->macclk);
out_regulator_disable:
if (priv->regulator)
regulator_disable(priv->regulator);
--
2.11.0
^ permalink raw reply related
* [PATCH] Fix handling of verdicts after NF_QUEUE
From: Debabrata Banerjee @ 2017-12-11 23:30 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: David S . Miller, netfilter-devel, coreteam, netdev, stable,
dbanerje
A verdict of NF_STOLEN after NF_QUEUE will cause an incorrect return value
and a potential kernel panic via double free of skb's
This was broken by commit 7034b566a4e7 ("netfilter: fix nf_queue handling")
and subsequently fixed in v4.10 by commit c63cbc460419 ("netfilter:
use switch() to handle verdict cases from nf_hook_slow()"). However that
commit cannot be cleanly cherry-picked to v4.9
Signed-off-by: Debabrata Banerjee <dbanerje@akamai.com>
---
This fix is only needed for v4.9 stable since v4.10+ does not have the
issue
---
net/netfilter/core.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 004af030ef1a..d869ea50623e 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -364,6 +364,11 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
ret = nf_queue(skb, state, &entry, verdict);
if (ret == 1 && entry)
goto next_hook;
+ } else {
+ /* Implicit handling for NF_STOLEN, as well as any other
+ * non conventional verdicts.
+ */
+ ret = 0;
}
return ret;
}
--
2.15.1
^ permalink raw reply related
* Re: [PATCH net-next v5 2/2] net: thunderx: add timestamping support
From: Richard Cochran @ 2017-12-11 23:32 UTC (permalink / raw)
To: Aleksey Makarov
Cc: netdev, linux-arm-kernel, linux-kernel, Goutham, Sunil,
Radoslaw Biernacki, Robert Richter, David Daney,
Philippe Ombredanne, Sunil Goutham
In-Reply-To: <20171211141435.2915-3-aleksey.makarov@cavium.com>
On Mon, Dec 11, 2017 at 05:14:31PM +0300, Aleksey Makarov wrote:
> diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
> index 4a02e618e318..204b234beb9d 100644
> --- a/drivers/net/ethernet/cavium/thunder/nic.h
> +++ b/drivers/net/ethernet/cavium/thunder/nic.h
> @@ -263,6 +263,8 @@ struct nicvf_drv_stats {
> struct u64_stats_sync syncp;
> };
>
> +struct cavium_ptp;
> +
> struct nicvf {
> struct nicvf *pnicvf;
> struct net_device *netdev;
> @@ -312,6 +314,12 @@ struct nicvf {
> struct tasklet_struct qs_err_task;
> struct work_struct reset_task;
>
> + /* PTP timestamp */
> + struct cavium_ptp *ptp_clock;
> + bool hw_rx_tstamp;
> + struct sk_buff *ptp_skb;
> + atomic_t tx_ptp_skbs;
It is disturbing that the above two fields are set in different
places. Shouldn't they be unified into one logical lock?
Here you clear them together:
> +static void nicvf_snd_ptp_handler(struct net_device *netdev,
> + struct cqe_send_t *cqe_tx)
> +{
> + struct nicvf *nic = netdev_priv(netdev);
> + struct skb_shared_hwtstamps ts;
> + u64 ns;
> +
> + nic = nic->pnicvf;
> +
> + /* Sync for 'ptp_skb' */
> + smp_rmb();
> +
> + /* New timestamp request can be queued now */
> + atomic_set(&nic->tx_ptp_skbs, 0);
> +
> + /* Check for timestamp requested skb */
> + if (!nic->ptp_skb)
> + return;
> +
> + /* Check if timestamping is timedout, which is set to 10us */
> + if (cqe_tx->send_status == CQ_TX_ERROP_TSTMP_TIMEOUT ||
> + cqe_tx->send_status == CQ_TX_ERROP_TSTMP_CONFLICT)
> + goto no_tstamp;
> +
> + /* Get the timestamp */
> + memset(&ts, 0, sizeof(ts));
> + ns = cavium_ptp_tstamp2time(nic->ptp_clock, cqe_tx->ptp_timestamp);
> + ts.hwtstamp = ns_to_ktime(ns);
> + skb_tstamp_tx(nic->ptp_skb, &ts);
> +
> +no_tstamp:
> + /* Free the original skb */
> + dev_kfree_skb_any(nic->ptp_skb);
> + nic->ptp_skb = NULL;
> + /* Sync 'ptp_skb' */
> + smp_wmb();
> +}
> +
but here you set the one:
> @@ -657,7 +697,12 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev,
> prefetch(skb);
> (*tx_pkts)++;
> *tx_bytes += skb->len;
> - napi_consume_skb(skb, budget);
> + /* If timestamp is requested for this skb, don't free it */
> + if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS &&
> + !nic->pnicvf->ptp_skb)
> + nic->pnicvf->ptp_skb = skb;
> + else
> + napi_consume_skb(skb, budget);
> sq->skbuff[cqe_tx->sqe_ptr] = (u64)NULL;
> } else {
> /* In case of SW TSO on 88xx, only last segment will have
here you clear one:
> @@ -1319,12 +1382,28 @@ int nicvf_stop(struct net_device *netdev)
>
> nicvf_free_cq_poll(nic);
>
> + /* Free any pending SKB saved to receive timestamp */
> + if (nic->ptp_skb) {
> + dev_kfree_skb_any(nic->ptp_skb);
> + nic->ptp_skb = NULL;
> + }
> +
> /* Clear multiqset info */
> nic->pnicvf = nic;
>
> return 0;
> }
here you clear both:
> @@ -1394,6 +1473,12 @@ int nicvf_open(struct net_device *netdev)
> if (nic->sqs_mode)
> nicvf_get_primary_vf_struct(nic);
>
> + /* Configure PTP timestamp */
> + if (nic->ptp_clock)
> + nicvf_config_hw_rx_tstamp(nic, nic->hw_rx_tstamp);
> + atomic_set(&nic->tx_ptp_skbs, 0);
> + nic->ptp_skb = NULL;
> +
> /* Configure receive side scaling and MTU */
> if (!nic->sqs_mode) {
> nicvf_rss_init(nic);
here you set the other:
> @@ -1385,6 +1388,29 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
> hdr->inner_l3_offset = skb_network_offset(skb) - 2;
> this_cpu_inc(nic->pnicvf->drv_stats->tx_tso);
> }
> +
> + /* Check if timestamp is requested */
> + if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
> + skb_tx_timestamp(skb);
> + return;
> + }
> +
> + /* Tx timestamping not supported along with TSO, so ignore request */
> + if (skb_shinfo(skb)->gso_size)
> + return;
> +
> + /* HW supports only a single outstanding packet to timestamp */
> + if (!atomic_add_unless(&nic->pnicvf->tx_ptp_skbs, 1, 1))
> + return;
> +
> + /* Mark the SKB for later reference */
> + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
> +
> + /* Finally enable timestamp generation
> + * Since 'post_cqe' is also set, two CQEs will be posted
> + * for this packet i.e CQE_TYPE_SEND and CQE_TYPE_SEND_PTP.
> + */
> + hdr->tstmp = 1;
> }
and so it is completely non-obvious whether this is race free or not.
Thanks,
Richard
^ permalink raw reply
* [Patch net-next] net_sched: switch to exit_batch for action pernet ops
From: Cong Wang @ 2017-12-11 23:35 UTC (permalink / raw)
To: netdev; +Cc: Cong Wang, Jamal Hadi Salim, Jiri Pirko
Since we now hold RTNL lock in tc_action_net_exit(), it is good to
batch them to speedup tc action dismantle.
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
---
include/net/act_api.h | 13 ++++++++++---
net/sched/act_bpf.c | 8 +++-----
net/sched/act_connmark.c | 8 +++-----
net/sched/act_csum.c | 8 +++-----
net/sched/act_gact.c | 8 +++-----
net/sched/act_ife.c | 8 +++-----
net/sched/act_ipt.c | 16 ++++++----------
net/sched/act_mirred.c | 8 +++-----
net/sched/act_nat.c | 8 +++-----
net/sched/act_pedit.c | 8 +++-----
net/sched/act_police.c | 8 +++-----
net/sched/act_sample.c | 8 +++-----
net/sched/act_simple.c | 8 +++-----
net/sched/act_skbedit.c | 8 +++-----
net/sched/act_skbmod.c | 8 +++-----
net/sched/act_tunnel_key.c | 8 +++-----
net/sched/act_vlan.c | 8 +++-----
17 files changed, 61 insertions(+), 88 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 02bf409140d0..6ed9692f20bd 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -120,12 +120,19 @@ int tc_action_net_init(struct tc_action_net *tn,
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
struct tcf_idrinfo *idrinfo);
-static inline void tc_action_net_exit(struct tc_action_net *tn)
+static inline void tc_action_net_exit(struct list_head *net_list,
+ unsigned int id)
{
+ struct net *net;
+
rtnl_lock();
- tcf_idrinfo_destroy(tn->ops, tn->idrinfo);
+ list_for_each_entry(net, net_list, exit_list) {
+ struct tc_action_net *tn = net_generic(net, id);
+
+ tcf_idrinfo_destroy(tn->ops, tn->idrinfo);
+ kfree(tn->idrinfo);
+ }
rtnl_unlock();
- kfree(tn->idrinfo);
}
int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index e6c477fa9ca5..b3f2c15affa7 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -401,16 +401,14 @@ static __net_init int bpf_init_net(struct net *net)
return tc_action_net_init(tn, &act_bpf_ops);
}
-static void __net_exit bpf_exit_net(struct net *net)
+static void __net_exit bpf_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, bpf_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, bpf_net_id);
}
static struct pernet_operations bpf_net_ops = {
.init = bpf_init_net,
- .exit = bpf_exit_net,
+ .exit_batch = bpf_exit_net,
.id = &bpf_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 10b7a8855a6c..2b15ba84e0c8 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -209,16 +209,14 @@ static __net_init int connmark_init_net(struct net *net)
return tc_action_net_init(tn, &act_connmark_ops);
}
-static void __net_exit connmark_exit_net(struct net *net)
+static void __net_exit connmark_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, connmark_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, connmark_net_id);
}
static struct pernet_operations connmark_net_ops = {
.init = connmark_init_net,
- .exit = connmark_exit_net,
+ .exit_batch = connmark_exit_net,
.id = &connmark_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index d836f998117b..af4b8ec60d9a 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -635,16 +635,14 @@ static __net_init int csum_init_net(struct net *net)
return tc_action_net_init(tn, &act_csum_ops);
}
-static void __net_exit csum_exit_net(struct net *net)
+static void __net_exit csum_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, csum_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, csum_net_id);
}
static struct pernet_operations csum_net_ops = {
.init = csum_init_net,
- .exit = csum_exit_net,
+ .exit_batch = csum_exit_net,
.id = &csum_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index e29a48ef7fc3..9d632e92cad0 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -235,16 +235,14 @@ static __net_init int gact_init_net(struct net *net)
return tc_action_net_init(tn, &act_gact_ops);
}
-static void __net_exit gact_exit_net(struct net *net)
+static void __net_exit gact_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, gact_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, gact_net_id);
}
static struct pernet_operations gact_net_ops = {
.init = gact_init_net,
- .exit = gact_exit_net,
+ .exit_batch = gact_exit_net,
.id = &gact_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index dee9cf22686c..5954e992685a 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -858,16 +858,14 @@ static __net_init int ife_init_net(struct net *net)
return tc_action_net_init(tn, &act_ife_ops);
}
-static void __net_exit ife_exit_net(struct net *net)
+static void __net_exit ife_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, ife_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, ife_net_id);
}
static struct pernet_operations ife_net_ops = {
.init = ife_init_net,
- .exit = ife_exit_net,
+ .exit_batch = ife_exit_net,
.id = &ife_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 2479b255dc1d..06e380ae0928 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -337,16 +337,14 @@ static __net_init int ipt_init_net(struct net *net)
return tc_action_net_init(tn, &act_ipt_ops);
}
-static void __net_exit ipt_exit_net(struct net *net)
+static void __net_exit ipt_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, ipt_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, ipt_net_id);
}
static struct pernet_operations ipt_net_ops = {
.init = ipt_init_net,
- .exit = ipt_exit_net,
+ .exit_batch = ipt_exit_net,
.id = &ipt_net_id,
.size = sizeof(struct tc_action_net),
};
@@ -387,16 +385,14 @@ static __net_init int xt_init_net(struct net *net)
return tc_action_net_init(tn, &act_xt_ops);
}
-static void __net_exit xt_exit_net(struct net *net)
+static void __net_exit xt_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, xt_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, xt_net_id);
}
static struct pernet_operations xt_net_ops = {
.init = xt_init_net,
- .exit = xt_exit_net,
+ .exit_batch = xt_exit_net,
.id = &xt_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index cee2d413bf57..37e5e4decbd6 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -334,16 +334,14 @@ static __net_init int mirred_init_net(struct net *net)
return tc_action_net_init(tn, &act_mirred_ops);
}
-static void __net_exit mirred_exit_net(struct net *net)
+static void __net_exit mirred_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, mirred_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, mirred_net_id);
}
static struct pernet_operations mirred_net_ops = {
.init = mirred_init_net,
- .exit = mirred_exit_net,
+ .exit_batch = mirred_exit_net,
.id = &mirred_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index c365d01b99c8..98c6a4b2f523 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -310,16 +310,14 @@ static __net_init int nat_init_net(struct net *net)
return tc_action_net_init(tn, &act_nat_ops);
}
-static void __net_exit nat_exit_net(struct net *net)
+static void __net_exit nat_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, nat_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, nat_net_id);
}
static struct pernet_operations nat_net_ops = {
.init = nat_init_net,
- .exit = nat_exit_net,
+ .exit_batch = nat_exit_net,
.id = &nat_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index dba996bcd6dc..349beaffb29e 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -453,16 +453,14 @@ static __net_init int pedit_init_net(struct net *net)
return tc_action_net_init(tn, &act_pedit_ops);
}
-static void __net_exit pedit_exit_net(struct net *net)
+static void __net_exit pedit_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, pedit_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, pedit_net_id);
}
static struct pernet_operations pedit_net_ops = {
.init = pedit_init_net,
- .exit = pedit_exit_net,
+ .exit_batch = pedit_exit_net,
.id = &pedit_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 3bb2ebf9e9ae..bf483db993a1 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -334,16 +334,14 @@ static __net_init int police_init_net(struct net *net)
return tc_action_net_init(tn, &act_police_ops);
}
-static void __net_exit police_exit_net(struct net *net)
+static void __net_exit police_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, police_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, police_net_id);
}
static struct pernet_operations police_net_ops = {
.init = police_init_net,
- .exit = police_exit_net,
+ .exit_batch = police_exit_net,
.id = &police_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index 859a93903339..1ba0df238756 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -236,16 +236,14 @@ static __net_init int sample_init_net(struct net *net)
return tc_action_net_init(tn, &act_sample_ops);
}
-static void __net_exit sample_exit_net(struct net *net)
+static void __net_exit sample_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, sample_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, sample_net_id);
}
static struct pernet_operations sample_net_ops = {
.init = sample_init_net,
- .exit = sample_exit_net,
+ .exit_batch = sample_exit_net,
.id = &sample_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index eda57b47a6b6..425eac11f6da 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -204,16 +204,14 @@ static __net_init int simp_init_net(struct net *net)
return tc_action_net_init(tn, &act_simp_ops);
}
-static void __net_exit simp_exit_net(struct net *net)
+static void __net_exit simp_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, simp_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, simp_net_id);
}
static struct pernet_operations simp_net_ops = {
.init = simp_init_net,
- .exit = simp_exit_net,
+ .exit_batch = simp_exit_net,
.id = &simp_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 59949d61f20d..5a3f691bb545 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -241,16 +241,14 @@ static __net_init int skbedit_init_net(struct net *net)
return tc_action_net_init(tn, &act_skbedit_ops);
}
-static void __net_exit skbedit_exit_net(struct net *net)
+static void __net_exit skbedit_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, skbedit_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, skbedit_net_id);
}
static struct pernet_operations skbedit_net_ops = {
.init = skbedit_init_net,
- .exit = skbedit_exit_net,
+ .exit_batch = skbedit_exit_net,
.id = &skbedit_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index f090bba1a79e..fa975262dbac 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -266,16 +266,14 @@ static __net_init int skbmod_init_net(struct net *net)
return tc_action_net_init(tn, &act_skbmod_ops);
}
-static void __net_exit skbmod_exit_net(struct net *net)
+static void __net_exit skbmod_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, skbmod_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, skbmod_net_id);
}
static struct pernet_operations skbmod_net_ops = {
.init = skbmod_init_net,
- .exit = skbmod_exit_net,
+ .exit_batch = skbmod_exit_net,
.id = &skbmod_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 57b63bdec3ae..0e23aac09ad6 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -325,16 +325,14 @@ static __net_init int tunnel_key_init_net(struct net *net)
return tc_action_net_init(tn, &act_tunnel_key_ops);
}
-static void __net_exit tunnel_key_exit_net(struct net *net)
+static void __net_exit tunnel_key_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, tunnel_key_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, tunnel_key_net_id);
}
static struct pernet_operations tunnel_key_net_ops = {
.init = tunnel_key_init_net,
- .exit = tunnel_key_exit_net,
+ .exit_batch = tunnel_key_exit_net,
.id = &tunnel_key_net_id,
.size = sizeof(struct tc_action_net),
};
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 41f0878ad26e..e1a1b3f3983a 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -301,16 +301,14 @@ static __net_init int vlan_init_net(struct net *net)
return tc_action_net_init(tn, &act_vlan_ops);
}
-static void __net_exit vlan_exit_net(struct net *net)
+static void __net_exit vlan_exit_net(struct list_head *net_list)
{
- struct tc_action_net *tn = net_generic(net, vlan_net_id);
-
- tc_action_net_exit(tn);
+ tc_action_net_exit(net_list, vlan_net_id);
}
static struct pernet_operations vlan_net_ops = {
.init = vlan_init_net,
- .exit = vlan_exit_net,
+ .exit_batch = vlan_exit_net,
.id = &vlan_net_id,
.size = sizeof(struct tc_action_net),
};
--
2.13.0
^ permalink raw reply related
* Re: [PATCH net-next v5 2/2] net: thunderx: add timestamping support
From: Richard Cochran @ 2017-12-11 23:36 UTC (permalink / raw)
To: Aleksey Makarov
Cc: netdev, linux-arm-kernel, linux-kernel, Goutham, Sunil,
Radoslaw Biernacki, Robert Richter, David Daney,
Philippe Ombredanne, Sunil Goutham
In-Reply-To: <20171211141435.2915-3-aleksey.makarov@cavium.com>
On Mon, Dec 11, 2017 at 05:14:31PM +0300, Aleksey Makarov wrote:
> @@ -880,6 +889,46 @@ static void nic_pause_frame(struct nicpf *nic, int vf, struct pfc *cfg)
> }
> }
>
> +/* Enable or disable HW timestamping by BGX for pkts received on a LMAC */
> +static void nic_config_timestamp(struct nicpf *nic, int vf, struct set_ptp *ptp)
> +{
> + struct pkind_cfg *pkind;
> + u8 lmac, bgx_idx;
> + u64 pkind_val, pkind_idx;
> +
> + if (vf >= nic->num_vf_en)
> + return;
> +
> + bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
> +
> + pkind_idx = lmac + bgx_idx * MAX_LMAC_PER_BGX;
> + pkind_val = nic_reg_read(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3));
> + pkind = (struct pkind_cfg *)&pkind_val;
> +
> + if (ptp->enable && !pkind->hdr_sl) {
> + /* Skiplen to exclude 8byte timestamp while parsing pkt
> + * If not configured, will result in L2 errors.
> + */
> + pkind->hdr_sl = 4;
> + /* Adjust max packet length allowed */
> + pkind->maxlen += (pkind->hdr_sl * 2);
> + bgx_config_timestamping(nic->node, bgx_idx, lmac, true);
> + nic_reg_write(nic,
> + NIC_PF_RX_ETYPE_0_7 | (1 << 3),
> + (ETYPE_ALG_ENDPARSE << 16) | ETH_P_1588);
don't need three lines for this function call.
> + } else if (!ptp->enable && pkind->hdr_sl) {
> + pkind->maxlen -= (pkind->hdr_sl * 2);
> + pkind->hdr_sl = 0;
> + bgx_config_timestamping(nic->node, bgx_idx, lmac, false);
> + nic_reg_write(nic,
> + NIC_PF_RX_ETYPE_0_7 | (1 << 3),
> + (1ULL << 16) | ETH_P_8021Q); /* reset value */
here neither. Also avoid comment on the LHS. If 1<<16 means "reset"
then just define a macro.
> + }
> +
> + nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val);
> +}
> +
Thanks,
Richard
^ permalink raw reply
* [PATCH net-next] tcp: allow TLP in ECN CWR
From: Yuchung Cheng @ 2017-12-11 23:42 UTC (permalink / raw)
To: davem; +Cc: netdev, ncardwell, edumazet, nanditad, sibanez, Yuchung Cheng
From: Neal Cardwell <ncardwell@google.com>
This patch enables tail loss probe in cwnd reduction (CWR) state
to detect potential losses. Prior to this patch, since the sender
uses PRR to determine the cwnd in CWR state, the combination of
CWR+PRR plus tcp_tso_should_defer() could cause unnecessary stalls
upon losses: PRR makes cwnd so gentle that tcp_tso_should_defer()
defers sending wait for more ACKs. The ACKs may not come due to
packet losses.
Disallowing TLP when there is unused cwnd had the primary effect
of disallowing TLP when there is TSO deferral, Nagle deferral,
or we hit the rwin limit. Because basically every application
write() or incoming ACK will cause us to run tcp_write_xmit()
to see if we can send more, and then if we sent something we call
tcp_schedule_loss_probe() to see if we should schedule a TLP. At
that point, there are a few common reasons why some cwnd budget
could still be unused:
(a) rwin limit
(b) nagle check
(c) TSO deferral
(d) TSQ
For (d), after the next packet tx completion the TSQ mechanism
will allow us to send more packets, so we don't really need a
TLP (in practice it shouldn't matter whether we schedule one
or not). But for (a), (b), (c) the sender won't send any more
packets until it gets another ACK. But if the whole flight was
lost, or all the ACKs were lost, then we won't get any more ACKs,
and ideally we should schedule and send a TLP to get more feedback.
In particular for a long time we have wanted some kind of timer for
TSO deferral, and at least this would give us some kind of timer
Reported-by: Steve Ibanez <sibanez@stanford.edu>
Signed-off-by: Neal Cardwell <ncardwell@google.com>
Signed-off-by: Yuchung Cheng <ycheng@google.com>
Reviewed-by: Nandita Dukkipati <nanditad@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp_output.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index a4d214c7b506..04be9f833927 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2414,15 +2414,12 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto)
early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans;
/* Schedule a loss probe in 2*RTT for SACK capable connections
- * in Open state, that are either limited by cwnd or application.
+ * not in loss recovery, that are either limited by cwnd or application.
*/
if ((early_retrans != 3 && early_retrans != 4) ||
!tp->packets_out || !tcp_is_sack(tp) ||
- icsk->icsk_ca_state != TCP_CA_Open)
- return false;
-
- if ((tp->snd_cwnd > tcp_packets_in_flight(tp)) &&
- !tcp_write_queue_empty(sk))
+ (icsk->icsk_ca_state != TCP_CA_Open &&
+ icsk->icsk_ca_state != TCP_CA_CWR))
return false;
/* Probe timeout is 2*rtt. Add minimum RTO to account
--
2.15.1.424.g9478a66081-goog
^ permalink raw reply related
* [PATCH] igb: Free IRQs when device is hotplugged
From: Lyude Paul @ 2017-12-11 23:45 UTC (permalink / raw)
To: intel-wired-lan; +Cc: Todd Fujinaka, stable, Jeff Kirsher, netdev, linux-kernel
Recently I got a Caldigit TS3 Thunderbolt 3 dock, and noticed that upon
hotplugging my kernel would immediately crash due to igb:
[ 680.825801] kernel BUG at drivers/pci/msi.c:352!
[ 680.828388] invalid opcode: 0000 [#1] SMP
[ 680.829194] Modules linked in: igb(O) thunderbolt i2c_algo_bit joydev vfat fat btusb btrtl btbcm btintel bluetooth ecdh_generic hp_wmi sparse_keymap rfkill wmi_bmof iTCO_wdt intel_rapl x86_pkg_temp_thermal coretemp crc32_pclmul snd_pcm rtsx_pci_ms mei_me snd_timer memstick snd pcspkr mei soundcore i2c_i801 tpm_tis psmouse shpchp wmi tpm_tis_core tpm video hp_wireless acpi_pad rtsx_pci_sdmmc mmc_core crc32c_intel serio_raw rtsx_pci mfd_core xhci_pci xhci_hcd i2c_hid i2c_core [last unloaded: igb]
[ 680.831085] CPU: 1 PID: 78 Comm: kworker/u16:1 Tainted: G O 4.15.0-rc3Lyude-Test+ #6
[ 680.831596] Hardware name: HP HP ZBook Studio G4/826B, BIOS P71 Ver. 01.03 06/09/2017
[ 680.832168] Workqueue: kacpi_hotplug acpi_hotplug_work_fn
[ 680.832687] RIP: 0010:free_msi_irqs+0x180/0x1b0
[ 680.833271] RSP: 0018:ffffc9000030fbf0 EFLAGS: 00010286
[ 680.833761] RAX: ffff8803405f9c00 RBX: ffff88033e3d2e40 RCX: 000000000000002c
[ 680.834278] RDX: 0000000000000000 RSI: 00000000000000ac RDI: ffff880340be2178
[ 680.834832] RBP: 0000000000000000 R08: ffff880340be1ff0 R09: ffff8803405f9c00
[ 680.835342] R10: 0000000000000000 R11: 0000000000000040 R12: ffff88033d63a298
[ 680.835822] R13: ffff88033d63a000 R14: 0000000000000060 R15: ffff880341959000
[ 680.836332] FS: 0000000000000000(0000) GS:ffff88034f440000(0000) knlGS:0000000000000000
[ 680.836817] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 680.837360] CR2: 000055e64044afdf CR3: 0000000001c09002 CR4: 00000000003606e0
[ 680.837954] Call Trace:
[ 680.838853] pci_disable_msix+0xce/0xf0
[ 680.839616] igb_reset_interrupt_capability+0x5d/0x60 [igb]
[ 680.840278] igb_remove+0x9d/0x110 [igb]
[ 680.840764] pci_device_remove+0x36/0xb0
[ 680.841279] device_release_driver_internal+0x157/0x220
[ 680.841739] pci_stop_bus_device+0x7d/0xa0
[ 680.842255] pci_stop_bus_device+0x2b/0xa0
[ 680.842722] pci_stop_bus_device+0x3d/0xa0
[ 680.843189] pci_stop_and_remove_bus_device+0xe/0x20
[ 680.843627] trim_stale_devices+0xf3/0x140
[ 680.844086] trim_stale_devices+0x94/0x140
[ 680.844532] trim_stale_devices+0xa6/0x140
[ 680.845031] ? get_slot_status+0x90/0xc0
[ 680.845536] acpiphp_check_bridge.part.5+0xfe/0x140
[ 680.846021] acpiphp_hotplug_notify+0x175/0x200
[ 680.846581] ? free_bridge+0x100/0x100
[ 680.847113] acpi_device_hotplug+0x8a/0x490
[ 680.847535] acpi_hotplug_work_fn+0x1a/0x30
[ 680.848076] process_one_work+0x182/0x3a0
[ 680.848543] worker_thread+0x2e/0x380
[ 680.848963] ? process_one_work+0x3a0/0x3a0
[ 680.849373] kthread+0x111/0x130
[ 680.849776] ? kthread_create_worker_on_cpu+0x50/0x50
[ 680.850188] ret_from_fork+0x1f/0x30
[ 680.850601] Code: 43 14 85 c0 0f 84 d5 fe ff ff 31 ed eb 0f 83 c5 01 39 6b 14 0f 86 c5 fe ff ff 8b 7b 10 01 ef e8 b7 e4 d2 ff 48 83 78 70 00 74 e3 <0f> 0b 49 8d b5 a0 00 00 00 e8 62 6f d3 ff e9 c7 fe ff ff 48 8b
[ 680.851497] RIP: free_msi_irqs+0x180/0x1b0 RSP: ffffc9000030fbf0
As it turns out, normally the freeing of IRQs that would fix this is called
inside of the scope of __igb_close(). However, since the device is
already gone by the point we try to unregister the netdevice from the
driver due to a hotplug we end up seeing that the netif isn't present
and thus, forget to free any of the device IRQs.
So: after unregistering the netdev in igb_remove() check whether the PCI
device is stale and if so, free it's IRQs and tx/rx resources.
Signed-off-by: Lyude Paul <lyude@redhat.com>
Fixes: 9474933caf21 ("igb: close/suspend race in netif_device_detach")
Cc: Todd Fujinaka <todd.fujinaka@intel.com>
Cc: stable@vger.kernel.org
---
drivers/net/ethernet/intel/igb/igb_main.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index c208753ff5b7..e650348b4bd7 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3325,6 +3325,16 @@ static void igb_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
+ /* If the PCI device has already been physically removed (e.g. user
+ * unplugged a thunderbolt dock containing our hw) then the netif will
+ * already be down, so unregistering the netdev won't free the IRQs
+ */
+ if (!pci_device_is_present(pdev)) {
+ igb_free_irq(adapter);
+ igb_free_all_tx_resources(adapter);
+ igb_free_all_rx_resources(adapter);
+ }
+
igb_clear_interrupt_scheme(adapter);
pci_iounmap(pdev, adapter->io_addr);
--
2.14.3
^ permalink raw reply related
* Re: [PATCH iproute2 1/1] ss: remove duplicate assignment
From: Stephen Hemminger @ 2017-12-11 23:57 UTC (permalink / raw)
To: Roman Mashak; +Cc: jhs, netdev
In-Reply-To: <1513027471-19346-1-git-send-email-mrv@mojatatu.com>
On Mon, 11 Dec 2017 16:24:31 -0500
Roman Mashak <mrv@mojatatu.com> wrote:
> Signed-off-by: Roman Mashak <mrv@mojatatu.com>
Applied and added Fixes: 8250bc9ff4e5 ("ss: Unify inet sockets output")
^ permalink raw reply
* Re: [PATCH iproute2 net-next 0/4] Abstract columns, properly space and wrap fields
From: Stephen Hemminger @ 2017-12-12 0:07 UTC (permalink / raw)
To: Stefano Brivio; +Cc: netdev, Sabrina Dubroca, David Ahern
In-Reply-To: <cover.1512750298.git.sbrivio@redhat.com>
On Fri, 8 Dec 2017 18:07:19 +0100
Stefano Brivio <sbrivio@redhat.com> wrote:
> Currently, 'ss' simply subdivides the whole available screen width
> between available columns, starting from a set of hardcoded amount
> of spacing and growing column widths.
>
> This makes the output unreadable in several cases, as it doesn't take
> into account the actual content width.
>
> Fix this by introducing a simple abstraction for columns, buffering
> the output, measuring the width of the fields, grouping fields into
> lines as they fit, equally distributing any remaining whitespace, and
> finally rendering the result. Some examples are reported below [1].
>
> This implementation doesn't seem to cause any significant performance
> issues, as reported in 3/4.
>
> Patch 1/4 replaces all relevant printf() calls by the out() helper,
> which simply consists of the usual printf() implementation.
>
> Patch 2/4 implements column abstraction, with configurable column
> width and delimiters, and 3/4 splits buffering and rendering phases,
> employing a simple buffering mechanism with chunked allocation and
> introducing a rendering function.
>
> Up to this point, the output is still unchanged.
>
> Finally, 4/4 introduces field width calculation based on content
> length measured while buffering, in order to split fields onto
> multiple lines and equally space them within the single lines.
>
> Now that column behaviour is well-defined and more easily
> configurable, it should be easier to further improve the output by
> splitting logically separable information (e.g. TCP details) into
> additional columns. However, this patchset keeps the full "extended"
> information into a single column, for the moment being.
>
>
> [1]
>
> - 80 columns terminal, ss -Z -f netlink
> * before:
> Recv-Q Send-Q Local Address:Port Peer Address:Port
>
> 0 0 rtnl:evolution-calen/2075 * pr
> oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:abrt-applet/32700 * pr
> oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:firefox/21619 * pr
> oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:evolution-calen/32639 * p
> roc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> [...]
>
> * after:
> Recv-Q Send-Q Local Address:Port Peer Address:Port
> 0 0 rtnl:evolution-calen/2075 *
> proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:abrt-applet/32700 *
> proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:firefox/21619 *
> proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> 0 0 rtnl:evolution-calen/32639 *
> proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
> [...]
>
> - 80 colums terminal, ss -tunpl
> * before:
> Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
> udp UNCONN 0 0 *:37732 *:*
> udp UNCONN 0 0 *:5353 *:*
> udp UNCONN 0 0 192.168.122.1:53 *:*
> udp UNCONN 0 0 *%virbr0:67 *:*
> [...]
>
> * after:
> Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
> udp UNCONN 0 0 *:37732 *:*
> udp UNCONN 0 0 *:5353 *:*
> udp UNCONN 0 0 192.168.122.1:53 *:*
> udp UNCONN 0 0 *%virbr0:67 *:*
> [...]
>
> - 66 columns terminal, ss -tunpl
> * before:
> Netid State Recv-Q Send-Q Local Address:Port P
> eer Address:Port
> udp UNCONN 0 0 *:37732 *:*
>
> udp UNCONN 0 0 *:5353 *:*
>
> udp UNCONN 0 0 192.168.122.1:53
> *:*
> udp UNCONN 0 0 *%virbr0:67 *:*
> [...]
>
> * after:
> Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
> udp UNCONN 0 0 *:37732 *:*
> udp UNCONN 0 0 *:5353 *:*
> udp UNCONN 0 0 192.168.122.1:53 *:*
> udp UNCONN 0 0 *%virbr0:67 *:*
> [...]
>
>
> Stefano Brivio (4):
> ss: Replace printf() calls for "main" output by calls to helper
> ss: Introduce columns lightweight abstraction
> ss: Buffer raw fields first, then render them as a table
> ss: Implement automatic column width calculation
I was going to apply this but it does not apply cleanly to current iproute2 net-next
tree. Please rebase and resubmit.
^ permalink raw reply
* Re: [PATCH] Fix handling of verdicts after NF_QUEUE
From: Pablo Neira Ayuso @ 2017-12-12 0:23 UTC (permalink / raw)
To: Debabrata Banerjee
Cc: David S . Miller, netfilter-devel, coreteam, netdev, stable
In-Reply-To: <20171211233024.18303-1-dbanerje@akamai.com>
Hi,
Thanks for catching up this, see below.
On Mon, Dec 11, 2017 at 06:30:24PM -0500, Debabrata Banerjee wrote:
> A verdict of NF_STOLEN after NF_QUEUE will cause an incorrect return value
> and a potential kernel panic via double free of skb's
>
> This was broken by commit 7034b566a4e7 ("netfilter: fix nf_queue handling")
> and subsequently fixed in v4.10 by commit c63cbc460419 ("netfilter:
> use switch() to handle verdict cases from nf_hook_slow()"). However that
> commit cannot be cleanly cherry-picked to v4.9
>
> Signed-off-by: Debabrata Banerjee <dbanerje@akamai.com>
>
> ---
>
> This fix is only needed for v4.9 stable since v4.10+ does not have the
> issue
> ---
> net/netfilter/core.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/net/netfilter/core.c b/net/netfilter/core.c
> index 004af030ef1a..d869ea50623e 100644
> --- a/net/netfilter/core.c
> +++ b/net/netfilter/core.c
> @@ -364,6 +364,11 @@ int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
> ret = nf_queue(skb, state, &entry, verdict);
> if (ret == 1 && entry)
> goto next_hook;
> + } else {
> + /* Implicit handling for NF_STOLEN, as well as any other
> + * non conventional verdicts.
> + */
> + ret = 0;
Another possibility (more simple?) would be this:
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state)
{
struct nf_hook_entry *entry;
unsigned int verdict;
- int ret = 0;
+ int ret;
entry = rcu_dereference(state->hook_entries);
next_hook:
+ ret = 0;
Basically, make sure ret is set to zero when jumping to the next_hook
label.
Thanks!
^ permalink raw reply
* [PATCH net-next v3 0/6] net: qualcomm: rmnet: Configuration options
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
This series adds support for configuring features on rmnet devices.
The rmnet specific features to be configured here are aggregation and
control commands.
Patch 1 is a cleanup of return codes in the transmit path.
Patch 2 removes some redundant ingress and egress macros.
Patch 3 restricts the creation of rmnet dev to one dev per mux id for a
given real dev.
Patch 4 adds ethernet data path support.
Patches 5-6 add support for configuring features on new and existing
rmnet devices.
v1->v2:
The memory leak fixed as part of patch 1 is merged seperately as
a896d94abd2c ("net: qualcomm: rmnet: Fix leak on transmit failure").
Fix a use after free in patch 4 if a packet with headroom lesser than ethernet
header length is received.
v2->v3:
Fix formatting problem in patch 5 in the return statement.
Subash Abhinov Kasiviswanathan (6):
net: qualcomm: rmnet: Remove the rmnet_map_results enum
net: qualcomm: rmnet: Remove the some redundant macros
net: qualcomm: rmnet: Allow only one rmnet dev per muxid per real dev
net: qualcomm: rmnet: Process packets over ethernet
net: qualcomm: rmnet: Allow to configure flags for new devices
net: qualcomm: rmnet: Allow to configure flags for existing devices
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 64 ++++++++++++++++++----
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 -
.../net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 42 +++++++-------
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 9 ---
.../net/ethernet/qualcomm/rmnet/rmnet_private.h | 10 +---
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 3 +
6 files changed, 78 insertions(+), 51 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH net-next v3 1/6] net: qualcomm: rmnet: Remove the rmnet_map_results enum
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Only the success and consumed entries were actually in use.
Use standard error codes instead.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 15 +++------------
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h | 9 ---------
2 files changed, 3 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 08e4afc..1e1ea10 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -142,11 +142,11 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
skb->protocol = htons(ETH_P_MAP);
- return RMNET_MAP_SUCCESS;
+ return 0;
fail:
kfree_skb(skb);
- return RMNET_MAP_CONSUMED;
+ return -ENOMEM;
}
static void
@@ -213,17 +213,8 @@ void rmnet_egress_handler(struct sk_buff *skb)
}
if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
- switch (rmnet_map_egress_handler(skb, port, mux_id, orig_dev)) {
- case RMNET_MAP_CONSUMED:
+ if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
return;
-
- case RMNET_MAP_SUCCESS:
- break;
-
- default:
- kfree_skb(skb);
- return;
- }
}
rmnet_vnd_tx_fixup(skb, orig_dev);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index 3af3fe7..4df359d 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -30,15 +30,6 @@ struct rmnet_map_control_command {
};
} __aligned(1);
-enum rmnet_map_results {
- RMNET_MAP_SUCCESS,
- RMNET_MAP_CONSUMED,
- RMNET_MAP_GENERAL_FAILURE,
- RMNET_MAP_NOT_ENABLED,
- RMNET_MAP_FAILED_AGGREGATION,
- RMNET_MAP_FAILED_MUX
-};
-
enum rmnet_map_commands {
RMNET_MAP_COMMAND_NONE,
RMNET_MAP_COMMAND_FLOW_DISABLE,
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 2/6] net: qualcomm: rmnet: Remove the some redundant macros
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Multiplexing is always enabled when transmiting from a rmnet device,
so remove the redundant egress macros. De-multiplexing is always
enabled when receiving packets from a rmnet device, so remove those
ingress macros.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 10 ++--------
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 -
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 19 +++++++------------
drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h | 10 ++--------
4 files changed, 11 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index df21e90..46bb228 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -143,11 +143,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
struct netlink_ext_ack *extack)
{
- int ingress_format = RMNET_INGRESS_FORMAT_DEMUXING |
- RMNET_INGRESS_FORMAT_DEAGGREGATION |
- RMNET_INGRESS_FORMAT_MAP;
- int egress_format = RMNET_EGRESS_FORMAT_MUXING |
- RMNET_EGRESS_FORMAT_MAP;
+ int ingress_format = RMNET_INGRESS_FORMAT_DEAGGREGATION;
struct net_device *real_dev;
int mode = RMNET_EPMODE_VND;
struct rmnet_endpoint *ep;
@@ -181,9 +177,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
if (err)
goto err2;
- netdev_dbg(dev, "data format [ingress 0x%08X] [egress 0x%08X]\n",
- ingress_format, egress_format);
- port->egress_data_format = egress_format;
+ netdev_dbg(dev, "data format [ingress 0x%08X]\n", ingress_format);
port->ingress_data_format = ingress_format;
port->rmnet_mode = mode;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index c19259e..2ea9fe3 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -33,7 +33,6 @@ struct rmnet_endpoint {
struct rmnet_port {
struct net_device *dev;
u32 ingress_data_format;
- u32 egress_data_format;
u8 nr_rmnet_devs;
u8 rmnet_mode;
struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 1e1ea10..a46053c 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -133,12 +133,10 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
if (!map_header)
goto fail;
- if (port->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) {
- if (mux_id == 0xff)
- map_header->mux_id = 0;
- else
- map_header->mux_id = mux_id;
- }
+ if (mux_id == 0xff)
+ map_header->mux_id = 0;
+ else
+ map_header->mux_id = mux_id;
skb->protocol = htons(ETH_P_MAP);
@@ -178,8 +176,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
switch (port->rmnet_mode) {
case RMNET_EPMODE_VND:
- if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP)
- rmnet_map_ingress_handler(skb, port);
+ rmnet_map_ingress_handler(skb, port);
break;
case RMNET_EPMODE_BRIDGE:
rmnet_bridge_handler(skb, port->bridge_ep);
@@ -212,10 +209,8 @@ void rmnet_egress_handler(struct sk_buff *skb)
return;
}
- if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
- if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
- return;
- }
+ if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
+ return;
rmnet_vnd_tx_fixup(skb, orig_dev);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
index 49102f9..d214280 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
@@ -19,14 +19,8 @@
#define RMNET_TX_QUEUE_LEN 1000
/* Constants */
-#define RMNET_EGRESS_FORMAT_MAP BIT(1)
-#define RMNET_EGRESS_FORMAT_AGGREGATION BIT(2)
-#define RMNET_EGRESS_FORMAT_MUXING BIT(3)
-
-#define RMNET_INGRESS_FORMAT_MAP BIT(1)
-#define RMNET_INGRESS_FORMAT_DEAGGREGATION BIT(2)
-#define RMNET_INGRESS_FORMAT_DEMUXING BIT(3)
-#define RMNET_INGRESS_FORMAT_MAP_COMMANDS BIT(4)
+#define RMNET_INGRESS_FORMAT_DEAGGREGATION BIT(0)
+#define RMNET_INGRESS_FORMAT_MAP_COMMANDS BIT(1)
/* Replace skb->dev to a virtual rmnet device and pass up the stack */
#define RMNET_EPMODE_VND (1)
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 3/6] net: qualcomm: rmnet: Allow only one rmnet dev per muxid per real dev
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Upon de-multiplexing data from one real dev, the packets can be sent
to an unique rmnet device for a given mux id.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 9caa5e3..5bb29f4 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -185,6 +185,9 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
if (ep->egress_dev)
return -EINVAL;
+ if (rmnet_get_endpoint(port, id))
+ return -EBUSY;
+
rc = register_netdevice(rmnet_dev);
if (!rc) {
ep->egress_dev = rmnet_dev;
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 4/6] net: qualcomm: rmnet: Process packets over ethernet
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Add support to send and receive packets over ethernet.
An example of usage is testing the data path on UML. This can be
achieved by setting up two UML instances in multicast mode and
associating rmnet over the UML ethernet device.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index a46053c..0553932 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -15,6 +15,7 @@
#include <linux/netdevice.h>
#include <linux/netdev_features.h>
+#include <linux/if_arp.h>
#include "rmnet_private.h"
#include "rmnet_config.h"
#include "rmnet_vnd.h"
@@ -104,6 +105,15 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
{
struct sk_buff *skbn;
+ if (skb->dev->type == ARPHRD_ETHER) {
+ if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_KERNEL)) {
+ kfree_skb(skb);
+ return;
+ }
+
+ skb_push(skb, ETH_HLEN);
+ }
+
if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
while ((skbn = rmnet_map_deaggregate(skb)) != NULL)
__rmnet_map_ingress_handler(skbn, port);
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 5/6] net: qualcomm: rmnet: Allow to configure flags for new devices
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Add an option to configure the rmnet aggregation and command features
on device creation. This is achieved by using the vlan flags option.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 46bb228..7a4c26e 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -177,11 +177,20 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
if (err)
goto err2;
- netdev_dbg(dev, "data format [ingress 0x%08X]\n", ingress_format);
- port->ingress_data_format = ingress_format;
port->rmnet_mode = mode;
hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
+
+ if (data[IFLA_VLAN_FLAGS]) {
+ struct ifla_vlan_flags *flags;
+
+ flags = nla_data(data[IFLA_VLAN_FLAGS]);
+ ingress_format = flags->flags & flags->mask;
+ }
+
+ netdev_dbg(dev, "data format [ingress 0x%08X]\n", ingress_format);
+ port->ingress_data_format = ingress_format;
+
return 0;
err2:
@@ -313,7 +322,8 @@ static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
static size_t rmnet_get_size(const struct net_device *dev)
{
- return nla_total_size(2); /* IFLA_VLAN_ID */
+ return nla_total_size(2) /* IFLA_VLAN_ID */ +
+ nla_total_size(sizeof(struct ifla_vlan_flags)); /* IFLA_VLAN_FLAGS */
}
struct rtnl_link_ops rmnet_link_ops __read_mostly = {
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v3 6/6] net: qualcomm: rmnet: Allow to configure flags for existing devices
From: Subash Abhinov Kasiviswanathan @ 2017-12-12 0:30 UTC (permalink / raw)
To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1513038615-16407-1-git-send-email-subashab@codeaurora.org>
Add an option to configure the mux id, aggregation and commad feature
for existing rmnet devices. Implement the changelink netlink
operation for this.
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 7a4c26e..cedacdd 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -320,6 +320,45 @@ static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
}
+static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
+ struct nlattr *data[],
+ struct netlink_ext_ack *extack)
+{
+ struct rmnet_priv *priv = netdev_priv(dev);
+ struct net_device *real_dev;
+ struct rmnet_endpoint *ep;
+ struct rmnet_port *port;
+ u16 mux_id;
+
+ real_dev = __dev_get_by_index(dev_net(dev),
+ nla_get_u32(tb[IFLA_LINK]));
+
+ if (!real_dev || !dev || !rmnet_is_real_dev_registered(real_dev))
+ return -ENODEV;
+
+ port = rmnet_get_port_rtnl(real_dev);
+
+ if (data[IFLA_VLAN_ID]) {
+ mux_id = nla_get_u16(data[IFLA_VLAN_ID]);
+ ep = rmnet_get_endpoint(port, priv->mux_id);
+
+ hlist_del_init_rcu(&ep->hlnode);
+ hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
+
+ ep->mux_id = mux_id;
+ priv->mux_id = mux_id;
+ }
+
+ if (data[IFLA_VLAN_FLAGS]) {
+ struct ifla_vlan_flags *flags;
+
+ flags = nla_data(data[IFLA_VLAN_FLAGS]);
+ port->ingress_data_format = flags->flags & flags->mask;
+ }
+
+ return 0;
+}
+
static size_t rmnet_get_size(const struct net_device *dev)
{
return nla_total_size(2) /* IFLA_VLAN_ID */ +
@@ -335,6 +374,7 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = {
.newlink = rmnet_newlink,
.dellink = rmnet_dellink,
.get_size = rmnet_get_size,
+ .changelink = rmnet_changelink,
};
/* Needs either rcu_read_lock() or rtnl lock */
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] igb: Free IRQs when device is hotplugged
From: Stephen Hemminger @ 2017-12-12 0:34 UTC (permalink / raw)
To: Lyude Paul
Cc: intel-wired-lan, Todd Fujinaka, stable, Jeff Kirsher, netdev,
linux-kernel
In-Reply-To: <20171211234502.27445-1-lyude@redhat.com>
On Mon, 11 Dec 2017 18:45:02 -0500
Lyude Paul <lyude@redhat.com> wrote:
> Recently I got a Caldigit TS3 Thunderbolt 3 dock, and noticed that upon
> hotplugging my kernel would immediately crash due to igb:
>
> [ 680.825801] kernel BUG at drivers/pci/msi.c:352!
> [ 680.828388] invalid opcode: 0000 [#1] SMP
> [ 680.829194] Modules linked in: igb(O) thunderbolt i2c_algo_bit joydev vfat fat btusb btrtl btbcm btintel bluetooth ecdh_generic hp_wmi sparse_keymap rfkill wmi_bmof iTCO_wdt intel_rapl x86_pkg_temp_thermal coretemp crc32_pclmul snd_pcm rtsx_pci_ms mei_me snd_timer memstick snd pcspkr mei soundcore i2c_i801 tpm_tis psmouse shpchp wmi tpm_tis_core tpm video hp_wireless acpi_pad rtsx_pci_sdmmc mmc_core crc32c_intel serio_raw rtsx_pci mfd_core xhci_pci xhci_hcd i2c_hid i2c_core [last unloaded: igb]
> [ 680.831085] CPU: 1 PID: 78 Comm: kworker/u16:1 Tainted: G O 4.15.0-rc3Lyude-Test+ #6
> [ 680.831596] Hardware name: HP HP ZBook Studio G4/826B, BIOS P71 Ver. 01.03 06/09/2017
> [ 680.832168] Workqueue: kacpi_hotplug acpi_hotplug_work_fn
> [ 680.832687] RIP: 0010:free_msi_irqs+0x180/0x1b0
> [ 680.833271] RSP: 0018:ffffc9000030fbf0 EFLAGS: 00010286
> [ 680.833761] RAX: ffff8803405f9c00 RBX: ffff88033e3d2e40 RCX: 000000000000002c
> [ 680.834278] RDX: 0000000000000000 RSI: 00000000000000ac RDI: ffff880340be2178
> [ 680.834832] RBP: 0000000000000000 R08: ffff880340be1ff0 R09: ffff8803405f9c00
> [ 680.835342] R10: 0000000000000000 R11: 0000000000000040 R12: ffff88033d63a298
> [ 680.835822] R13: ffff88033d63a000 R14: 0000000000000060 R15: ffff880341959000
> [ 680.836332] FS: 0000000000000000(0000) GS:ffff88034f440000(0000) knlGS:0000000000000000
> [ 680.836817] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 680.837360] CR2: 000055e64044afdf CR3: 0000000001c09002 CR4: 00000000003606e0
> [ 680.837954] Call Trace:
> [ 680.838853] pci_disable_msix+0xce/0xf0
> [ 680.839616] igb_reset_interrupt_capability+0x5d/0x60 [igb]
> [ 680.840278] igb_remove+0x9d/0x110 [igb]
> [ 680.840764] pci_device_remove+0x36/0xb0
> [ 680.841279] device_release_driver_internal+0x157/0x220
> [ 680.841739] pci_stop_bus_device+0x7d/0xa0
> [ 680.842255] pci_stop_bus_device+0x2b/0xa0
> [ 680.842722] pci_stop_bus_device+0x3d/0xa0
> [ 680.843189] pci_stop_and_remove_bus_device+0xe/0x20
> [ 680.843627] trim_stale_devices+0xf3/0x140
> [ 680.844086] trim_stale_devices+0x94/0x140
> [ 680.844532] trim_stale_devices+0xa6/0x140
> [ 680.845031] ? get_slot_status+0x90/0xc0
> [ 680.845536] acpiphp_check_bridge.part.5+0xfe/0x140
> [ 680.846021] acpiphp_hotplug_notify+0x175/0x200
> [ 680.846581] ? free_bridge+0x100/0x100
> [ 680.847113] acpi_device_hotplug+0x8a/0x490
> [ 680.847535] acpi_hotplug_work_fn+0x1a/0x30
> [ 680.848076] process_one_work+0x182/0x3a0
> [ 680.848543] worker_thread+0x2e/0x380
> [ 680.848963] ? process_one_work+0x3a0/0x3a0
> [ 680.849373] kthread+0x111/0x130
> [ 680.849776] ? kthread_create_worker_on_cpu+0x50/0x50
> [ 680.850188] ret_from_fork+0x1f/0x30
> [ 680.850601] Code: 43 14 85 c0 0f 84 d5 fe ff ff 31 ed eb 0f 83 c5 01 39 6b 14 0f 86 c5 fe ff ff 8b 7b 10 01 ef e8 b7 e4 d2 ff 48 83 78 70 00 74 e3 <0f> 0b 49 8d b5 a0 00 00 00 e8 62 6f d3 ff e9 c7 fe ff ff 48 8b
> [ 680.851497] RIP: free_msi_irqs+0x180/0x1b0 RSP: ffffc9000030fbf0
>
> As it turns out, normally the freeing of IRQs that would fix this is called
> inside of the scope of __igb_close(). However, since the device is
> already gone by the point we try to unregister the netdevice from the
> driver due to a hotplug we end up seeing that the netif isn't present
> and thus, forget to free any of the device IRQs.
>
> So: after unregistering the netdev in igb_remove() check whether the PCI
> device is stale and if so, free it's IRQs and tx/rx resources.
>
> Signed-off-by: Lyude Paul <lyude@redhat.com>
> Fixes: 9474933caf21 ("igb: close/suspend race in netif_device_detach")
> Cc: Todd Fujinaka <todd.fujinaka@intel.com>
> Cc: stable@vger.kernel.org
> ---
> drivers/net/ethernet/intel/igb/igb_main.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
> index c208753ff5b7..e650348b4bd7 100644
> --- a/drivers/net/ethernet/intel/igb/igb_main.c
> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
> @@ -3325,6 +3325,16 @@ static void igb_remove(struct pci_dev *pdev)
>
> unregister_netdev(netdev);
>
> + /* If the PCI device has already been physically removed (e.g. user
> + * unplugged a thunderbolt dock containing our hw) then the netif will
> + * already be down, so unregistering the netdev won't free the IRQs
> + */
> + if (!pci_device_is_present(pdev)) {
> + igb_free_irq(adapter);
> + igb_free_all_tx_resources(adapter);
> + igb_free_all_rx_resources(adapter);
> + }
> +
> igb_clear_interrupt_scheme(adapter);
>
> pci_iounmap(pdev, adapter->io_addr);
This looks like you are making a special case out of something that should
be fixed in igb_close instead.
Most likely something is wrong with earlier commit.
commit 9474933caf21a4cb5147223dca1551f527aaac36
Author: Todd Fujinaka <todd.fujinaka@intel.com>
Date: Tue Nov 15 08:54:26 2016 -0800
igb: close/suspend race in netif_device_detach
Similar to ixgbe, when an interface is part of a namespace it is
possible that igb_close() may be called while __igb_shutdown() is
running which ends up in a double free WARN and/or a BUG in
free_msi_irqs().
Extend the rtnl_lock() to protect the call to netif_device_detach() and
igb_clear_interrupt_scheme() in __igb_shutdown() and check for
netif_device_present() to avoid calling igb_clear_interrupt_scheme() a
second time in igb_close().
Also extend the rtnl lock in igb_resume() to netif_device_attach().
Signed-off-by: Todd Fujinaka <todd.fujinaka@intel.com>
Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Layers on layers of workarounds does not lead to stability.
^ permalink raw reply
* RE: [PATCH] Fix handling of verdicts after NF_QUEUE
From: Banerjee, Debabrata @ 2017-12-12 0:36 UTC (permalink / raw)
To: 'Pablo Neira Ayuso'
Cc: David S . Miller, netfilter-devel@vger.kernel.org,
coreteam@netfilter.org, netdev@vger.kernel.org,
stable@vger.kernel.org
In-Reply-To: <20171212002318.GA7681@salvia>
> From: Pablo Neira Ayuso [mailto:pablo@netfilter.org]
> On Mon, Dec 11, 2017 at 06:30:24PM -0500, Debabrata Banerjee wrote:
> > + } else {
> > + /* Implicit handling for NF_STOLEN, as well as any other
> > + * non conventional verdicts.
> > + */
> > + ret = 0;
>
> Another possibility (more simple?) would be this:
>
> int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state) {
> struct nf_hook_entry *entry;
> unsigned int verdict;
> - int ret = 0;
> + int ret;
>
> entry = rcu_dereference(state->hook_entries);
> next_hook:
> + ret = 0;
>
> Basically, make sure ret is set to zero when jumping to the next_hook label.
Many ways to fix it, but I thought including the comment was appropriate.
Happy to change it if we want simpler instead.
-Deb
^ permalink raw reply
* Re: [PATCH] igb: Free IRQs when device is hotplugged
From: Lyude Paul @ 2017-12-12 0:37 UTC (permalink / raw)
To: Stephen Hemminger
Cc: intel-wired-lan, Todd Fujinaka, stable, Jeff Kirsher, netdev,
linux-kernel
In-Reply-To: <20171211163422.07d538fb@xeon-e3>
On Mon, 2017-12-11 at 16:34 -0800, Stephen Hemminger wrote:
> On Mon, 11 Dec 2017 18:45:02 -0500
> Lyude Paul <lyude@redhat.com> wrote:
>
> > Recently I got a Caldigit TS3 Thunderbolt 3 dock, and noticed that upon
> > hotplugging my kernel would immediately crash due to igb:
> >
> > [ 680.825801] kernel BUG at drivers/pci/msi.c:352!
> > [ 680.828388] invalid opcode: 0000 [#1] SMP
> > [ 680.829194] Modules linked in: igb(O) thunderbolt i2c_algo_bit joydev
> > vfat fat btusb btrtl btbcm btintel bluetooth ecdh_generic hp_wmi
> > sparse_keymap rfkill wmi_bmof iTCO_wdt intel_rapl x86_pkg_temp_thermal
> > coretemp crc32_pclmul snd_pcm rtsx_pci_ms mei_me snd_timer memstick snd
> > pcspkr mei soundcore i2c_i801 tpm_tis psmouse shpchp wmi tpm_tis_core tpm
> > video hp_wireless acpi_pad rtsx_pci_sdmmc mmc_core crc32c_intel serio_raw
> > rtsx_pci mfd_core xhci_pci xhci_hcd i2c_hid i2c_core [last unloaded: igb]
> > [ 680.831085] CPU: 1 PID: 78 Comm: kworker/u16:1 Tainted:
> > G O 4.15.0-rc3Lyude-Test+ #6
> > [ 680.831596] Hardware name: HP HP ZBook Studio G4/826B, BIOS P71 Ver.
> > 01.03 06/09/2017
> > [ 680.832168] Workqueue: kacpi_hotplug acpi_hotplug_work_fn
> > [ 680.832687] RIP: 0010:free_msi_irqs+0x180/0x1b0
> > [ 680.833271] RSP: 0018:ffffc9000030fbf0 EFLAGS: 00010286
> > [ 680.833761] RAX: ffff8803405f9c00 RBX: ffff88033e3d2e40 RCX:
> > 000000000000002c
> > [ 680.834278] RDX: 0000000000000000 RSI: 00000000000000ac RDI:
> > ffff880340be2178
> > [ 680.834832] RBP: 0000000000000000 R08: ffff880340be1ff0 R09:
> > ffff8803405f9c00
> > [ 680.835342] R10: 0000000000000000 R11: 0000000000000040 R12:
> > ffff88033d63a298
> > [ 680.835822] R13: ffff88033d63a000 R14: 0000000000000060 R15:
> > ffff880341959000
> > [ 680.836332] FS: 0000000000000000(0000) GS:ffff88034f440000(0000)
> > knlGS:0000000000000000
> > [ 680.836817] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [ 680.837360] CR2: 000055e64044afdf CR3: 0000000001c09002 CR4:
> > 00000000003606e0
> > [ 680.837954] Call Trace:
> > [ 680.838853] pci_disable_msix+0xce/0xf0
> > [ 680.839616] igb_reset_interrupt_capability+0x5d/0x60 [igb]
> > [ 680.840278] igb_remove+0x9d/0x110 [igb]
> > [ 680.840764] pci_device_remove+0x36/0xb0
> > [ 680.841279] device_release_driver_internal+0x157/0x220
> > [ 680.841739] pci_stop_bus_device+0x7d/0xa0
> > [ 680.842255] pci_stop_bus_device+0x2b/0xa0
> > [ 680.842722] pci_stop_bus_device+0x3d/0xa0
> > [ 680.843189] pci_stop_and_remove_bus_device+0xe/0x20
> > [ 680.843627] trim_stale_devices+0xf3/0x140
> > [ 680.844086] trim_stale_devices+0x94/0x140
> > [ 680.844532] trim_stale_devices+0xa6/0x140
> > [ 680.845031] ? get_slot_status+0x90/0xc0
> > [ 680.845536] acpiphp_check_bridge.part.5+0xfe/0x140
> > [ 680.846021] acpiphp_hotplug_notify+0x175/0x200
> > [ 680.846581] ? free_bridge+0x100/0x100
> > [ 680.847113] acpi_device_hotplug+0x8a/0x490
> > [ 680.847535] acpi_hotplug_work_fn+0x1a/0x30
> > [ 680.848076] process_one_work+0x182/0x3a0
> > [ 680.848543] worker_thread+0x2e/0x380
> > [ 680.848963] ? process_one_work+0x3a0/0x3a0
> > [ 680.849373] kthread+0x111/0x130
> > [ 680.849776] ? kthread_create_worker_on_cpu+0x50/0x50
> > [ 680.850188] ret_from_fork+0x1f/0x30
> > [ 680.850601] Code: 43 14 85 c0 0f 84 d5 fe ff ff 31 ed eb 0f 83 c5 01 39
> > 6b 14 0f 86 c5 fe ff ff 8b 7b 10 01 ef e8 b7 e4 d2 ff 48 83 78 70 00 74 e3
> > <0f> 0b 49 8d b5 a0 00 00 00 e8 62 6f d3 ff e9 c7 fe ff ff 48 8b
> > [ 680.851497] RIP: free_msi_irqs+0x180/0x1b0 RSP: ffffc9000030fbf0
> >
> > As it turns out, normally the freeing of IRQs that would fix this is called
> > inside of the scope of __igb_close(). However, since the device is
> > already gone by the point we try to unregister the netdevice from the
> > driver due to a hotplug we end up seeing that the netif isn't present
> > and thus, forget to free any of the device IRQs.
> >
> > So: after unregistering the netdev in igb_remove() check whether the PCI
> > device is stale and if so, free it's IRQs and tx/rx resources.
> >
> > Signed-off-by: Lyude Paul <lyude@redhat.com>
> > Fixes: 9474933caf21 ("igb: close/suspend race in netif_device_detach")
> > Cc: Todd Fujinaka <todd.fujinaka@intel.com>
> > Cc: stable@vger.kernel.org
> > ---
> > drivers/net/ethernet/intel/igb/igb_main.c | 10 ++++++++++
> > 1 file changed, 10 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/intel/igb/igb_main.c
> > b/drivers/net/ethernet/intel/igb/igb_main.c
> > index c208753ff5b7..e650348b4bd7 100644
> > --- a/drivers/net/ethernet/intel/igb/igb_main.c
> > +++ b/drivers/net/ethernet/intel/igb/igb_main.c
> > @@ -3325,6 +3325,16 @@ static void igb_remove(struct pci_dev *pdev)
> >
> > unregister_netdev(netdev);
> >
> > + /* If the PCI device has already been physically removed (e.g. user
> > + * unplugged a thunderbolt dock containing our hw) then the netif
> > will
> > + * already be down, so unregistering the netdev won't free the IRQs
> > + */
> > + if (!pci_device_is_present(pdev)) {
> > + igb_free_irq(adapter);
> > + igb_free_all_tx_resources(adapter);
> > + igb_free_all_rx_resources(adapter);
> > + }
> > +
> > igb_clear_interrupt_scheme(adapter);
> >
> > pci_iounmap(pdev, adapter->io_addr);
>
> This looks like you are making a special case out of something that should
> be fixed in igb_close instead.
>
> Most likely something is wrong with earlier commit.
>
> commit 9474933caf21a4cb5147223dca1551f527aaac36
> Author: Todd Fujinaka <todd.fujinaka@intel.com>
> Date: Tue Nov 15 08:54:26 2016 -0800
>
> igb: close/suspend race in netif_device_detach
>
> Similar to ixgbe, when an interface is part of a namespace it is
> possible that igb_close() may be called while __igb_shutdown() is
> running which ends up in a double free WARN and/or a BUG in
> free_msi_irqs().
>
> Extend the rtnl_lock() to protect the call to netif_device_detach() and
> igb_clear_interrupt_scheme() in __igb_shutdown() and check for
> netif_device_present() to avoid calling igb_clear_interrupt_scheme() a
> second time in igb_close().
>
> Also extend the rtnl lock in igb_resume() to netif_device_attach().
>
> Signed-off-by: Todd Fujinaka <todd.fujinaka@intel.com>
> Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
> Tested-by: Aaron Brown <aaron.f.brown@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
>
>
> Layers on layers of workarounds does not lead to stability.'
Agreed, although it should be noted though I mentioned that exact commit in the
patch I sent :P. Will rework patch and send out a new version.
>
^ permalink raw reply
* [PATCH iproute2 net-next v2 0/4] Abstract columns, properly space and wrap fields
From: Stefano Brivio @ 2017-12-12 0:46 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
Currently, 'ss' simply subdivides the whole available screen width
between available columns, starting from a set of hardcoded amount
of spacing and growing column widths.
This makes the output unreadable in several cases, as it doesn't take
into account the actual content width.
Fix this by introducing a simple abstraction for columns, buffering
the output, measuring the width of the fields, grouping fields into
lines as they fit, equally distributing any remaining whitespace, and
finally rendering the result. Some examples are reported below [1].
This implementation doesn't seem to cause any significant performance
issues, as reported in 3/4.
Patch 1/4 replaces all relevant printf() calls by the out() helper,
which simply consists of the usual printf() implementation.
Patch 2/4 implements column abstraction, with configurable column
width and delimiters, and 3/4 splits buffering and rendering phases,
employing a simple buffering mechanism with chunked allocation and
introducing a rendering function.
Up to this point, the output is still unchanged.
Finally, 4/4 introduces field width calculation based on content
length measured while buffering, in order to split fields onto
multiple lines and equally space them within the single lines.
Now that column behaviour is well-defined and more easily
configurable, it should be easier to further improve the output by
splitting logically separable information (e.g. TCP details) into
additional columns. However, this patchset keeps the full "extended"
information into a single column, for the moment being.
v2: rebase after conflict with 00ac78d39c29 ("ss: print tcpi_rcv_ssthresh")
[1]
- 80 columns terminal, ss -Z -f netlink
* before:
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 rtnl:evolution-calen/2075 * pr
oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:abrt-applet/32700 * pr
oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:firefox/21619 * pr
oc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:evolution-calen/32639 * p
roc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[...]
* after:
Recv-Q Send-Q Local Address:Port Peer Address:Port
0 0 rtnl:evolution-calen/2075 *
proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:abrt-applet/32700 *
proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:firefox/21619 *
proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
0 0 rtnl:evolution-calen/32639 *
proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[...]
- 80 columns terminal, ss -tunpl
* before:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 *:37732 *:*
udp UNCONN 0 0 *:5353 *:*
udp UNCONN 0 0 192.168.122.1:53 *:*
udp UNCONN 0 0 *%virbr0:67 *:*
[...]
* after:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 *:37732 *:*
udp UNCONN 0 0 *:5353 *:*
udp UNCONN 0 0 192.168.122.1:53 *:*
udp UNCONN 0 0 *%virbr0:67 *:*
[...]
- 66 columns terminal, ss -tunpl
* before:
Netid State Recv-Q Send-Q Local Address:Port P
eer Address:Port
udp UNCONN 0 0 *:37732 *:*
udp UNCONN 0 0 *:5353 *:*
udp UNCONN 0 0 192.168.122.1:53
*:*
udp UNCONN 0 0 *%virbr0:67 *:*
[...]
* after:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 *:37732 *:*
udp UNCONN 0 0 *:5353 *:*
udp UNCONN 0 0 192.168.122.1:53 *:*
udp UNCONN 0 0 *%virbr0:67 *:*
[...]
Stefano Brivio (4):
ss: Replace printf() calls for "main" output by calls to helper
ss: Introduce columns lightweight abstraction
ss: Buffer raw fields first, then render them as a table
ss: Implement automatic column width calculation
misc/ss.c | 895 +++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 621 insertions(+), 274 deletions(-)
--
2.9.4
^ permalink raw reply
* [PATCH iproute2 net-next v2 1/4] ss: Replace printf() calls for "main" output by calls to helper
From: Stefano Brivio @ 2017-12-12 0:46 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1513039237.git.sbrivio@redhat.com>
This is preparation work for output buffering, which will allow
us to use optimal spacing and alignment of logical "columns".
The new out() function is just a re-implementation of a typical
libc's printf(), except that the return value of vfprintf() is
ignored as no callers use it. This implementation will be
replaced in the next patches to provide column width adjustment
and adequate spacing.
All printf() calls that output parts of the socket list are now
replaced by calls to out(). Output of summary and version is
excluded from this.
No functional differences here, output not affected.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
v2: rebase after conflict with 00ac78d39c29 ("ss: print tcpi_rcv_ssthresh")
misc/ss.c | 399 ++++++++++++++++++++++++++++++++------------------------------
1 file changed, 205 insertions(+), 194 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index da52d5edeb7e..a7d3b89e1478 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include <stdbool.h>
#include <limits.h>
+#include <stdarg.h>
#include "utils.h"
#include "rt_names.h"
@@ -823,6 +824,15 @@ static const char *vsock_netid_name(int type)
}
}
+static void out(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ va_end(args);
+}
+
static void sock_state_print(struct sockstat *s)
{
const char *sock_name;
@@ -863,39 +873,39 @@ static void sock_state_print(struct sockstat *s)
}
if (netid_width)
- printf("%-*s ", netid_width,
- is_sctp_assoc(s, sock_name) ? "" : sock_name);
+ out("%-*s ", netid_width,
+ is_sctp_assoc(s, sock_name) ? "" : sock_name);
if (state_width) {
if (is_sctp_assoc(s, sock_name))
- printf("`- %-*s ", state_width - 3,
- sctp_sstate_name[s->state]);
+ out("`- %-*s ", state_width - 3,
+ sctp_sstate_name[s->state]);
else
- printf("%-*s ", state_width, sstate_name[s->state]);
+ out("%-*s ", state_width, sstate_name[s->state]);
}
- printf("%-6d %-6d %s", s->rq, s->wq, odd_width_pad);
+ out("%-6d %-6d %s", s->rq, s->wq, odd_width_pad);
}
static void sock_details_print(struct sockstat *s)
{
if (s->uid)
- printf(" uid:%u", s->uid);
+ out(" uid:%u", s->uid);
- printf(" ino:%u", s->ino);
- printf(" sk:%llx", s->sk);
+ out(" ino:%u", s->ino);
+ out(" sk:%llx", s->sk);
if (s->mark)
- printf(" fwmark:0x%x", s->mark);
+ out(" fwmark:0x%x", s->mark);
}
static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
int port_len, const char *port, const char *ifname)
{
if (ifname) {
- printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
- port_len, port);
+ out("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
+ port_len, port);
} else {
- printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
+ out("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
}
}
@@ -1793,12 +1803,12 @@ static void proc_ctx_print(struct sockstat *s)
if (find_entry(s->ino, &buf,
(show_proc_ctx & show_sock_ctx) ?
PROC_SOCK_CTX : PROC_CTX) > 0) {
- printf(" users:(%s)", buf);
+ out(" users:(%s)", buf);
free(buf);
}
} else if (show_users) {
if (find_entry(s->ino, &buf, USERS) > 0) {
- printf(" users:(%s)", buf);
+ out(" users:(%s)", buf);
free(buf);
}
}
@@ -1878,51 +1888,51 @@ static char *sprint_bw(char *buf, double bw)
static void sctp_stats_print(struct sctp_info *s)
{
if (s->sctpi_tag)
- printf(" tag:%x", s->sctpi_tag);
+ out(" tag:%x", s->sctpi_tag);
if (s->sctpi_state)
- printf(" state:%s", sctp_sstate_name[s->sctpi_state]);
+ out(" state:%s", sctp_sstate_name[s->sctpi_state]);
if (s->sctpi_rwnd)
- printf(" rwnd:%d", s->sctpi_rwnd);
+ out(" rwnd:%d", s->sctpi_rwnd);
if (s->sctpi_unackdata)
- printf(" unackdata:%d", s->sctpi_unackdata);
+ out(" unackdata:%d", s->sctpi_unackdata);
if (s->sctpi_penddata)
- printf(" penddata:%d", s->sctpi_penddata);
+ out(" penddata:%d", s->sctpi_penddata);
if (s->sctpi_instrms)
- printf(" instrms:%d", s->sctpi_instrms);
+ out(" instrms:%d", s->sctpi_instrms);
if (s->sctpi_outstrms)
- printf(" outstrms:%d", s->sctpi_outstrms);
+ out(" outstrms:%d", s->sctpi_outstrms);
if (s->sctpi_inqueue)
- printf(" inqueue:%d", s->sctpi_inqueue);
+ out(" inqueue:%d", s->sctpi_inqueue);
if (s->sctpi_outqueue)
- printf(" outqueue:%d", s->sctpi_outqueue);
+ out(" outqueue:%d", s->sctpi_outqueue);
if (s->sctpi_overall_error)
- printf(" overerr:%d", s->sctpi_overall_error);
+ out(" overerr:%d", s->sctpi_overall_error);
if (s->sctpi_max_burst)
- printf(" maxburst:%d", s->sctpi_max_burst);
+ out(" maxburst:%d", s->sctpi_max_burst);
if (s->sctpi_maxseg)
- printf(" maxseg:%d", s->sctpi_maxseg);
+ out(" maxseg:%d", s->sctpi_maxseg);
if (s->sctpi_peer_rwnd)
- printf(" prwnd:%d", s->sctpi_peer_rwnd);
+ out(" prwnd:%d", s->sctpi_peer_rwnd);
if (s->sctpi_peer_tag)
- printf(" ptag:%x", s->sctpi_peer_tag);
+ out(" ptag:%x", s->sctpi_peer_tag);
if (s->sctpi_peer_capable)
- printf(" pcapable:%d", s->sctpi_peer_capable);
+ out(" pcapable:%d", s->sctpi_peer_capable);
if (s->sctpi_peer_sack)
- printf(" psack:%d", s->sctpi_peer_sack);
+ out(" psack:%d", s->sctpi_peer_sack);
if (s->sctpi_s_autoclose)
- printf(" autoclose:%d", s->sctpi_s_autoclose);
+ out(" autoclose:%d", s->sctpi_s_autoclose);
if (s->sctpi_s_adaptation_ind)
- printf(" adapind:%d", s->sctpi_s_adaptation_ind);
+ out(" adapind:%d", s->sctpi_s_adaptation_ind);
if (s->sctpi_s_pd_point)
- printf(" pdpoint:%d", s->sctpi_s_pd_point);
+ out(" pdpoint:%d", s->sctpi_s_pd_point);
if (s->sctpi_s_nodelay)
- printf(" nodealy:%d", s->sctpi_s_nodelay);
+ out(" nodealy:%d", s->sctpi_s_nodelay);
if (s->sctpi_s_disable_fragments)
- printf(" nofrag:%d", s->sctpi_s_disable_fragments);
+ out(" nofrag:%d", s->sctpi_s_disable_fragments);
if (s->sctpi_s_v4mapped)
- printf(" v4mapped:%d", s->sctpi_s_v4mapped);
+ out(" v4mapped:%d", s->sctpi_s_v4mapped);
if (s->sctpi_s_frag_interleave)
- printf(" fraginl:%d", s->sctpi_s_frag_interleave);
+ out(" fraginl:%d", s->sctpi_s_frag_interleave);
}
static void tcp_stats_print(struct tcpstat *s)
@@ -1930,65 +1940,65 @@ static void tcp_stats_print(struct tcpstat *s)
char b1[64];
if (s->has_ts_opt)
- printf(" ts");
+ out(" ts");
if (s->has_sack_opt)
- printf(" sack");
+ out(" sack");
if (s->has_ecn_opt)
- printf(" ecn");
+ out(" ecn");
if (s->has_ecnseen_opt)
- printf(" ecnseen");
+ out(" ecnseen");
if (s->has_fastopen_opt)
- printf(" fastopen");
+ out(" fastopen");
if (s->cong_alg[0])
- printf(" %s", s->cong_alg);
+ out(" %s", s->cong_alg);
if (s->has_wscale_opt)
- printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
+ out(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
if (s->rto)
- printf(" rto:%g", s->rto);
+ out(" rto:%g", s->rto);
if (s->backoff)
- printf(" backoff:%u", s->backoff);
+ out(" backoff:%u", s->backoff);
if (s->rtt)
- printf(" rtt:%g/%g", s->rtt, s->rttvar);
+ out(" rtt:%g/%g", s->rtt, s->rttvar);
if (s->ato)
- printf(" ato:%g", s->ato);
+ out(" ato:%g", s->ato);
if (s->qack)
- printf(" qack:%d", s->qack);
+ out(" qack:%d", s->qack);
if (s->qack & 1)
- printf(" bidir");
+ out(" bidir");
if (s->mss)
- printf(" mss:%d", s->mss);
+ out(" mss:%d", s->mss);
if (s->rcv_mss)
- printf(" rcvmss:%d", s->rcv_mss);
+ out(" rcvmss:%d", s->rcv_mss);
if (s->advmss)
- printf(" advmss:%d", s->advmss);
+ out(" advmss:%d", s->advmss);
if (s->cwnd)
- printf(" cwnd:%u", s->cwnd);
+ out(" cwnd:%u", s->cwnd);
if (s->ssthresh)
- printf(" ssthresh:%d", s->ssthresh);
+ out(" ssthresh:%d", s->ssthresh);
if (s->bytes_acked)
- printf(" bytes_acked:%llu", s->bytes_acked);
+ out(" bytes_acked:%llu", s->bytes_acked);
if (s->bytes_received)
- printf(" bytes_received:%llu", s->bytes_received);
+ out(" bytes_received:%llu", s->bytes_received);
if (s->segs_out)
- printf(" segs_out:%u", s->segs_out);
+ out(" segs_out:%u", s->segs_out);
if (s->segs_in)
- printf(" segs_in:%u", s->segs_in);
+ out(" segs_in:%u", s->segs_in);
if (s->data_segs_out)
- printf(" data_segs_out:%u", s->data_segs_out);
+ out(" data_segs_out:%u", s->data_segs_out);
if (s->data_segs_in)
- printf(" data_segs_in:%u", s->data_segs_in);
+ out(" data_segs_in:%u", s->data_segs_in);
if (s->dctcp && s->dctcp->enabled) {
struct dctcpstat *dctcp = s->dctcp;
- printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
- dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
- dctcp->ab_tot);
+ out(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
+ dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
+ dctcp->ab_tot);
} else if (s->dctcp) {
- printf(" dctcp:fallback_mode");
+ out(" dctcp:fallback_mode");
}
if (s->bbr_info) {
@@ -1998,73 +2008,72 @@ static void tcp_stats_print(struct tcpstat *s)
bw <<= 32;
bw |= s->bbr_info->bbr_bw_lo;
- printf(" bbr:(bw:%sbps,mrtt:%g",
- sprint_bw(b1, bw * 8.0),
- (double)s->bbr_info->bbr_min_rtt / 1000.0);
+ out(" bbr:(bw:%sbps,mrtt:%g",
+ sprint_bw(b1, bw * 8.0),
+ (double)s->bbr_info->bbr_min_rtt / 1000.0);
if (s->bbr_info->bbr_pacing_gain)
- printf(",pacing_gain:%g",
- (double)s->bbr_info->bbr_pacing_gain / 256.0);
+ out(",pacing_gain:%g",
+ (double)s->bbr_info->bbr_pacing_gain / 256.0);
if (s->bbr_info->bbr_cwnd_gain)
- printf(",cwnd_gain:%g",
- (double)s->bbr_info->bbr_cwnd_gain / 256.0);
- printf(")");
+ out(",cwnd_gain:%g",
+ (double)s->bbr_info->bbr_cwnd_gain / 256.0);
+ out(")");
}
if (s->send_bps)
- printf(" send %sbps", sprint_bw(b1, s->send_bps));
+ out(" send %sbps", sprint_bw(b1, s->send_bps));
if (s->lastsnd)
- printf(" lastsnd:%u", s->lastsnd);
+ out(" lastsnd:%u", s->lastsnd);
if (s->lastrcv)
- printf(" lastrcv:%u", s->lastrcv);
+ out(" lastrcv:%u", s->lastrcv);
if (s->lastack)
- printf(" lastack:%u", s->lastack);
+ out(" lastack:%u", s->lastack);
if (s->pacing_rate) {
- printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
+ out(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
if (s->pacing_rate_max)
- printf("/%sbps", sprint_bw(b1,
- s->pacing_rate_max));
+ out("/%sbps", sprint_bw(b1, s->pacing_rate_max));
}
if (s->delivery_rate)
- printf(" delivery_rate %sbps", sprint_bw(b1, s->delivery_rate));
+ out(" delivery_rate %sbps", sprint_bw(b1, s->delivery_rate));
if (s->app_limited)
- printf(" app_limited");
+ out(" app_limited");
if (s->busy_time) {
- printf(" busy:%llums", s->busy_time / 1000);
+ out(" busy:%llums", s->busy_time / 1000);
if (s->rwnd_limited)
- printf(" rwnd_limited:%llums(%.1f%%)",
- s->rwnd_limited / 1000,
- 100.0 * s->rwnd_limited / s->busy_time);
+ out(" rwnd_limited:%llums(%.1f%%)",
+ s->rwnd_limited / 1000,
+ 100.0 * s->rwnd_limited / s->busy_time);
if (s->sndbuf_limited)
- printf(" sndbuf_limited:%llums(%.1f%%)",
- s->sndbuf_limited / 1000,
- 100.0 * s->sndbuf_limited / s->busy_time);
+ out(" sndbuf_limited:%llums(%.1f%%)",
+ s->sndbuf_limited / 1000,
+ 100.0 * s->sndbuf_limited / s->busy_time);
}
if (s->unacked)
- printf(" unacked:%u", s->unacked);
+ out(" unacked:%u", s->unacked);
if (s->retrans || s->retrans_total)
- printf(" retrans:%u/%u", s->retrans, s->retrans_total);
+ out(" retrans:%u/%u", s->retrans, s->retrans_total);
if (s->lost)
- printf(" lost:%u", s->lost);
+ out(" lost:%u", s->lost);
if (s->sacked && s->ss.state != SS_LISTEN)
- printf(" sacked:%u", s->sacked);
+ out(" sacked:%u", s->sacked);
if (s->fackets)
- printf(" fackets:%u", s->fackets);
+ out(" fackets:%u", s->fackets);
if (s->reordering != 3)
- printf(" reordering:%d", s->reordering);
+ out(" reordering:%d", s->reordering);
if (s->rcv_rtt)
- printf(" rcv_rtt:%g", s->rcv_rtt);
+ out(" rcv_rtt:%g", s->rcv_rtt);
if (s->rcv_space)
- printf(" rcv_space:%d", s->rcv_space);
+ out(" rcv_space:%d", s->rcv_space);
if (s->rcv_ssthresh)
- printf(" rcv_ssthresh:%u", s->rcv_ssthresh);
+ out(" rcv_ssthresh:%u", s->rcv_ssthresh);
if (s->not_sent)
- printf(" notsent:%u", s->not_sent);
+ out(" notsent:%u", s->not_sent);
if (s->min_rtt)
- printf(" minrtt:%g", s->min_rtt);
+ out(" minrtt:%g", s->min_rtt);
}
static void tcp_timer_print(struct tcpstat *s)
@@ -2081,18 +2090,18 @@ static void tcp_timer_print(struct tcpstat *s)
if (s->timer) {
if (s->timer > 4)
s->timer = 5;
- printf(" timer:(%s,%s,%d)",
- tmr_name[s->timer],
- print_ms_timer(s->timeout),
- s->retrans);
+ out(" timer:(%s,%s,%d)",
+ tmr_name[s->timer],
+ print_ms_timer(s->timeout),
+ s->retrans);
}
}
static void sctp_timer_print(struct tcpstat *s)
{
if (s->timer)
- printf(" timer:(T3_RTX,%s,%d)",
- print_ms_timer(s->timeout), s->retrans);
+ out(" timer:(T3_RTX,%s,%d)",
+ print_ms_timer(s->timeout), s->retrans);
}
static int tcp_show_line(char *line, const struct filter *f, int family)
@@ -2151,13 +2160,13 @@ static int tcp_show_line(char *line, const struct filter *f, int family)
if (show_details) {
sock_details_print(&s.ss);
if (opt[0])
- printf(" opt:\"%s\"", opt);
+ out(" opt:\"%s\"", opt);
}
if (show_tcpinfo)
tcp_stats_print(&s);
- printf("\n");
+ out("\n");
return 0;
}
@@ -2200,44 +2209,44 @@ static void print_skmeminfo(struct rtattr *tb[], int attrtype)
const struct inet_diag_meminfo *minfo =
RTA_DATA(tb[INET_DIAG_MEMINFO]);
- printf(" mem:(r%u,w%u,f%u,t%u)",
- minfo->idiag_rmem,
- minfo->idiag_wmem,
- minfo->idiag_fmem,
- minfo->idiag_tmem);
+ out(" mem:(r%u,w%u,f%u,t%u)",
+ minfo->idiag_rmem,
+ minfo->idiag_wmem,
+ minfo->idiag_fmem,
+ minfo->idiag_tmem);
}
return;
}
skmeminfo = RTA_DATA(tb[attrtype]);
- printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
- skmeminfo[SK_MEMINFO_RMEM_ALLOC],
- skmeminfo[SK_MEMINFO_RCVBUF],
- skmeminfo[SK_MEMINFO_WMEM_ALLOC],
- skmeminfo[SK_MEMINFO_SNDBUF],
- skmeminfo[SK_MEMINFO_FWD_ALLOC],
- skmeminfo[SK_MEMINFO_WMEM_QUEUED],
- skmeminfo[SK_MEMINFO_OPTMEM]);
+ out(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
+ skmeminfo[SK_MEMINFO_RMEM_ALLOC],
+ skmeminfo[SK_MEMINFO_RCVBUF],
+ skmeminfo[SK_MEMINFO_WMEM_ALLOC],
+ skmeminfo[SK_MEMINFO_SNDBUF],
+ skmeminfo[SK_MEMINFO_FWD_ALLOC],
+ skmeminfo[SK_MEMINFO_WMEM_QUEUED],
+ skmeminfo[SK_MEMINFO_OPTMEM]);
if (RTA_PAYLOAD(tb[attrtype]) >=
(SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
- printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
+ out(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
if (RTA_PAYLOAD(tb[attrtype]) >=
(SK_MEMINFO_DROPS + 1) * sizeof(__u32))
- printf(",d%u", skmeminfo[SK_MEMINFO_DROPS]);
+ out(",d%u", skmeminfo[SK_MEMINFO_DROPS]);
- printf(")");
+ out(")");
}
static void print_md5sig(struct tcp_diag_md5sig *sig)
{
- printf("%s/%d=",
- format_host(sig->tcpm_family,
- sig->tcpm_family == AF_INET6 ? 16 : 4,
- &sig->tcpm_addr),
- sig->tcpm_prefixlen);
+ out("%s/%d=",
+ format_host(sig->tcpm_family,
+ sig->tcpm_family == AF_INET6 ? 16 : 4,
+ &sig->tcpm_addr),
+ sig->tcpm_prefixlen);
print_escape_buf(sig->tcpm_key, sig->tcpm_keylen, " ,");
}
@@ -2382,10 +2391,10 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
struct tcp_diag_md5sig *sig = RTA_DATA(tb[INET_DIAG_MD5SIG]);
int len = RTA_PAYLOAD(tb[INET_DIAG_MD5SIG]);
- printf(" md5keys:");
+ out(" md5keys:");
print_md5sig(sig++);
for (len -= sizeof(*sig); len > 0; len -= sizeof(*sig)) {
- printf(",");
+ out(",");
print_md5sig(sig++);
}
}
@@ -2420,18 +2429,18 @@ static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]);
sa = RTA_DATA(tb[INET_DIAG_LOCALS]);
- printf("locals:%s", format_host_sa(sa));
+ out("locals:%s", format_host_sa(sa));
for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
- printf(",%s", format_host_sa(sa));
+ out(",%s", format_host_sa(sa));
}
if (tb[INET_DIAG_PEERS]) {
len = RTA_PAYLOAD(tb[INET_DIAG_PEERS]);
sa = RTA_DATA(tb[INET_DIAG_PEERS]);
- printf(" peers:%s", format_host_sa(sa));
+ out(" peers:%s", format_host_sa(sa));
for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
- printf(",%s", format_host_sa(sa));
+ out(",%s", format_host_sa(sa));
}
if (tb[INET_DIAG_INFO]) {
struct sctp_info *info;
@@ -2518,18 +2527,19 @@ static int inet_show_sock(struct nlmsghdr *nlh,
if (show_details) {
sock_details_print(s);
if (s->local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY])
- printf(" v6only:%u", v6only);
+ out(" v6only:%u", v6only);
if (tb[INET_DIAG_SHUTDOWN]) {
unsigned char mask;
mask = rta_getattr_u8(tb[INET_DIAG_SHUTDOWN]);
- printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+ out(" %c-%c",
+ mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
if (show_mem || (show_tcpinfo && s->type != IPPROTO_UDP)) {
- printf("\n\t");
+ out("\n\t");
if (s->type == IPPROTO_SCTP)
sctp_show_info(nlh, r, tb);
else
@@ -2537,7 +2547,7 @@ static int inet_show_sock(struct nlmsghdr *nlh,
}
sctp_ino = s->ino;
- printf("\n");
+ out("\n");
return 0;
}
@@ -2993,9 +3003,9 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
inet_stats_print(&s, false);
if (show_details && opt[0])
- printf(" opt:\"%s\"", opt);
+ out(" opt:\"%s\"", opt);
- printf("\n");
+ out("\n");
return 0;
}
@@ -3170,10 +3180,11 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
unsigned char mask;
mask = rta_getattr_u8(tb[UNIX_DIAG_SHUTDOWN]);
- printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
+ out(" %c-%c",
+ mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
- printf("\n");
+ out("\n");
return 0;
}
@@ -3330,7 +3341,7 @@ static int unix_show(struct filter *f)
if (++cnt > MAX_UNIX_REMEMBER) {
while (list) {
unix_stats_print(list, f);
- printf("\n");
+ out("\n");
unix_list_drop_first(&list);
}
@@ -3340,7 +3351,7 @@ static int unix_show(struct filter *f)
fclose(fp);
while (list) {
unix_stats_print(list, f);
- printf("\n");
+ out("\n");
unix_list_drop_first(&list);
}
@@ -3386,12 +3397,12 @@ static int packet_stats_print(struct sockstat *s, const struct filter *f)
static void packet_show_ring(struct packet_diag_ring *ring)
{
- printf("blk_size:%d", ring->pdr_block_size);
- printf(",blk_nr:%d", ring->pdr_block_nr);
- printf(",frm_size:%d", ring->pdr_frame_size);
- printf(",frm_nr:%d", ring->pdr_frame_nr);
- printf(",tmo:%d", ring->pdr_retire_tmo);
- printf(",features:0x%x", ring->pdr_features);
+ out("blk_size:%d", ring->pdr_block_size);
+ out(",blk_nr:%d", ring->pdr_block_nr);
+ out(",frm_size:%d", ring->pdr_frame_size);
+ out(",frm_nr:%d", ring->pdr_frame_nr);
+ out(",tmo:%d", ring->pdr_retire_tmo);
+ out(",features:0x%x", ring->pdr_features);
}
static int packet_show_sock(const struct sockaddr_nl *addr,
@@ -3449,56 +3460,56 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
if (show_details) {
if (pinfo) {
- printf("\n\tver:%d", pinfo->pdi_version);
- printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
- printf(" flags( ");
+ out("\n\tver:%d", pinfo->pdi_version);
+ out(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
+ out(" flags( ");
if (pinfo->pdi_flags & PDI_RUNNING)
- printf("running");
+ out("running");
if (pinfo->pdi_flags & PDI_AUXDATA)
- printf(" auxdata");
+ out(" auxdata");
if (pinfo->pdi_flags & PDI_ORIGDEV)
- printf(" origdev");
+ out(" origdev");
if (pinfo->pdi_flags & PDI_VNETHDR)
- printf(" vnethdr");
+ out(" vnethdr");
if (pinfo->pdi_flags & PDI_LOSS)
- printf(" loss");
+ out(" loss");
if (!pinfo->pdi_flags)
- printf("0");
- printf(" )");
+ out("0");
+ out(" )");
}
if (ring_rx) {
- printf("\n\tring_rx(");
+ out("\n\tring_rx(");
packet_show_ring(ring_rx);
- printf(")");
+ out(")");
}
if (ring_tx) {
- printf("\n\tring_tx(");
+ out("\n\tring_tx(");
packet_show_ring(ring_tx);
- printf(")");
+ out(")");
}
if (has_fanout) {
uint16_t type = (fanout >> 16) & 0xffff;
- printf("\n\tfanout(");
- printf("id:%d,", fanout & 0xffff);
- printf("type:");
+ out("\n\tfanout(");
+ out("id:%d,", fanout & 0xffff);
+ out("type:");
if (type == 0)
- printf("hash");
+ out("hash");
else if (type == 1)
- printf("lb");
+ out("lb");
else if (type == 2)
- printf("cpu");
+ out("cpu");
else if (type == 3)
- printf("roll");
+ out("roll");
else if (type == 4)
- printf("random");
+ out("random");
else if (type == 5)
- printf("qm");
+ out("qm");
else
- printf("0x%x", type);
+ out("0x%x", type);
- printf(")");
+ out(")");
}
}
@@ -3508,15 +3519,15 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
sizeof(struct sock_filter);
- printf("\n\tbpf filter (%d): ", num);
+ out("\n\tbpf filter (%d): ", num);
while (num) {
- printf(" 0x%02x %u %u %u,",
- fil->code, fil->jt, fil->jf, fil->k);
+ out(" 0x%02x %u %u %u,",
+ fil->code, fil->jt, fil->jf, fil->k);
num--;
fil++;
}
}
- printf("\n");
+ out("\n");
return 0;
}
@@ -3559,7 +3570,7 @@ static int packet_show_line(char *buf, const struct filter *f, int fam)
if (packet_stats_print(&stat, f))
return 0;
- printf("\n");
+ out("\n");
return 0;
}
@@ -3672,14 +3683,14 @@ static int netlink_show_one(struct filter *f,
else if (pid > 0)
getpidcon(pid, &pid_context);
- printf(" proc_ctx=%s", pid_context ? : "unavailable");
+ out(" proc_ctx=%s", pid_context ? : "unavailable");
free(pid_context);
}
if (show_details) {
- printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
+ out(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
}
- printf("\n");
+ out("\n");
return 0;
}
@@ -3715,9 +3726,9 @@ static int netlink_show_sock(const struct sockaddr_nl *addr,
}
if (show_mem) {
- printf("\t");
+ out("\t");
print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
- printf("\n");
+ out("\n");
}
return 0;
@@ -3808,7 +3819,7 @@ static void vsock_stats_print(struct sockstat *s, struct filter *f)
proc_ctx_print(s);
- printf("\n");
+ out("\n");
}
static int vsock_show_sock(const struct sockaddr_nl *addr,
@@ -4573,10 +4584,10 @@ int main(int argc, char *argv[])
if (show_header) {
if (netid_width)
- printf("%-*s ", netid_width, "Netid");
+ out("%-*s ", netid_width, "Netid");
if (state_width)
- printf("%-*s ", state_width, "State");
- printf("%-6s %-6s %s", "Recv-Q", "Send-Q", odd_width_pad);
+ out("%-*s ", state_width, "State");
+ out("%-6s %-6s %s", "Recv-Q", "Send-Q", odd_width_pad);
}
/* Make enough space for the local/remote port field */
@@ -4584,9 +4595,9 @@ int main(int argc, char *argv[])
serv_width += 13;
if (show_header) {
- printf("%*s:%-*s %*s:%-*s\n",
- addr_width, "Local Address", serv_width, "Port",
- addr_width, "Peer Address", serv_width, "Port");
+ out("%*s:%-*s %*s:%-*s\n",
+ addr_width, "Local Address", serv_width, "Port",
+ addr_width, "Peer Address", serv_width, "Port");
}
fflush(stdout);
--
2.9.4
^ permalink raw reply related
* [PATCH iproute2 net-next v2 2/4] ss: Introduce columns lightweight abstraction
From: Stefano Brivio @ 2017-12-12 0:46 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1513039237.git.sbrivio@redhat.com>
Instead of embedding spacing directly while printing contents,
logically declare columns and functions to buffer their content,
to print left and right spacing around fields, to flush them to
screen, and to print headers.
This makes it a bit easier to handle layout changes and prepares
for full output buffering, needed for optimal spacing in field
output layout.
Columns are currently set up to retain exactly the same output
as before. This needs some slight adjustments of the values
previously calculated in main(), as the width value introduced
here already includes the width of left delimiters and spacing
is not explicitly printed anymore whenever a field is printed.
These calculations will go away altogether once automatic width
calculation is implemented.
We can also remove explicit printing of newlines after the final
content for a given line is printed, flushing the last field on
a line will cause field_flush() to print newlines where
appropriate.
No changes in output expected here.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
v2: rebase after conflict with 00ac78d39c29 ("ss: print tcpi_rcv_ssthresh")
misc/ss.c | 291 ++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 198 insertions(+), 93 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index a7d3b89e1478..42310ba4120d 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -103,11 +103,48 @@ int show_header = 1;
int follow_events;
int sctp_ino;
-int netid_width;
-int state_width;
-int addr_width;
-int serv_width;
-char *odd_width_pad = "";
+enum col_id {
+ COL_NETID,
+ COL_STATE,
+ COL_RECVQ,
+ COL_SENDQ,
+ COL_ADDR,
+ COL_SERV,
+ COL_RADDR,
+ COL_RSERV,
+ COL_EXT,
+ COL_MAX
+};
+
+enum col_align {
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
+};
+
+struct column {
+ const enum col_align align;
+ const char *header;
+ const char *ldelim;
+ int width; /* Including delimiter. -1: fit to content, 0: hide */
+ int stored; /* Characters buffered */
+ int printed; /* Characters printed so far */
+};
+
+static struct column columns[] = {
+ { ALIGN_LEFT, "Netid", "", 0, 0, 0 },
+ { ALIGN_LEFT, "State", " ", 0, 0, 0 },
+ { ALIGN_LEFT, "Recv-Q", " ", 7, 0, 0 },
+ { ALIGN_LEFT, "Send-Q", " ", 7, 0, 0 },
+ { ALIGN_RIGHT, "Local Address:", " ", 0, 0, 0 },
+ { ALIGN_LEFT, "Port", "", 0, 0, 0 },
+ { ALIGN_RIGHT, "Peer Address:", " ", 0, 0, 0 },
+ { ALIGN_LEFT, "Port", "", 0, 0, 0 },
+ { ALIGN_LEFT, "", "", -1, 0, 0 },
+};
+
+static struct column *current_field = columns;
+static char field_buf[BUFSIZ];
static const char *TCP_PROTO = "tcp";
static const char *SCTP_PROTO = "sctp";
@@ -826,13 +863,113 @@ static const char *vsock_netid_name(int type)
static void out(const char *fmt, ...)
{
+ struct column *f = current_field;
va_list args;
va_start(args, fmt);
- vfprintf(stdout, fmt, args);
+ f->stored += vsnprintf(field_buf + f->stored, BUFSIZ - f->stored,
+ fmt, args);
va_end(args);
}
+static int print_left_spacing(struct column *f)
+{
+ int s;
+
+ if (f->width < 0 || f->align == ALIGN_LEFT)
+ return 0;
+
+ s = f->width - f->stored - f->printed;
+ if (f->align == ALIGN_CENTER)
+ /* If count of total spacing is odd, shift right by one */
+ s = (s + 1) / 2;
+
+ if (s > 0)
+ return printf("%*c", s, ' ');
+
+ return 0;
+}
+
+static void print_right_spacing(struct column *f)
+{
+ int s;
+
+ if (f->width < 0 || f->align == ALIGN_RIGHT)
+ return;
+
+ s = f->width - f->printed;
+ if (f->align == ALIGN_CENTER)
+ s /= 2;
+
+ if (s > 0)
+ printf("%*c", s, ' ');
+}
+
+static int field_needs_delimiter(struct column *f)
+{
+ if (!f->stored)
+ return 0;
+
+ /* Was another field already printed on this line? */
+ for (f--; f >= columns; f--)
+ if (f->width)
+ return 1;
+
+ return 0;
+}
+
+/* Flush given field to screen together with delimiter and spacing */
+static void field_flush(struct column *f)
+{
+ if (!f->width)
+ return;
+
+ if (field_needs_delimiter(f))
+ f->printed = printf("%s", f->ldelim);
+
+ f->printed += print_left_spacing(f);
+ f->printed += printf("%s", field_buf);
+ print_right_spacing(f);
+
+ *field_buf = 0;
+ f->printed = 0;
+ f->stored = 0;
+}
+
+static int field_is_last(struct column *f)
+{
+ return f - columns == COL_MAX - 1;
+}
+
+static void field_next(void)
+{
+ field_flush(current_field);
+
+ if (field_is_last(current_field)) {
+ printf("\n");
+ current_field = columns;
+ } else {
+ current_field++;
+ }
+}
+
+/* Walk through fields and flush them until we reach the desired one */
+static void field_set(enum col_id id)
+{
+ while (id != current_field - columns)
+ field_next();
+}
+
+/* Print header for all non-empty columns */
+static void print_header(void)
+{
+ while (!field_is_last(current_field)) {
+ if (current_field->width)
+ out(current_field->header);
+ field_next();
+ }
+}
+
static void sock_state_print(struct sockstat *s)
{
const char *sock_name;
@@ -872,18 +1009,21 @@ static void sock_state_print(struct sockstat *s)
sock_name = "unknown";
}
- if (netid_width)
- out("%-*s ", netid_width,
- is_sctp_assoc(s, sock_name) ? "" : sock_name);
- if (state_width) {
- if (is_sctp_assoc(s, sock_name))
- out("`- %-*s ", state_width - 3,
- sctp_sstate_name[s->state]);
- else
- out("%-*s ", state_width, sstate_name[s->state]);
+ if (is_sctp_assoc(s, sock_name)) {
+ field_set(COL_STATE); /* Empty Netid field */
+ out("`- %s", sctp_sstate_name[s->state]);
+ } else {
+ field_set(COL_NETID);
+ out("%s", sock_name);
+ field_set(COL_STATE);
+ out("%s", sstate_name[s->state]);
}
- out("%-6d %-6d %s", s->rq, s->wq, odd_width_pad);
+ field_set(COL_RECVQ);
+ out("%-6d", s->rq);
+ field_set(COL_SENDQ);
+ out("%-6d", s->wq);
+ field_set(COL_ADDR);
}
static void sock_details_print(struct sockstat *s)
@@ -898,21 +1038,17 @@ static void sock_details_print(struct sockstat *s)
out(" fwmark:0x%x", s->mark);
}
-static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
- int port_len, const char *port, const char *ifname)
-{
- if (ifname) {
- out("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
- port_len, port);
- } else {
- out("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
- }
-}
-
static void sock_addr_print(const char *addr, char *delim, const char *port,
const char *ifname)
{
- sock_addr_print_width(addr_width, addr, delim, serv_width, port, ifname);
+ if (ifname)
+ out("%s" "%%" "%s%s", addr, ifname, delim);
+ else
+ out("%s%s", addr, delim);
+
+ field_next();
+ out("%s", port);
+ field_next();
}
static const char *print_ms_timer(unsigned int timeout)
@@ -1093,7 +1229,6 @@ static void inet_addr_print(const inet_prefix *a, int port,
{
char buf[1024];
const char *ap = buf;
- int est_len = addr_width;
const char *ifname = NULL;
if (a->family == AF_INET) {
@@ -1112,24 +1247,13 @@ static void inet_addr_print(const inet_prefix *a, int port,
"[%s]", ap);
ap = buf;
}
-
- est_len = strlen(ap);
- if (est_len <= addr_width)
- est_len = addr_width;
- else
- est_len = addr_width + ((est_len-addr_width+3)/4)*4;
}
}
- if (ifindex) {
- ifname = ll_index_to_name(ifindex);
- est_len -= strlen(ifname) + 1; /* +1 for percent char */
- if (est_len < 0)
- est_len = 0;
- }
+ if (ifindex)
+ ifname = ll_index_to_name(ifindex);
- sock_addr_print_width(est_len, ap, ":", serv_width, resolve_service(port),
- ifname);
+ sock_addr_print(ap, ":", resolve_service(port), ifname);
}
struct aafilter {
@@ -2166,7 +2290,6 @@ static int tcp_show_line(char *line, const struct filter *f, int family)
if (show_tcpinfo)
tcp_stats_print(&s);
- out("\n");
return 0;
}
@@ -2547,7 +2670,6 @@ static int inet_show_sock(struct nlmsghdr *nlh,
}
sctp_ino = s->ino;
- out("\n");
return 0;
}
@@ -3005,7 +3127,6 @@ static int dgram_show_line(char *line, const struct filter *f, int family)
if (show_details && opt[0])
out(" opt:\"%s\"", opt);
- out("\n");
return 0;
}
@@ -3184,7 +3305,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
- out("\n");
return 0;
}
@@ -3341,8 +3461,6 @@ static int unix_show(struct filter *f)
if (++cnt > MAX_UNIX_REMEMBER) {
while (list) {
unix_stats_print(list, f);
- out("\n");
-
unix_list_drop_first(&list);
}
cnt = 0;
@@ -3351,8 +3469,6 @@ static int unix_show(struct filter *f)
fclose(fp);
while (list) {
unix_stats_print(list, f);
- out("\n");
-
unix_list_drop_first(&list);
}
@@ -3527,7 +3643,6 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
fil++;
}
}
- out("\n");
return 0;
}
@@ -3570,7 +3685,6 @@ static int packet_show_line(char *buf, const struct filter *f, int fam)
if (packet_stats_print(&stat, f))
return 0;
- out("\n");
return 0;
}
@@ -3690,7 +3804,6 @@ static int netlink_show_one(struct filter *f,
if (show_details) {
out(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
}
- out("\n");
return 0;
}
@@ -3728,7 +3841,6 @@ static int netlink_show_sock(const struct sockaddr_nl *addr,
if (show_mem) {
out("\t");
print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
- out("\n");
}
return 0;
@@ -3818,8 +3930,6 @@ static void vsock_stats_print(struct sockstat *s, struct filter *f)
vsock_addr_print(&s->remote, s->rport);
proc_ctx_print(s);
-
- out("\n");
}
static int vsock_show_sock(const struct sockaddr_nl *addr,
@@ -4539,13 +4649,17 @@ int main(int argc, char *argv[])
if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp))
usage();
- netid_width = 0;
if (current_filter.dbs&(current_filter.dbs-1))
- netid_width = 5;
+ columns[COL_NETID].width = 6;
- state_width = 0;
if (current_filter.states&(current_filter.states-1))
- state_width = 10;
+ columns[COL_STATE].width = 10;
+
+ /* If Netid or State are hidden, no delimiter before next column */
+ if (!columns[COL_NETID].width)
+ columns[COL_STATE].width--;
+ else if (!columns[COL_STATE].width)
+ columns[COL_RECVQ].width--;
if (isatty(STDOUT_FILENO)) {
struct winsize w;
@@ -4556,49 +4670,38 @@ int main(int argc, char *argv[])
}
}
- addrp_width = screen_width;
- if (netid_width)
- addrp_width -= netid_width + 1;
- if (state_width)
- addrp_width -= state_width + 1;
- addrp_width -= 14;
+ addrp_width = screen_width -
+ columns[COL_NETID].width -
+ columns[COL_STATE].width -
+ columns[COL_RECVQ].width -
+ columns[COL_SENDQ].width;
if (addrp_width&1) {
- if (netid_width)
- netid_width++;
- else if (state_width)
- state_width++;
+ if (columns[COL_NETID].width)
+ columns[COL_NETID].width++;
+ else if (columns[COL_STATE].width)
+ columns[COL_STATE].width++;
else
- odd_width_pad = " ";
+ columns[COL_SENDQ].width++;
}
addrp_width /= 2;
- addrp_width--;
- serv_width = resolve_services ? 7 : 5;
+ columns[COL_SERV].width = resolve_services ? 8 : 6;
+ if (addrp_width < 15 + columns[COL_SERV].width)
+ addrp_width = 15 + columns[COL_SERV].width;
- if (addrp_width < 15+serv_width+1)
- addrp_width = 15+serv_width+1;
-
- addr_width = addrp_width - serv_width - 1;
-
- if (show_header) {
- if (netid_width)
- out("%-*s ", netid_width, "Netid");
- if (state_width)
- out("%-*s ", state_width, "State");
- out("%-6s %-6s %s", "Recv-Q", "Send-Q", odd_width_pad);
- }
+ columns[COL_ADDR].width = addrp_width - columns[COL_SERV].width;
/* Make enough space for the local/remote port field */
- addr_width -= 13;
- serv_width += 13;
+ columns[COL_ADDR].width -= 13;
+ columns[COL_SERV].width += 13;
- if (show_header) {
- out("%*s:%-*s %*s:%-*s\n",
- addr_width, "Local Address", serv_width, "Port",
- addr_width, "Peer Address", serv_width, "Port");
- }
+ columns[COL_RADDR].width = columns[COL_ADDR].width;
+ columns[COL_RSERV].width = columns[COL_SERV].width;
+
+ if (show_header)
+ print_header();
fflush(stdout);
@@ -4627,5 +4730,7 @@ int main(int argc, char *argv[])
if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy();
+ field_next();
+
return 0;
}
--
2.9.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox