* Re: [PATCHv2 net-next 04/12] sctp: implement make_datafrag for sctp_stream_interleave
From: Xin Long @ 2017-12-08 17:23 UTC (permalink / raw)
To: David Laight
Cc: Marcelo Ricardo Leitner, Neil Horman, network dev,
linux-sctp@vger.kernel.org, davem@davemloft.net
In-Reply-To: <27aff622f1574b329e18ba21922f6e7e@AcuMS.aculab.com>
On Sat, Dec 9, 2017 at 12:22 AM, David Laight <David.Laight@aculab.com> wrote:
> From: Xin Long
>> Sent: 08 December 2017 16:18
>>
> ...
>> >> Alternatively you could preform the dereference in two steps (i.e. declare an si
>> >> pointer on the stack and set it equal to asoc->stream.si, then deref
>> >> si->make_datafrag at call time. That will at least give the compiler an
>> >> opportunity to preload the first pointer.
>
> You want to save the function pointer itself.
>
> ...
>> Another small difference:
>> as you can see, comparing to (X), (Y) is using 0x28(%rsp) in the loop,
>> instead of %r13.
>>
>> So that's what I can see from the related generated code.
>> If 0x848(%r13) is not worse than 0x28(%rsp) for cpu, I think
>> asoc->stream.si->make_datafrag() is even better. No ?
>
> That code must have far too many life local variables.
> Otherwise there's be a caller saved register available.
>
Hi, David, Sorry, I'm not sure we're worrying about the cpu cost or
codes style now ?
For cpu cost, I think 0x848(%r13) operation must be better than the
generated code of if-else.
For the codes style, comparing to the if-else, I think this one is
more readable. (ignore extendible stuff first, as probably no more
new type of data chunk).
^ permalink raw reply
* Re: [PATCH v4.1] phylib: Add device reset GPIO support
From: Sergei Shtylyov @ 2017-12-08 17:20 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Geert Uytterhoeven, David S . Miller, Andrew Lunn,
Florian Fainelli, Simon Horman, Magnus Damm, Rob Herring,
Mark Rutland, Nicolas Ferre, Richard Leitner,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Renesas,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMuHMdWv6CiCihjFHn-k2=3PC+-bRQaKMsZcsx51MYpynTLO4A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hello!
On 12/08/2017 12:53 PM, Geert Uytterhoeven wrote:
>> On 12/04/2017 03:35 PM, Geert Uytterhoeven wrote:
>>> From: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
>>> The PHY devices sometimes do have their reset signal (maybe even power
>>> supply?) tied to some GPIO and sometimes it also does happen that a boot
>>> loader does not leave it deasserted. So far this issue has been attacked
>>> from (as I believe) a wrong angle: by teaching the MAC driver to
>>> manipulate
>>> the GPIO in question; that solution, when applied to the device trees, led
>>> to adding the PHY reset GPIO properties to the MAC device node, with one
>>> exception: Cadence MACB driver which could handle the "reset-gpios" prop
>>> in a PHY device subnode. I believe that the correct approach is to teach
>>> the 'phylib' to get the MDIO device reset GPIO from the device tree node
>>> corresponding to this device -- which this patch is doing...
>>>
>>> Note that I had to modify the AT803x PHY driver as it would stop working
>>> otherwise -- it made use of the reset GPIO for its own purposes...
>>>
>>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org>
>>> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>> [geert: Propagate actual errors from fwnode_get_named_gpiod()]
>>> [geert: Avoid destroying initial setup]
>>> [geert: Consolidate GPIO descriptor acquiring code]
>>> Signed-off-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>
>>
>> [...]
>>>
>>> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
>>> index 2df7b62c1a36811e..8f8b7747c54bc478 100644
>>> --- a/drivers/net/phy/mdio_bus.c
>>> +++ b/drivers/net/phy/mdio_bus.c
>>
>> [...]
>>>
>>> @@ -48,9 +49,26 @@
>>> int mdiobus_register_device(struct mdio_device *mdiodev)
>>> {
>>> + struct gpio_desc *gpiod = NULL;
>>> +
>>> if (mdiodev->bus->mdio_map[mdiodev->addr])
>>> return -EBUSY;
>>> + /* Deassert the optional reset signal */
>>
>>
>> Umm, but why deassert it here for such a short time?
>
> That's a consequence of moving it from drivers/of/of_mdio.c to here.
Well, you shouldn't do code moves without some thinking. ;-)
> Not that it was deasserted that much longer in drivers/of/of_mdio.c, though...
There it had a reason, here I'm not seeing one. Perhaps using GPIOD_ASIS
(or GPIOD_OUT_HIGH) instead of GPIOD_OUT_LOW and dropping
mdio_device_reset(mdiodev, 1) afterwards would make more sense here?
> Gr{oetje,eeting}s,
>
> Geert
MBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH iproute2 net-next 4/4] ss: Implement automatic column width calculation
From: Stefano Brivio @ 2017-12-08 17:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1512750298.git.sbrivio@redhat.com>
Group fitting fields into lines and space them equally using the
remaining screen width for each line. If columns don't fit on
one line, break them into the least possible amount of lines and
keep them aligned across lines.
This is done by:
- recording the length of the longest item in each column during
formatting and buffering (which was added in the previous patch)
- fitting as many fields as possible on each line of output
- distributing the remaining padding space equally between the
columns
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
misc/ss.c | 188 +++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 120 insertions(+), 68 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index abc0da7fa8fe..44ad9587b62c 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -128,19 +128,21 @@ struct column {
const enum col_align align;
const char *header;
const char *ldelim;
- int width; /* Including delimiter. -1: fit to content, 0: hide */
+ int disabled;
+ int width; /* Calculated, including additional layout spacing */
+ int max_len; /* Measured maximum field length in this column */
};
static struct column columns[] = {
- { ALIGN_LEFT, "Netid", "", 0 },
- { ALIGN_LEFT, "State", " ", 0 },
- { ALIGN_LEFT, "Recv-Q", " ", 7 },
- { ALIGN_LEFT, "Send-Q", " ", 7 },
- { ALIGN_RIGHT, "Local Address:", " ", 0 },
- { ALIGN_LEFT, "Port", "", 0 },
- { ALIGN_RIGHT, "Peer Address:", " ", 0 },
- { ALIGN_LEFT, "Port", "", 0 },
- { ALIGN_LEFT, "", "", -1 },
+ { ALIGN_LEFT, "Netid", "", 0, 0, 0 },
+ { ALIGN_LEFT, "State", " ", 0, 0, 0 },
+ { ALIGN_LEFT, "Recv-Q", " ", 0, 0, 0 },
+ { ALIGN_LEFT, "Send-Q", " ", 0, 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, "", "", 0, 0, 0 },
};
static struct column *current_field = columns;
@@ -959,7 +961,7 @@ static void out(const char *fmt, ...)
char *pos;
int len;
- if (!f->width)
+ if (f->disabled)
return;
if (!buffer.head)
@@ -982,7 +984,7 @@ static int print_left_spacing(struct column *f, int stored, int printed)
{
int s;
- if (f->width < 0 || f->align == ALIGN_LEFT)
+ if (!f->width || f->align == ALIGN_LEFT)
return 0;
s = f->width - stored - printed;
@@ -1000,7 +1002,7 @@ static void print_right_spacing(struct column *f, int printed)
{
int s;
- if (f->width < 0 || f->align == ALIGN_RIGHT)
+ if (!f->width || f->align == ALIGN_RIGHT)
return;
s = f->width - printed;
@@ -1017,9 +1019,12 @@ static void field_flush(struct column *f)
struct buf_chunk *chunk = buffer.tail;
unsigned int pad = buffer.cur->len % 2;
- if (!f->width)
+ if (f->disabled)
return;
+ if (buffer.cur->len > f->max_len)
+ f->max_len = buffer.cur->len;
+
/* We need a new chunk if we can't store the next length descriptor.
* Mind the gap between end of previous token and next aligned position
* for length descriptor.
@@ -1062,7 +1067,7 @@ static void field_set(enum col_id id)
static void print_header(void)
{
while (!field_is_last(current_field)) {
- if (current_field->width)
+ if (!current_field->disabled)
out(current_field->header);
field_next();
}
@@ -1095,16 +1100,106 @@ static void buf_free_all(void)
buffer.head = NULL;
}
+/* Calculate column width from contents length. If columns don't fit on one
+ * line, break them into the least possible amount of lines and keep them
+ * aligned across lines. Available screen space is equally spread between fields
+ * as additional spacing.
+ */
+static void render_calc_width(int screen_width)
+{
+ int first, len = 0, linecols = 0;
+ struct column *c, *eol = columns - 1;
+
+ /* First pass: set width for each column to measured content length */
+ for (first = 1, c = columns; c - columns < COL_MAX; c++) {
+ if (c->disabled)
+ continue;
+
+ if (!first && c->max_len)
+ c->width = c->max_len + strlen(c->ldelim);
+ else
+ c->width = c->max_len;
+
+ /* But don't exceed screen size. If we exceed the screen size
+ * for even a single field, it will just start on a line of its
+ * own and then naturally wrap.
+ */
+ c->width = min(c->width, screen_width);
+
+ if (c->width)
+ first = 0;
+ }
+
+ /* Second pass: find out newlines and distribute available spacing */
+ for (c = columns; c - columns < COL_MAX; c++) {
+ int pad, spacing, rem, last;
+ struct column *tmp;
+
+ if (!c->width)
+ continue;
+
+ linecols++;
+ len += c->width;
+
+ for (last = 1, tmp = c + 1; tmp - columns < COL_MAX; tmp++) {
+ if (tmp->width) {
+ last = 0;
+ break;
+ }
+ }
+
+ if (!last && len < screen_width) {
+ /* Columns fit on screen so far, nothing to do yet */
+ continue;
+ }
+
+ if (len == screen_width) {
+ /* Exact fit, just start with new line */
+ goto newline;
+ }
+
+ if (len > screen_width) {
+ /* Screen width exceeded: go back one column */
+ len -= c->width;
+ c--;
+ linecols--;
+ }
+
+ /* Distribute remaining space to columns on this line */
+ pad = screen_width - len;
+ spacing = pad / linecols;
+ rem = pad % linecols;
+ for (tmp = c; tmp > eol; tmp--) {
+ if (!tmp->width)
+ continue;
+
+ tmp->width += spacing;
+ if (rem) {
+ tmp->width++;
+ rem--;
+ }
+ }
+
+newline:
+ /* Line break: reset line counters, mark end-of-line */
+ eol = c;
+ len = 0;
+ linecols = 0;
+ }
+}
+
/* Render buffered output with spacing and delimiters, then free up buffers */
-static void render(void)
+static void render(int screen_width)
{
struct buf_token *token = (struct buf_token *)buffer.head->data;
- int printed, line_started = 0, need_newline = 0;
+ int printed, line_started = 0;
struct column *f;
/* Ensure end alignment of last token, it wasn't necessarily flushed */
buffer.tail->end += buffer.cur->len % 2;
+ render_calc_width(screen_width);
+
/* Rewind and replay */
buffer.tail = buffer.head;
@@ -1124,23 +1219,16 @@ static void render(void)
printed += fwrite(token->data, 1, token->len, stdout);
print_right_spacing(f, printed);
- /* Variable field size or overflow, won't align to screen */
- if (printed > f->width)
- need_newline = 1;
-
/* Go to next non-empty field, deal with end-of-line */
do {
if (field_is_last(f)) {
- if (need_newline) {
- printf("\n");
- need_newline = 0;
- }
+ printf("\n");
f = columns;
line_started = 0;
} else {
f++;
}
- } while (!f->width);
+ } while (f->disabled);
token = buf_token_next(token);
}
@@ -4531,7 +4619,7 @@ int main(int argc, char *argv[])
FILE *filter_fp = NULL;
int ch;
int state_filter = 0;
- int addrp_width, screen_width = 80;
+ int screen_width = 80;
while ((ch = getopt_long(argc, argv,
"dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
@@ -4827,17 +4915,11 @@ int main(int argc, char *argv[])
if (ssfilter_parse(¤t_filter.f, argc, argv, filter_fp))
usage();
- if (current_filter.dbs&(current_filter.dbs-1))
- columns[COL_NETID].width = 6;
-
- if (current_filter.states&(current_filter.states-1))
- columns[COL_STATE].width = 10;
+ if (!(current_filter.dbs & (current_filter.dbs - 1)))
+ columns[COL_NETID].disabled = 1;
- /* 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 (!(current_filter.states & (current_filter.states - 1)))
+ columns[COL_STATE].disabled = 1;
if (isatty(STDOUT_FILENO)) {
struct winsize w;
@@ -4848,36 +4930,6 @@ int main(int argc, char *argv[])
}
}
- 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 (columns[COL_NETID].width)
- columns[COL_NETID].width++;
- else if (columns[COL_STATE].width)
- columns[COL_STATE].width++;
- else
- columns[COL_SENDQ].width++;
- }
-
- addrp_width /= 2;
-
- columns[COL_SERV].width = resolve_services ? 8 : 6;
- if (addrp_width < 15 + columns[COL_SERV].width)
- addrp_width = 15 + columns[COL_SERV].width;
-
- columns[COL_ADDR].width = addrp_width - columns[COL_SERV].width;
-
- /* Make enough space for the local/remote port field */
- columns[COL_ADDR].width -= 13;
- columns[COL_SERV].width += 13;
-
- columns[COL_RADDR].width = columns[COL_ADDR].width;
- columns[COL_RSERV].width = columns[COL_SERV].width;
-
if (show_header)
print_header();
@@ -4908,7 +4960,7 @@ int main(int argc, char *argv[])
if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy();
- render();
+ render(screen_width);
return 0;
}
--
2.9.4
^ permalink raw reply related
* [PATCH iproute2 net-next 3/4] ss: Buffer raw fields first, then render them as a table
From: Stefano Brivio @ 2017-12-08 17:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1512750298.git.sbrivio@redhat.com>
This allows us to measure the maximum field length for each
column before printing fields and will permit us to apply
optimal field spacing and distribution. Structure of the output
buffer with chunked allocation is described in comments.
Output is still unchanged, original spacing is used.
Running over one million sockets with -tul options by simply
modifying main() to loop 50,000 times over the *_show()
functions, buffering the whole output and rendering it at the
end, with 10 UDP sockets, 10 TCP sockets, while throwing
output away, doesn't show significant changes in execution time
on my laptop with an Intel i7-6600U CPU:
- before this patch:
$ time ./ss -tul > /dev/null
real 0m29.899s
user 0m2.017s
sys 0m27.801s
- after this patch:
$ time ./ss -tul > /dev/null
real 0m29.827s
user 0m1.942s
sys 0m27.812s
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
---
misc/ss.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 225 insertions(+), 46 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index 9dbcfd514d48..abc0da7fa8fe 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -47,6 +47,8 @@
#include <linux/vm_sockets_diag.h>
#define MAGIC_SEQ 123456
+#define BUF_CHUNK (1024 * 1024)
+#define LEN_ALIGN(x) (((x) + 1) & ~1)
#define DIAG_REQUEST(_req, _r) \
struct { \
@@ -127,24 +129,45 @@ struct column {
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 },
+ { ALIGN_LEFT, "Netid", "", 0 },
+ { ALIGN_LEFT, "State", " ", 0 },
+ { ALIGN_LEFT, "Recv-Q", " ", 7 },
+ { ALIGN_LEFT, "Send-Q", " ", 7 },
+ { ALIGN_RIGHT, "Local Address:", " ", 0 },
+ { ALIGN_LEFT, "Port", "", 0 },
+ { ALIGN_RIGHT, "Peer Address:", " ", 0 },
+ { ALIGN_LEFT, "Port", "", 0 },
+ { ALIGN_LEFT, "", "", -1 },
};
static struct column *current_field = columns;
-static char field_buf[BUFSIZ];
+
+/* Output buffer: chained chunks of BUF_CHUNK bytes. Each field is written to
+ * the buffer as a variable size token. A token consists of a 16 bits length
+ * field, followed by a string which is not NULL-terminated.
+ *
+ * A new chunk is allocated and linked when the current chunk doesn't have
+ * enough room to store the current token as a whole.
+ */
+struct buf_chunk {
+ struct buf_chunk *next; /* Next chained chunk */
+ char *end; /* Current end of content */
+ char data[0];
+};
+
+struct buf_token {
+ uint16_t len; /* Data length, excluding length descriptor */
+ char data[0];
+};
+
+static struct {
+ struct buf_token *cur; /* Position of current token in chunk */
+ struct buf_chunk *head; /* First chunk */
+ struct buf_chunk *tail; /* Current chunk */
+} buffer;
static const char *TCP_PROTO = "tcp";
static const char *SCTP_PROTO = "sctp";
@@ -860,25 +883,109 @@ static const char *vsock_netid_name(int type)
}
}
+/* Allocate and initialize a new buffer chunk */
+static struct buf_chunk *buf_chunk_new(void)
+{
+ struct buf_chunk *new = malloc(BUF_CHUNK);
+
+ if (!new)
+ abort();
+
+ new->next = NULL;
+
+ /* This is also the last block */
+ buffer.tail = new;
+
+ /* Next token will be stored at the beginning of chunk data area, and
+ * its initial length is zero.
+ */
+ buffer.cur = (struct buf_token *)new->data;
+ buffer.cur->len = 0;
+
+ new->end = buffer.cur->data;
+
+ return new;
+}
+
+/* Return available tail room in given chunk */
+static int buf_chunk_avail(struct buf_chunk *chunk)
+{
+ return BUF_CHUNK - offsetof(struct buf_chunk, data) -
+ (chunk->end - chunk->data);
+}
+
+/* Update end pointer and token length, link new chunk if we hit the end of the
+ * current one. Return -EAGAIN if we got a new chunk, caller has to print again.
+ */
+static int buf_update(int len)
+{
+ struct buf_chunk *chunk = buffer.tail;
+ struct buf_token *t = buffer.cur;
+
+ /* Claim success if new content fits in the current chunk, and anyway
+ * if this is the first token in the chunk: in the latter case,
+ * allocating a new chunk won't help, so we'll just cut the output.
+ */
+ if ((len < buf_chunk_avail(chunk) && len != -1 /* glibc < 2.0.6 */) ||
+ t == (struct buf_token *)chunk->data) {
+ len = min(len, buf_chunk_avail(chunk));
+
+ /* Total field length can't exceed 2^16 bytes, cut as needed */
+ len = min(len, USHRT_MAX - t->len);
+
+ chunk->end += len;
+ t->len += len;
+ return 0;
+ }
+
+ /* Content truncated, time to allocate more */
+ chunk->next = buf_chunk_new();
+
+ /* Copy current token over to new chunk, including length descriptor */
+ memcpy(chunk->next->data, t, sizeof(t->len) + t->len);
+ chunk->next->end += t->len;
+
+ /* Discard partially written field in old chunk */
+ chunk->end -= t->len + sizeof(t->len);
+
+ return -EAGAIN;
+}
+
+/* Append content to buffer as part of the current field */
static void out(const char *fmt, ...)
{
struct column *f = current_field;
va_list args;
+ char *pos;
+ int len;
+
+ if (!f->width)
+ return;
+
+ if (!buffer.head)
+ buffer.head = buf_chunk_new();
+
+again: /* Append to buffer: if we have a new chunk, print again */
+ pos = buffer.cur->data + buffer.cur->len;
va_start(args, fmt);
- f->stored += vsnprintf(field_buf + f->stored, BUFSIZ - f->stored,
- fmt, args);
+
+ /* Limit to tail room. If we hit the limit, buf_update() will tell us */
+ len = vsnprintf(pos, buf_chunk_avail(buffer.tail), fmt, args);
va_end(args);
+
+ if (buf_update(len))
+ goto again;
}
-static int print_left_spacing(struct column *f)
+static int print_left_spacing(struct column *f, int stored, int printed)
{
int s;
if (f->width < 0 || f->align == ALIGN_LEFT)
return 0;
- s = f->width - f->stored - f->printed;
+ s = f->width - stored - printed;
if (f->align == ALIGN_CENTER)
/* If count of total spacing is odd, shift right by one */
s = (s + 1) / 2;
@@ -889,14 +996,14 @@ static int print_left_spacing(struct column *f)
return 0;
}
-static void print_right_spacing(struct column *f)
+static void print_right_spacing(struct column *f, int printed)
{
int s;
if (f->width < 0 || f->align == ALIGN_RIGHT)
return;
- s = f->width - f->printed;
+ s = f->width - printed;
if (f->align == ALIGN_CENTER)
s /= 2;
@@ -904,35 +1011,29 @@ static void print_right_spacing(struct column *f)
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 */
+/* Done with field: update buffer pointer, start new token after current one */
static void field_flush(struct column *f)
{
+ struct buf_chunk *chunk = buffer.tail;
+ unsigned int pad = buffer.cur->len % 2;
+
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);
+ /* We need a new chunk if we can't store the next length descriptor.
+ * Mind the gap between end of previous token and next aligned position
+ * for length descriptor.
+ */
+ if (buf_chunk_avail(chunk) - pad < sizeof(buffer.cur->len)) {
+ chunk->end += pad;
+ chunk->next = buf_chunk_new();
+ return;
+ }
- *field_buf = 0;
- f->printed = 0;
- f->stored = 0;
+ buffer.cur = (struct buf_token *)(buffer.cur->data +
+ LEN_ALIGN(buffer.cur->len));
+ buffer.cur->len = 0;
+ buffer.tail->end = buffer.cur->data;
}
static int field_is_last(struct column *f)
@@ -944,12 +1045,10 @@ static void field_next(void)
{
field_flush(current_field);
- if (field_is_last(current_field)) {
- printf("\n");
+ if (field_is_last(current_field))
current_field = columns;
- } else {
+ else
current_field++;
- }
}
/* Walk through fields and flush them until we reach the desired one */
@@ -969,6 +1068,86 @@ static void print_header(void)
}
}
+/* Get the next available token in the buffer starting from the current token */
+static struct buf_token *buf_token_next(struct buf_token *cur)
+{
+ struct buf_chunk *chunk = buffer.tail;
+
+ /* If we reached the end of chunk contents, get token from next chunk */
+ if (cur->data + LEN_ALIGN(cur->len) == chunk->end) {
+ buffer.tail = chunk = chunk->next;
+ return chunk ? (struct buf_token *)chunk->data : NULL;
+ }
+
+ return (struct buf_token *)(cur->data + LEN_ALIGN(cur->len));
+}
+
+/* Free up all allocated buffer chunks */
+static void buf_free_all(void)
+{
+ struct buf_chunk *tmp;
+
+ for (buffer.tail = buffer.head; buffer.tail; ) {
+ tmp = buffer.tail;
+ buffer.tail = buffer.tail->next;
+ free(tmp);
+ }
+ buffer.head = NULL;
+}
+
+/* Render buffered output with spacing and delimiters, then free up buffers */
+static void render(void)
+{
+ struct buf_token *token = (struct buf_token *)buffer.head->data;
+ int printed, line_started = 0, need_newline = 0;
+ struct column *f;
+
+ /* Ensure end alignment of last token, it wasn't necessarily flushed */
+ buffer.tail->end += buffer.cur->len % 2;
+
+ /* Rewind and replay */
+ buffer.tail = buffer.head;
+
+ f = columns;
+ while (!f->width)
+ f++;
+
+ while (token) {
+ /* Print left delimiter only if we already started a line */
+ if (line_started++)
+ printed = printf("%s", current_field->ldelim);
+ else
+ printed = 0;
+
+ /* Print field content from token data with spacing */
+ printed += print_left_spacing(f, token->len, printed);
+ printed += fwrite(token->data, 1, token->len, stdout);
+ print_right_spacing(f, printed);
+
+ /* Variable field size or overflow, won't align to screen */
+ if (printed > f->width)
+ need_newline = 1;
+
+ /* Go to next non-empty field, deal with end-of-line */
+ do {
+ if (field_is_last(f)) {
+ if (need_newline) {
+ printf("\n");
+ need_newline = 0;
+ }
+ f = columns;
+ line_started = 0;
+ } else {
+ f++;
+ }
+ } while (!f->width);
+
+ token = buf_token_next(token);
+ }
+
+ buf_free_all();
+}
+
static void sock_state_print(struct sockstat *s)
{
const char *sock_name;
@@ -4729,7 +4908,7 @@ int main(int argc, char *argv[])
if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy();
- field_next();
+ render();
return 0;
}
--
2.9.4
^ permalink raw reply related
* [PATCH iproute2 net-next 2/4] ss: Introduce columns lightweight abstraction
From: Stefano Brivio @ 2017-12-08 17:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1512750298.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>
---
misc/ss.c | 289 ++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 198 insertions(+), 91 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index 72e117ca9405..9dbcfd514d48 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";
@@ -825,13 +862,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;
@@ -871,18 +1008,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)
@@ -897,21 +1037,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)
@@ -1092,7 +1228,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) {
@@ -1111,24 +1246,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 {
@@ -2163,7 +2287,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;
}
@@ -2544,7 +2667,6 @@ static int inet_show_sock(struct nlmsghdr *nlh,
}
sctp_ino = s->ino;
- out("\n");
return 0;
}
@@ -3002,7 +3124,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;
}
@@ -3181,7 +3302,6 @@ static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
}
}
- out("\n");
return 0;
}
@@ -3338,8 +3458,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;
@@ -3348,8 +3466,6 @@ static int unix_show(struct filter *f)
fclose(fp);
while (list) {
unix_stats_print(list, f);
- out("\n");
-
unix_list_drop_first(&list);
}
@@ -3524,7 +3640,6 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
fil++;
}
}
- out("\n");
return 0;
}
@@ -3567,7 +3682,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;
}
@@ -3687,7 +3801,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;
}
@@ -3725,7 +3838,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;
@@ -4536,13 +4648,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;
@@ -4553,49 +4669,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;
- if (addrp_width < 15+serv_width+1)
- addrp_width = 15+serv_width+1;
+ columns[COL_SERV].width = resolve_services ? 8 : 6;
+ if (addrp_width < 15 + columns[COL_SERV].width)
+ addrp_width = 15 + columns[COL_SERV].width;
- 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);
@@ -4624,5 +4729,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
* [PATCH iproute2 net-next 1/4] ss: Replace printf() calls for "main" output by calls to helper
From: Stefano Brivio @ 2017-12-08 17:07 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Sabrina Dubroca
In-Reply-To: <cover.1512750298.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>
---
misc/ss.c | 397 ++++++++++++++++++++++++++++++++------------------------------
1 file changed, 204 insertions(+), 193 deletions(-)
diff --git a/misc/ss.c b/misc/ss.c
index b5099d1e0e66..72e117ca9405 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"
@@ -822,6 +823,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;
@@ -862,39 +872,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);
}
}
@@ -1792,12 +1802,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);
}
}
@@ -1877,51 +1887,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)
@@ -1929,65 +1939,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) {
@@ -1997,71 +2007,70 @@ 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->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)
@@ -2078,18 +2087,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)
@@ -2148,13 +2157,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;
}
@@ -2197,44 +2206,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, " ,");
}
@@ -2379,10 +2388,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++);
}
}
@@ -2417,18 +2426,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;
@@ -2515,18 +2524,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
@@ -2534,7 +2544,7 @@ static int inet_show_sock(struct nlmsghdr *nlh,
}
sctp_ino = s->ino;
- printf("\n");
+ out("\n");
return 0;
}
@@ -2990,9 +3000,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;
}
@@ -3167,10 +3177,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;
}
@@ -3327,7 +3338,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);
}
@@ -3337,7 +3348,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);
}
@@ -3383,12 +3394,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,
@@ -3446,56 +3457,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(")");
}
}
@@ -3505,15 +3516,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;
}
@@ -3556,7 +3567,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;
}
@@ -3669,14 +3680,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;
}
@@ -3712,9 +3723,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;
@@ -3805,7 +3816,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,
@@ -4570,10 +4581,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 */
@@ -4581,9 +4592,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 0/4] Abstract columns, properly space and wrap fields
From: Stefano Brivio @ 2017-12-08 17:07 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.
[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
misc/ss.c | 893 +++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 621 insertions(+), 272 deletions(-)
--
2.9.4
^ permalink raw reply
* [PATCH] bnxt_en: Fix sources of spurious netpoll warnings
From: Calvin Owens @ 2017-12-08 17:05 UTC (permalink / raw)
To: Michael Chan; +Cc: netdev, linux-kernel, kernel-team, Calvin Owens
After applying 2270bc5da3497945 ("bnxt_en: Fix netpoll handling") and
903649e718f80da2 ("bnxt_en: Improve -ENOMEM logic in NAPI poll loop."),
we still see the following WARN fire:
------------[ cut here ]------------
WARNING: CPU: 0 PID: 1875170 at net/core/netpoll.c:165 netpoll_poll_dev+0x15a/0x160
bnxt_poll+0x0/0xd0 exceeded budget in poll
<snip>
Call Trace:
[<ffffffff814be5cd>] dump_stack+0x4d/0x70
[<ffffffff8107e013>] __warn+0xd3/0xf0
[<ffffffff8107e07f>] warn_slowpath_fmt+0x4f/0x60
[<ffffffff8179519a>] netpoll_poll_dev+0x15a/0x160
[<ffffffff81795f38>] netpoll_send_skb_on_dev+0x168/0x250
[<ffffffff817962fc>] netpoll_send_udp+0x2dc/0x440
[<ffffffff815fa9be>] write_ext_msg+0x20e/0x250
[<ffffffff810c8125>] call_console_drivers.constprop.23+0xa5/0x110
[<ffffffff810c9549>] console_unlock+0x339/0x5b0
[<ffffffff810c9a88>] vprintk_emit+0x2c8/0x450
[<ffffffff810c9d5f>] vprintk_default+0x1f/0x30
[<ffffffff81173df5>] printk+0x48/0x50
[<ffffffffa0197713>] edac_raw_mc_handle_error+0x563/0x5c0 [edac_core]
[<ffffffffa0197b9b>] edac_mc_handle_error+0x42b/0x6e0 [edac_core]
[<ffffffffa01c3a60>] sbridge_mce_output_error+0x410/0x10d0 [sb_edac]
[<ffffffffa01c47cc>] sbridge_check_error+0xac/0x130 [sb_edac]
[<ffffffffa0197f3c>] edac_mc_workq_function+0x3c/0x90 [edac_core]
[<ffffffff81095f8b>] process_one_work+0x19b/0x480
[<ffffffff810967ca>] worker_thread+0x6a/0x520
[<ffffffff8109c7c4>] kthread+0xe4/0x100
[<ffffffff81884c52>] ret_from_fork+0x22/0x40
This happens because we increment rx_pkts on -ENOMEM and -EIO, resulting
in rx_pkts > 0. Fix this by only bumping rx_pkts if we were actually
given a non-zero budget.
Signed-off-by: Calvin Owens <calvinowens@fb.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index c5c38d4..f38160f 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -1883,7 +1883,7 @@ static int bnxt_poll_work(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
* here forever if we consistently cannot allocate
* buffers.
*/
- else if (rc == -ENOMEM)
+ else if (rc == -ENOMEM && budget)
rx_pkts++;
else if (rc == -EBUSY) /* partial completion */
break;
@@ -1969,7 +1969,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget)
cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR);
rc = bnxt_rx_pkt(bp, bnapi, &raw_cons, &event);
- if (likely(rc == -EIO))
+ if (likely(rc == -EIO) && budget)
rx_pkts++;
else if (rc == -EBUSY) /* partial completion */
break;
--
2.9.5
^ permalink raw reply related
* RE: [PATCH net-next v2 5/5] qede: Use NETIF_F_GRO_HW.
From: Chopra, Manish @ 2017-12-08 17:02 UTC (permalink / raw)
To: Michael Chan, davem@davemloft.net
Cc: netdev@vger.kernel.org, andrew.gospodarek@broadcom.com,
Elior, Ariel, Dept-Eng Everest Linux L2
In-Reply-To: <1512633815-25037-6-git-send-email-michael.chan@broadcom.com>
> -----Original Message-----
> From: Michael Chan [mailto:michael.chan@broadcom.com]
> Sent: Thursday, December 07, 2017 1:34 PM
> To: davem@davemloft.net
> Cc: netdev@vger.kernel.org; andrew.gospodarek@broadcom.com; Elior, Ariel
> <Ariel.Elior@cavium.com>; Dept-Eng Everest Linux L2 <Dept-
> EngEverestLinuxL2@cavium.com>
> Subject: [PATCH net-next v2 5/5] qede: Use NETIF_F_GRO_HW.
>
> Advertise NETIF_F_GRO_HW and set edev->gro_disable according to the feature
> flag. Add qede_fix_features() to drop NETIF_F_GRO_HW if XDP is running or
> MTU does not support GRO_HW. qede_change_mtu() also checks and disables
> GRO_HW if MTU is not supported.
>
> Cc: Ariel Elior <Ariel.Elior@cavium.com>
> Cc: everest-linux-l2@cavium.com
> Signed-off-by: Michael Chan <michael.chan@broadcom.com>
> ---
> drivers/net/ethernet/qlogic/qede/qede.h | 2 ++
> drivers/net/ethernet/qlogic/qede/qede_ethtool.c | 3 +++
> drivers/net/ethernet/qlogic/qede/qede_filter.c | 20 +++++++++++++-------
> drivers/net/ethernet/qlogic/qede/qede_main.c | 17 ++++++-----------
> 4 files changed, 24 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/net/ethernet/qlogic/qede/qede.h
> b/drivers/net/ethernet/qlogic/qede/qede.h
> index a3a70ad..8a33651 100644
> --- a/drivers/net/ethernet/qlogic/qede/qede.h
> +++ b/drivers/net/ethernet/qlogic/qede/qede.h
> @@ -494,6 +494,8 @@ int qede_free_tx_pkt(struct qede_dev *edev, void
> qede_vlan_mark_nonconfigured(struct qede_dev *edev); int
> qede_configure_vlan_filters(struct qede_dev *edev);
>
> +netdev_features_t qede_fix_features(struct net_device *dev,
> + netdev_features_t features);
> int qede_set_features(struct net_device *dev, netdev_features_t features);
> void qede_set_rx_mode(struct net_device *ndev); void
> qede_config_rx_mode(struct net_device *ndev); diff --git
> a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
> b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
> index dae7412..4ca3847 100644
> --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
> +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
> @@ -940,6 +940,9 @@ int qede_change_mtu(struct net_device *ndev, int
> new_mtu)
> DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
> "Configuring MTU size of %d\n", new_mtu);
>
> + if (new_mtu > PAGE_SIZE)
> + ndev->features &= ~NETIF_F_GRO_HW;
> +
> /* Set the mtu field and re-start the interface if needed */
> args.u.mtu = new_mtu;
> args.func = &qede_update_mtu;
> diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c
> b/drivers/net/ethernet/qlogic/qede/qede_filter.c
> index c1a0708..2de947e 100644
> --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c
> +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c
> @@ -895,19 +895,25 @@ static void qede_set_features_reload(struct
> qede_dev *edev,
> edev->ndev->features = args->u.features; }
>
> +netdev_features_t qede_fix_features(struct net_device *dev,
> + netdev_features_t features)
> +{
> + struct qede_dev *edev = netdev_priv(dev);
> +
> + if (edev->xdp_prog || edev->ndev->mtu > PAGE_SIZE)
> + features &= ~NETIF_F_GRO_HW;
> +
> + return features;
> +}
> +
> int qede_set_features(struct net_device *dev, netdev_features_t features) {
> struct qede_dev *edev = netdev_priv(dev);
> netdev_features_t changes = features ^ dev->features;
> bool need_reload = false;
>
> - /* No action needed if hardware GRO is disabled during driver load */
> - if (changes & NETIF_F_GRO) {
> - if (dev->features & NETIF_F_GRO)
> - need_reload = !edev->gro_disable;
> - else
> - need_reload = edev->gro_disable;
> - }
> + if (changes & NETIF_F_GRO_HW)
> + need_reload = true;
>
> if (need_reload) {
> struct qede_reload_args args;
> diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c
> b/drivers/net/ethernet/qlogic/qede/qede_main.c
> index 57332b3..90d79ae 100644
> --- a/drivers/net/ethernet/qlogic/qede/qede_main.c
> +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
> @@ -545,6 +545,7 @@ static int qede_ioctl(struct net_device *dev, struct ifreq
> *ifr, int cmd) #endif
> .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
> .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
> + .ndo_fix_features = qede_fix_features,
> .ndo_set_features = qede_set_features,
> .ndo_get_stats64 = qede_get_stats64,
> #ifdef CONFIG_QED_SRIOV
> @@ -572,6 +573,7 @@ static int qede_ioctl(struct net_device *dev, struct ifreq
> *ifr, int cmd)
> .ndo_change_mtu = qede_change_mtu,
> .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
> .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
> + .ndo_fix_features = qede_fix_features,
> .ndo_set_features = qede_set_features,
> .ndo_get_stats64 = qede_get_stats64,
> .ndo_udp_tunnel_add = qede_udp_tunnel_add, @@ -589,6 +591,7 @@
> static int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> .ndo_change_mtu = qede_change_mtu,
> .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
> .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
> + .ndo_fix_features = qede_fix_features,
> .ndo_set_features = qede_set_features,
> .ndo_get_stats64 = qede_get_stats64,
> .ndo_udp_tunnel_add = qede_udp_tunnel_add, @@ -676,7 +679,7 @@
> static void qede_init_ndev(struct qede_dev *edev)
> ndev->priv_flags |= IFF_UNICAST_FLT;
>
> /* user-changeble features */
> - hw_features = NETIF_F_GRO | NETIF_F_SG |
> + hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG |
> NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> NETIF_F_TSO | NETIF_F_TSO6;
>
> @@ -1228,18 +1231,9 @@ static int qede_alloc_sge_mem(struct qede_dev
> *edev, struct qede_rx_queue *rxq)
> dma_addr_t mapping;
> int i;
>
> - /* Don't perform FW aggregations in case of XDP */
> - if (edev->xdp_prog)
> - edev->gro_disable = 1;
> -
> if (edev->gro_disable)
> return 0;
>
> - if (edev->ndev->mtu > PAGE_SIZE) {
> - edev->gro_disable = 1;
> - return 0;
> - }
> -
> for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) {
> struct qede_agg_info *tpa_info = &rxq->tpa_info[i];
> struct sw_rx_data *replace_buf = &tpa_info->buffer; @@ -
> 1269,6 +1263,7 @@ static int qede_alloc_sge_mem(struct qede_dev *edev,
> struct qede_rx_queue *rxq)
> err:
> qede_free_sge_mem(edev, rxq);
> edev->gro_disable = 1;
> + edev->ndev->features &= ~NETIF_F_GRO_HW;
> return -ENOMEM;
> }
>
> @@ -1511,7 +1506,7 @@ static void qede_init_fp(struct qede_dev *edev)
> edev->ndev->name, queue_id);
> }
>
> - edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO);
> + edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW);
> }
>
> static int qede_set_real_num_queues(struct qede_dev *edev)
> --
> 1.8.3.1
Hi Michael, we have currently tested changes for qede driver and that overall looks good.
One small observation though in following steps -
1) HW GRO on initially as per "ethtool -k".
2) change MTU to 9000 which will not be supported with HW gro [HW gro gets off as per "ethtool -k"].
3) Change MTU back to 1500 which is supported mtu for HW gro but HW gro remains off as per "ethtool -k".
I don't have any strong recommendation that in step 3 if user fallback to supported mtu for HW gro then HW gro should
be again turned on automatically. I will leave up to user to control it back through ethtool.
Please note that we are yet to test bnx2x but I do see you are going to send V3. Hopefully, we will be able to provide feedback on bnx2x by that time.
Thanks for making this change.
Acked-by: Manish Chopra <manish.chopra@cavium.com>
^ permalink raw reply
* Re: [PATCH v2 net-next 4/4] bpftool: implement cgroup bpf operations
From: David Ahern @ 2017-12-08 16:52 UTC (permalink / raw)
To: Quentin Monnet, Roman Gushchin
Cc: netdev, linux-kernel, kernel-team, ast, daniel, jakub.kicinski,
kafai
In-Reply-To: <0eed580a-804b-329e-7bfc-1dc5c09a1deb@netronome.com>
On 12/8/17 8:39 AM, Quentin Monnet wrote:
> I don't believe compatibility is an issue here, since the program and
> its documentation come together (so they should stay in sync) and are
> part of the kernel tree (so the tool should be compatible with the
> kernel sources it comes with). My concern is that there is no way to
> guess from the current description what the values for ATTACH_FLAG or
> ATTACH_TYPE can be, without reading the source code of the program—which
> is not exactly user-friendly.
>
The tool should be backward and forward compatible across kernel
versions. Running a newer command on an older kernel should fail in a
deterministic. While the tool is in the kernel tree for ease of
development, that should not be confused with having a direct tie to any
kernel version.
I believe man pages do include kernel version descriptions in flags
(e.g., man 7 socket -- flags are denoted with "since Linux x.y") which
is one way to handle it with the usual caveat that vendors might have
backported support to earlier kernels.
^ permalink raw reply
* Re: [PATCH RFC 0/4] Fixes for Marvell MII paged register access races
From: Russell King - ARM Linux @ 2017-12-08 16:44 UTC (permalink / raw)
To: Andrew Lunn; +Cc: Florian Fainelli, netdev
In-Reply-To: <20171208161714.GC30846@lunn.ch>
On Fri, Dec 08, 2017 at 05:17:14PM +0100, Andrew Lunn wrote:
> Hi Russell
>
> > There is an open question whether there should be generic helpers for
> > this. Generic helpers would mean:
> >
> > - Additional couple of function pointers in phy_driver to read/write the
> > paging register. This has the restriction that there must only be one
> > paging register.
>
> I must be missing something. I don't see why there is this
> restriction. Don't we just need
>
> int phy_get_page(phydev);
> int phy_set_page(phydev, page);
The restriction occurs because a PHY may have several different
registers, and knowing which of the registers need touching becomes an
issue. We wouldn't want these accessors to needlessly access several
registers each and every time we requested an access to the page
register.
There's also the issue of whether an "int" or whatever type we choose to
pass the "page" around is enough bits. I haven't surveyed all the PHY
drivers yet to know the answer to that.
> We might even be able to do without phy_get_page(), if we assume page
> 0 should be selected by default, and all paged reads/write return to
> page 0 afterwards.
That would break the marvell driver, where it polls the copper page (0)
and fiber page (1) for link, and leaves the page set appropriately
depending on which negotiated the link. Not nice, but that's how the
driver is written to work.
> > - The helpers become more expensive, and because they're in a separate
> > compilation unit, the compiler will be unable to optimise them by
> > inlining the static functions.
>
> The mdio bus is slow. Often there is a completion function triggered
> by an interrupt etc. Worst case it is bit-banging. I suspect the gains
> from inlining are just noise in the bigger picture.
Yep.
> > - The helpers would be re-usable, saving replications of that code, and
> > making it more likely for phy authors to safely access the PHY.
>
> This is the key point for me. This has likely to of been broken for
> years. If it is obviously broken, driver writers are more likely to
> get it right. Here it is not obvious, so we should take it out of the
> driver writers hands and do it in the core.
See the patch below that partially does this on top of this series.
drivers/net/phy/marvell.c | 70 +++++++++++++++++++--------
drivers/net/phy/phy-core.c | 118 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 8 +++
3 files changed, 176 insertions(+), 20 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 5548ac8fa239..183a60a06099 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -537,9 +537,9 @@ static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev)
else
mscr = 0;
- return marvell_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
- MII_88E1121_PHY_MSCR_REG,
- MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
+ return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1121_PHY_MSCR_REG,
+ MII_88E1121_PHY_MSCR_DELAY_MASK, mscr);
}
static int m88e1121_config_aneg(struct phy_device *phydev)
@@ -567,9 +567,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
{
int err;
- err = marvell_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
- MII_88E1318S_PHY_MSCR1_REG,
- 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
+ err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE,
+ MII_88E1318S_PHY_MSCR1_REG,
+ 0, MII_88E1318S_PHY_MSCR1_PAD_ODD);
if (err < 0)
return err;
@@ -894,9 +894,9 @@ static int m88e1121_config_init(struct phy_device *phydev)
int err;
/* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */
- err = marvell_write_paged(phydev, MII_MARVELL_LED_PAGE,
- MII_88E1121_PHY_LED_CTRL,
- MII_88E1121_PHY_LED_DEF);
+ err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE,
+ MII_88E1121_PHY_LED_CTRL,
+ MII_88E1121_PHY_LED_DEF);
if (err < 0)
return err;
@@ -1544,7 +1544,7 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
int val;
u64 ret;
- val = marvell_read_paged(phydev, stat.page, stat.reg);
+ val = phy_read_paged(phydev, stat.page, stat.reg);
if (val < 0) {
ret = UINT64_MAX;
} else {
@@ -1684,8 +1684,8 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
*temp = 0;
- ret = marvell_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
- MII_88E1510_TEMP_SENSOR);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1510_TEMP_SENSOR);
if (ret < 0)
return ret;
@@ -1700,8 +1700,8 @@ static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
*temp = 0;
- ret = marvell_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
- MII_88E1121_MISC_TEST);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST);
if (ret < 0)
return ret;
@@ -1718,10 +1718,10 @@ static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
temp = temp / 1000;
temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f);
- return marvell_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
- MII_88E1121_MISC_TEST,
- ~MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
- temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
+ return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST,
+ ~MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK,
+ temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT);
}
static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
@@ -1730,8 +1730,8 @@ static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
*alarm = false;
- ret = marvell_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
- MII_88E1121_MISC_TEST);
+ ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE,
+ MII_88E1121_MISC_TEST);
if (ret < 0)
return ret;
@@ -1977,6 +1977,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -1995,6 +1997,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2013,6 +2017,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2031,6 +2037,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2050,6 +2058,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2071,6 +2081,8 @@ static struct phy_driver marvell_drivers[] = {
.set_wol = &m88e1318_set_wol,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2089,6 +2101,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2107,6 +2121,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2125,6 +2141,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2143,6 +2161,8 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2164,6 +2184,8 @@ static struct phy_driver marvell_drivers[] = {
.set_wol = &m88e1318_set_wol,
.resume = &marvell_resume,
.suspend = &marvell_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2184,6 +2206,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2203,6 +2227,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2223,6 +2249,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
@@ -2242,6 +2270,8 @@ static struct phy_driver marvell_drivers[] = {
.did_interrupt = &m88e1121_did_interrupt,
.resume = &genphy_resume,
.suspend = &genphy_suspend,
+ .read_page = marvell_read_page,
+ .write_page = marvell_write_page,
.get_sset_count = marvell_get_sset_count,
.get_strings = marvell_get_strings,
.get_stats = marvell_get_stats,
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 83d32644cb4d..66363b425c2a 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -280,3 +280,121 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
return ret;
}
EXPORT_SYMBOL(phy_write_mmd);
+
+static int __phy_read_page(struct phy_device *phydev)
+{
+ return phydev->drv->read_page(phydev);
+}
+
+static int __phy_write_page(struct phy_device *phydev, int page)
+{
+ return phydev->drv->write_page(phydev, page);
+}
+
+static int __phy_select_page(struct phy_device *phydev, int page)
+{
+ int ret, oldpage;
+
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
+ oldpage = ret = __phy_read_page(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write_page(phydev, page);
+ if (ret < 0)
+ return ret;
+
+ return oldpage;
+}
+
+static int __phy_restore_page(struct phy_device *phydev, int page, int rc)
+{
+ int ret;
+
+ if (page < 0) {
+ /* Propagate the phy page selection error code */
+ ret = page;
+ } else {
+ ret = __phy_write_page(phydev, page);
+
+ /* Propagate the operation return code if the page write
+ * was successful.
+ */
+ if (rc < 0 && ret >= 0)
+ ret = rc;
+ }
+
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
+
+ return ret;
+}
+
+/**
+ * phy_read_paged() - Convenience function for reading a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ *
+ * Same rules as for phy_read();
+ */
+int phy_read_paged(struct phy_device *phydev, int page, int regnum)
+{
+ int ret, oldpage;
+
+ oldpage = __phy_select_page(phydev, page);
+ if (oldpage >= 0)
+ ret = __phy_read(phydev, regnum);
+
+ return __phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_read_paged);
+
+/**
+ * phy_write_paged() - Convenience function for writing a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ * @val: value to write
+ *
+ * Same rules as for phy_write();
+ */
+int phy_write_paged(struct phy_device *phydev, int page, int regnum, int val)
+{
+ int ret, oldpage;
+
+ oldpage = __phy_select_page(phydev, page);
+ if (oldpage >= 0)
+ ret = __phy_write(phydev, regnum, val);
+
+ return __phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_write_paged);
+
+/**
+ * phy_modify_paged() - Convenience function for modifying a paged register
+ * @phydev: a pointer to a &struct phy_device
+ * @page: the page for the phy
+ * @regnum: register number
+ * @mask: bit mask of bits to preserve
+ * @set: bit mask of bits to set
+ *
+ * Same rules as for phy_read() and phy_write();
+ */
+int phy_modify_paged(struct phy_device *phydev, int page, int regnum,
+ int mask, int set)
+{
+ int ret, res, oldpage;
+
+ oldpage = __phy_select_page(phydev, page);
+ if (oldpage >= 0) {
+ ret = __phy_read(phydev, regnum);
+ if (ret >= 0) {
+ res = __phy_write(phydev, regnum, (ret & mask) | set);
+ if (res < 0)
+ ret = res;
+ }
+ }
+
+ return __phy_restore_page(phydev, oldpage, ret);
+}
+EXPORT_SYMBOL(phy_modify_paged);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 1db6e8eec85b..fa6f17d2a2de 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -634,6 +634,9 @@ struct phy_driver {
int (*write_mmd)(struct phy_device *dev, int devnum, u16 regnum,
u16 val);
+ int (*read_page)(struct phy_device *dev);
+ int (*write_page)(struct phy_device *dev, int page);
+
/* Get the size and type of the eeprom contained within a plug-in
* module */
int (*module_info)(struct phy_device *dev,
@@ -840,6 +843,11 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev)
*/
int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
+int phy_read_paged(struct phy_device *phydev, int page, int regnum);
+int phy_write_paged(struct phy_device *phydev, int page, int regnum, int val);
+int phy_modify_paged(struct phy_device *phydev, int page, int regnum,
+ int mask, int set);
+
bool phy_check_valid(int speed, int duplex, u32 features);
struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
^ permalink raw reply related
* Re: [PATCH] net: dsa: allow XAUI phy interface mode
From: Russell King - ARM Linux @ 2017-12-08 16:42 UTC (permalink / raw)
To: Andrew Lunn; +Cc: Vivien Didelot, Florian Fainelli, netdev
In-Reply-To: <20171208162643.GD30846@lunn.ch>
On Fri, Dec 08, 2017 at 05:26:43PM +0100, Andrew Lunn wrote:
> On Fri, Dec 08, 2017 at 04:04:59PM +0000, Russell King wrote:
> > XGMII is a 32-bit bus plus two clock signals per direction. XAUI is
> > four serial lanes per direction. The 88e6190 supports XAUI but not
> > XGMII as it doesn't have enough pins. The same is true of 88e6176.
> >
> > Match on PHY_INTERFACE_MODE_XAUI for the XAUI port type, but keep
> > accepting XGMII for backwards compatibility.
>
> Hi Russell
>
> The backwards compatibility is for the ZII devel C, the DSA link
> between the two switches? I don't think there are any other boards
> using this.
>
> I will ask around, but i don't think we need to worry about backwards
> compatibility. There is no region of flash set aside for the DT blob,
> etc. I always TFTP boot using the one from the kernel, etc.
Well, there's also kexec to consider, where it's better not to specify
the --dtb option because that wipes out the modifications (such as the
memory information) that the boot loader made to the pristine kbuild
generated dtb. So, with kexec its preferable to use the existing dtb
even with a newer kernel, or if not go through a full reboot to use a
new dtb.
Whether anyone uses kexec on this platform though would be an entirely
separate question, but I'm generally not in favour of breaking
compatibility with already merged DT without good reason.
You do seem to be correct that this only applies (in mainline) to the
ZII rev C board, so I guess including a patch to update its dts for
the inter-switch connection would at least be sensible.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up
^ permalink raw reply
* Re: [PATCH] selftests: net: Adding config fragment CONFIG_CGROUP_BPF=y
From: Daniel Borkmann @ 2017-12-08 16:29 UTC (permalink / raw)
To: Naresh Kamboju, netdev; +Cc: shuahkh, guro, shuah, linux-kselftest
In-Reply-To: <1512674639-13764-1-git-send-email-naresh.kamboju@linaro.org>
On 12/07/2017 08:23 PM, Naresh Kamboju wrote:
> CONFIG_CGROUP_BPF=y is required for test_dev_cgroup test case.
>
> Signed-off-by: Naresh Kamboju <naresh.kamboju@linaro.org>
> ---
> tools/testing/selftests/net/config | 1 +
Did you mean to add this to tools/testing/selftests/bpf/config instead?
test_dev_cgroup is under bpf selftests. Please respin for the correct
test suite.
> 1 file changed, 1 insertion(+)
>
> diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config
> index e57b4ac..02301c6 100644
> --- a/tools/testing/selftests/net/config
> +++ b/tools/testing/selftests/net/config
> @@ -1,3 +1,4 @@
> CONFIG_USER_NS=y
> CONFIG_BPF_SYSCALL=y
> CONFIG_TEST_BPF=m
> +CONFIG_CGROUP_BPF=y
>
^ permalink raw reply
* Re: [PATCH v5 net-next] net/tcp: trace all TCP/IP state transition with tcp_set_state tracepoint
From: David Miller @ 2017-12-08 16:28 UTC (permalink / raw)
To: laoar.shao
Cc: marcelo.leitner, songliubraving, kuznet, yoshfuji, rostedt,
bgregg, netdev, linux-kernel
In-Reply-To: <CALOAHbDNSaHqeQCSeNMfT7udN32VEciZA0bHgtt=coeXr4xj+g@mail.gmail.com>
From: Yafang Shao <laoar.shao@gmail.com>
Date: Fri, 8 Dec 2017 23:50:44 +0800
> 2017-12-08 23:42 GMT+08:00 David Miller <davem@davemloft.net>:
>> From: Yafang Shao <laoar.shao@gmail.com>
>> Date: Fri, 8 Dec 2017 11:40:23 +0800
>>
>>> It will looks like these,
>>>
>>> if (sk->sk_protocol == IPPROTO_TCP)
>>> __tcp_set_state(newsk, TCP_SYN_RECV);
>>> else
>>> newsk->sk_state = TCP_SYN_RECV;
>>>
>>>
>>> if (sk->sk_protocol == IPPROTO_TCP)
>>> __tcp_set_state(sk, TCP_CLOSE);
>>> else
>>> sk->sk_state = TCP_CLOSE;
>>>
>>> if (sk->sk_protocol == IPPROTO_TCP)
>>> tcp_state_store(sk, state);
>>> else
>>> sk_state_store(sk, state);
>>>
>>>
>>> Some redundant code.
>>>
>>> IMO, put these similar code into a wrapper is more nice.
>>
>> I think this discussion and how ugly this is getting shows that
>> tracing the state transitions of a socket is perhaps not best as a TCP
>> specific feature.
>
> Do you mean that tcp_set_state tracepoint should be replaced with
> sk_set_state tracepoint and move that tracepoint to
> trace/events/sock.h ?
Yes, something like that.
It will avoid all of these protocol specific checks and weird
dependencies.
^ permalink raw reply
* Re: [PATCH] net: dsa: allow XAUI phy interface mode
From: Andrew Lunn @ 2017-12-08 16:26 UTC (permalink / raw)
To: Russell King; +Cc: Vivien Didelot, Florian Fainelli, netdev
In-Reply-To: <E1eNL91-0007uX-Ig@rmk-PC.armlinux.org.uk>
On Fri, Dec 08, 2017 at 04:04:59PM +0000, Russell King wrote:
> XGMII is a 32-bit bus plus two clock signals per direction. XAUI is
> four serial lanes per direction. The 88e6190 supports XAUI but not
> XGMII as it doesn't have enough pins. The same is true of 88e6176.
>
> Match on PHY_INTERFACE_MODE_XAUI for the XAUI port type, but keep
> accepting XGMII for backwards compatibility.
Hi Russell
The backwards compatibility is for the ZII devel C, the DSA link
between the two switches? I don't think there are any other boards
using this.
I will ask around, but i don't think we need to worry about backwards
compatibility. There is no region of flash set aside for the DT blob,
etc. I always TFTP boot using the one from the kernel, etc.
Andrew
^ permalink raw reply
* Re: [PATCH net-next 5/6] net: qualcomm: rmnet: Allow to configure flags for new devices
From: Dan Williams @ 2017-12-08 16:26 UTC (permalink / raw)
To: Subash Abhinov Kasiviswanathan, davem, netdev
In-Reply-To: <1512369428-20455-6-git-send-email-subashab@codeaurora.org>
On Sun, 2017-12-03 at 23:37 -0700, Subash Abhinov Kasiviswanathan
wrote:
> Add an option to configure the rmnet aggregation and command features
> on device creation. This is achieved by using the vlan flags option.
Does this overload the VLAN flags item with different meanings than
VLAN_FLAG_* that are specific to rmnet?
Dan
> 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 5e530db..2f5f661 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:
> @@ -312,7 +321,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 = {
^ permalink raw reply
* RE: [PATCHv2 net-next 04/12] sctp: implement make_datafrag for sctp_stream_interleave
From: David Laight @ 2017-12-08 16:22 UTC (permalink / raw)
To: 'Xin Long', Marcelo Ricardo Leitner
Cc: Neil Horman, network dev, linux-sctp@vger.kernel.org,
davem@davemloft.net
In-Reply-To: <CADvbK_ckOgH9vzXVzckEtWAkJaYn9wuhJtZ+qpzep2T6C8Wung@mail.gmail.com>
From: Xin Long
> Sent: 08 December 2017 16:18
>
...
> >> Alternatively you could preform the dereference in two steps (i.e. declare an si
> >> pointer on the stack and set it equal to asoc->stream.si, then deref
> >> si->make_datafrag at call time. That will at least give the compiler an
> >> opportunity to preload the first pointer.
You want to save the function pointer itself.
...
> Another small difference:
> as you can see, comparing to (X), (Y) is using 0x28(%rsp) in the loop,
> instead of %r13.
>
> So that's what I can see from the related generated code.
> If 0x848(%r13) is not worse than 0x28(%rsp) for cpu, I think
> asoc->stream.si->make_datafrag() is even better. No ?
That code must have far too many life local variables.
Otherwise there's be a caller saved register available.
David
^ permalink raw reply
* RE: [PATCH net 3/3] hv_netvsc: Fix the default receive buffer size
From: Haiyang Zhang @ 2017-12-08 16:18 UTC (permalink / raw)
To: Dan Carpenter, Stephen Hemminger
Cc: devel@linuxdriverproject.org, Stephen Hemminger,
netdev@vger.kernel.org
In-Reply-To: <20171208104459.wtwexebad4acbod3@mwanda>
> -----Original Message-----
> From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
> Sent: Friday, December 8, 2017 5:45 AM
> To: Stephen Hemminger <stephen@networkplumber.org>
> Cc: KY Srinivasan <kys@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; Stephen Hemminger
> <sthemmin@microsoft.com>; devel@linuxdriverproject.org;
> netdev@vger.kernel.org
> Subject: Re: [PATCH net 3/3] hv_netvsc: Fix the default receive buffer size
>
> On Thu, Dec 07, 2017 at 04:10:55PM -0800, Stephen Hemminger wrote:
> > From: Haiyang Zhang <haiyangz@microsoft.com>
> >
> > The intended size is 16 MB, and the default slot size is 1728.
> > So, NETVSC_DEFAULT_RX should be 16*1024*1024 / 1728 = 9709.
> >
> > Fixes: 5023a6db73196 ("netvsc: increase default receive buffer size")
> > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
> > ---
> > drivers/net/hyperv/netvsc_drv.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/hyperv/netvsc_drv.c
> > b/drivers/net/hyperv/netvsc_drv.c index dc70de674ca9..edfcde5d3621
> > 100644
> > --- a/drivers/net/hyperv/netvsc_drv.c
> > +++ b/drivers/net/hyperv/netvsc_drv.c
> > @@ -50,7 +50,7 @@
> > #define NETVSC_MIN_TX_SECTIONS 10
> > #define NETVSC_DEFAULT_TX 192 /* ~1M */
> > #define NETVSC_MIN_RX_SECTIONS 10 /* ~64K */
> > -#define NETVSC_DEFAULT_RX 10485 /* Max ~16M */
> > +#define NETVSC_DEFAULT_RX 9709 /* ~16M */
>
> How does this bug look like to the user? Memory corruption?
>
> It's weird to me reviewing this code that the default sizes are stored in
> netvsc_drv.c and the max sizes are stored in hyperv_net.h.
> Could we move these to hyperv_net.h? We could write it like:
> #define NETVSC_DEFAULT_RX ((16 * 1024 * 1024) /
> NETVSC_RECV_SECTION_SIZE)
>
> 16MB is sort of a weird default because it's larger than the 15MB allowed for
> legacy versions, but it's smaller than the 32MB you'd want for the current
> versions.
As a tradeoff between traffic burst and latency, we set the default to be 16MB.
And this default is reduced automatically for legacy hosts based on the NVSP
version in patch 2.
I will move the change to hyperv_net.h
Thanks,
- Haiyang
^ permalink raw reply
* Re: [PATCHv2 net-next 04/12] sctp: implement make_datafrag for sctp_stream_interleave
From: Xin Long @ 2017-12-08 16:17 UTC (permalink / raw)
To: Marcelo Ricardo Leitner
Cc: Neil Horman, David Laight, network dev,
linux-sctp@vger.kernel.org, davem@davemloft.net
In-Reply-To: <20171208160001.GF3328@localhost.localdomain>
On Sat, Dec 9, 2017 at 12:00 AM, Marcelo Ricardo Leitner
<marcelo.leitner@gmail.com> wrote:
> On Fri, Dec 08, 2017 at 10:37:34AM -0500, Neil Horman wrote:
>> On Fri, Dec 08, 2017 at 12:56:30PM -0200, Marcelo Ricardo Leitner wrote:
>> > On Fri, Dec 08, 2017 at 02:06:04PM +0000, David Laight wrote:
>> > > From: Xin Long
>> > > > Sent: 08 December 2017 13:04
>> > > ...
>> > > > @@ -264,8 +264,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
>> > > > frag |= SCTP_DATA_SACK_IMM;
>> > > > }
>> > > >
>> > > > - chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag,
>> > > > - 0, GFP_KERNEL);
>> > > > + chunk = asoc->stream.si->make_datafrag(asoc, sinfo, len, frag,
>> > > > + GFP_KERNEL);
>> > >
>> > > I know that none of the sctp code is very optimised, but that indirect
>> > > call is going to be horrid.
>> >
>> > Yeah.. but there is no way to avoid the double derreference
>> > considering we only have the asoc pointer in there and we have to
>> > reach the contents of the data chunk operations struct, and the .si
>> > part is the same as 'stream' part as it's a constant offset.
>> >
>> > Due to the for() in there, we could add a variable to store
>> > asoc->stream.si outside the for and then we can do only a single deref
>> > inside it. Xin, can you please try and see if the generated code is
>> > different?
>> >
>> > Other suggestions?
>> >
>> Is it worth replacing the si struct with an index/enum value, and indexing an
>> array of method pointer structs? That would save you at least one dereference.
>
> Hmmm, maybe, yes. It would be like
> sctp_stream_interleave[asoc->stream.si].make_datafrag(...)
>
> Then same goes for pf->af, probably.
>
>>
>> Alternatively you could preform the dereference in two steps (i.e. declare an si
>> pointer on the stack and set it equal to asoc->stream.si, then deref
>> si->make_datafrag at call time. That will at least give the compiler an
>> opportunity to preload the first pointer.
>
> Yep, that was my 2nd paragraph above :-) but it only works for cases
> such as this one.
Now:
for(N) {
...
chunk = asoc->stream.si->make_datafrag(asoc, sinfo, len, frag,
0x000000000000fb58 <+360>: mov 0x848(%r13),%rax <---- [a]
0x000000000000fb5f <+367>: movzbl %cl,%ecx
0x000000000000fb62 <+370>: mov $0x14000c0,%r8d
0x000000000000fb68 <+376>: mov %r12d,%edx
0x000000000000fb6b <+379>: mov (%rsp),%rsi
0x000000000000fb6f <+383>: mov %r13,%rdi <=(X)
0x000000000000fb72 <+386>: callq *0x8(%rax) <---- [b]
0x000000000000fb78 <+392>: mov %rax,%r15
}
ret = N * ([a] + [b])
After using a variable:
struct sctp_stream_interleave *si;
...
si = asoc->stream.si;
0x000000000000fb44 <+340>: mov 0x848(%r14),%rax
0x000000000000fb4e <+350>: mov %rax,0x20(%rsp) <----- [1]
for(N) {
...
chunk = si->make_datafrag(asoc, sinfo, len, frag, GFP_KERNEL);
0x000000000000fb69 <+377>: mov 0x20(%rsp),%rax <----- [2]
0x000000000000fb6e <+382>: movzbl %cl,%ecx
0x000000000000fb71 <+385>: mov $0x14000c0,%r8d
0x000000000000fb77 <+391>: mov %r12d,%edx
0x000000000000fb7a <+394>: mov (%rsp),%rsi
0x000000000000fb7e <+398>: mov 0x28(%rsp),%rdi <=(Y)
0x000000000000fb83 <+403>: callq *0x8(%rax) <----- [3]
0x000000000000fb89 <+409>: mov %rax,%r14
}
ret = [1] + N * ([2] + [3])
Another small difference:
as you can see, comparing to (X), (Y) is using 0x28(%rsp) in the loop,
instead of %r13.
So that's what I can see from the related generated code.
If 0x848(%r13) is not worse than 0x28(%rsp) for cpu, I think
asoc->stream.si->make_datafrag() is even better. No ?
^ permalink raw reply
* Re: [PATCH RFC 0/4] Fixes for Marvell MII paged register access races
From: Andrew Lunn @ 2017-12-08 16:17 UTC (permalink / raw)
To: Russell King - ARM Linux; +Cc: Florian Fainelli, netdev
In-Reply-To: <20171208154756.GF10595@n2100.armlinux.org.uk>
Hi Russell
> There is an open question whether there should be generic helpers for
> this. Generic helpers would mean:
>
> - Additional couple of function pointers in phy_driver to read/write the
> paging register. This has the restriction that there must only be one
> paging register.
I must be missing something. I don't see why there is this
restriction. Don't we just need
int phy_get_page(phydev);
int phy_set_page(phydev, page);
We might even be able to do without phy_get_page(), if we assume page
0 should be selected by default, and all paged reads/write return to
page 0 afterwards.
> - The helpers become more expensive, and because they're in a separate
> compilation unit, the compiler will be unable to optimise them by
> inlining the static functions.
The mdio bus is slow. Often there is a completion function triggered
by an interrupt etc. Worst case it is bit-banging. I suspect the gains
from inlining are just noise in the bigger picture.
> - The helpers would be re-usable, saving replications of that code, and
> making it more likely for phy authors to safely access the PHY.
This is the key point for me. This has likely to of been broken for
years. If it is obviously broken, driver writers are more likely to
get it right. Here it is not obvious, so we should take it out of the
driver writers hands and do it in the core.
> Another potential question is whether using the mdiobus lock (which
> excludes all other MII bus access) is best - while it has the advantage
> of also ensuring atomicity with userspace accesses, it means that no one
> else can access an independent PHY on the same bus while a paged access
> is on-going. It feels like a big hammer, but I'm not convinced that we
> will see a lot of contention on it.
I think you are right about there being little contention on the lock.
I suspect most paged accesses are performed during initial setup and
configuration. I guess the once per second poll does not need to use
paged registers. And the weight of that hammer can be reduced a lot by
using interrupts instead of polling.
Andrew
^ permalink raw reply
* RE: [PATCH net 1/3] hv_netvsc: Correct the max receive buffer size
From: Haiyang Zhang @ 2017-12-08 16:11 UTC (permalink / raw)
To: Dan Carpenter, Stephen Hemminger
Cc: KY Srinivasan, Stephen Hemminger, devel@linuxdriverproject.org,
netdev@vger.kernel.org
In-Reply-To: <20171208103325.xt6nrzvxijewbdkl@mwanda>
> -----Original Message-----
> From: Dan Carpenter [mailto:dan.carpenter@oracle.com]
> Sent: Friday, December 8, 2017 5:33 AM
> To: Stephen Hemminger <stephen@networkplumber.org>
> Cc: KY Srinivasan <kys@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; Stephen Hemminger
> <sthemmin@microsoft.com>; devel@linuxdriverproject.org;
> netdev@vger.kernel.org
> Subject: Re: [PATCH net 1/3] hv_netvsc: Correct the max receive buffer size
>
> On Thu, Dec 07, 2017 at 04:10:53PM -0800, Stephen Hemminger wrote:
> > From: Haiyang Zhang <haiyangz@microsoft.com>
> >
> > It should be 31 MB on recent host versions.
> >
> > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
>
> This is very vague. What does "recent" mean in this context? There are also
> some unrelated white space changes here which make the patch harder to
> read.
>
> This patch kind of makes the bug fixed by patch 2 even worse because
> before the receive buffer was capped at around 16MB and now we can set
> the receive buffer to 31MB. It might make sense to fold the two patches
> together.
>
> Is patch 2 a memory corruption bug? The changelog doesn't really say what
> the user visible effects of the bug are. Basically if you make the buffer too
> small then it's a performance issue but if you make it too large what happens?
> It's not clear to me.
For NVSP v2, and earlier host, the limit is 15MB. Later hosts, the limit is 31MB.
Setting beyond it will be denied by the host, resulting the vNIC doesn't come up.
I will merge this one together with the patch 2.
Thanks,
- Haiyang
^ permalink raw reply
* Re: [PATCHv2 net-next 04/12] sctp: implement make_datafrag for sctp_stream_interleave
From: Neil Horman @ 2017-12-08 16:08 UTC (permalink / raw)
To: David Laight
Cc: 'Marcelo Ricardo Leitner', 'Xin Long',
network dev, linux-sctp@vger.kernel.org, davem@davemloft.net
In-Reply-To: <e3256db09d434461acb5861b30ef6f65@AcuMS.aculab.com>
On Fri, Dec 08, 2017 at 04:04:58PM +0000, David Laight wrote:
> From: Marcelo Ricardo Leitner
> > Sent: 08 December 2017 16:00
> ...
> > > Is it worth replacing the si struct with an index/enum value, and indexing an
> > > array of method pointer structs? That would save you at least one dereference.
> >
> > Hmmm, maybe, yes. It would be like
> > sctp_stream_interleave[asoc->stream.si].make_datafrag(...)
>
> If you only expect 2 choices then an if () is likely
> to produce better code that the above.
>
> The actual implementation can be hidden inside a #define
> or static inline function.
>
Thats the real question though, will we expect more than two interleaving
strategies? Currently its a boolean operation so the answer seems like yes, but
is there a possiblity of a biased interleaving, or other worthwhile algorithm?
Neil
> David
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: pull-request: bpf-next 2017-12-07
From: David Miller @ 2017-12-08 16:06 UTC (permalink / raw)
To: ast; +Cc: daniel, netdev
In-Reply-To: <20171208062211.2545706-1-ast@kernel.org>
From: Alexei Starovoitov <ast@kernel.org>
Date: Thu, 7 Dec 2017 22:22:11 -0800
> The following pull-request contains BPF updates for your net-next tree.
>
> The main changes are:
>
> 1) Detailed documentation of BPF development process from Daniel.
>
> 2) Addition of is_fullsock, snd_cwnd and srtt_us fields to bpf_sock_ops
> from Lawrence.
>
> 3) Minor follow up for bpf_skb_set_tunnel_key() from William.
>
> Please consider pulling these changes from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
Pulled, thanks Alexei.
^ permalink raw reply
* [PATCH] net: dsa: allow XAUI phy interface mode
From: Russell King @ 2017-12-08 16:04 UTC (permalink / raw)
To: Andrew Lunn, Vivien Didelot; +Cc: Florian Fainelli, netdev
XGMII is a 32-bit bus plus two clock signals per direction. XAUI is
four serial lanes per direction. The 88e6190 supports XAUI but not
XGMII as it doesn't have enough pins. The same is true of 88e6176.
Match on PHY_INTERFACE_MODE_XAUI for the XAUI port type, but keep
accepting XGMII for backwards compatibility.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/dsa/mv88e6xxx/port.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index a7801f6668a5..6315774d72b3 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -338,6 +338,7 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
break;
case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_XAUI:
cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
break;
case PHY_INTERFACE_MODE_RXAUI:
--
2.7.4
^ permalink raw reply related
* RE: [PATCHv2 net-next 04/12] sctp: implement make_datafrag for sctp_stream_interleave
From: David Laight @ 2017-12-08 16:04 UTC (permalink / raw)
To: 'Marcelo Ricardo Leitner', Neil Horman
Cc: 'Xin Long', network dev, linux-sctp@vger.kernel.org,
davem@davemloft.net
In-Reply-To: <20171208160001.GF3328@localhost.localdomain>
From: Marcelo Ricardo Leitner
> Sent: 08 December 2017 16:00
...
> > Is it worth replacing the si struct with an index/enum value, and indexing an
> > array of method pointer structs? That would save you at least one dereference.
>
> Hmmm, maybe, yes. It would be like
> sctp_stream_interleave[asoc->stream.si].make_datafrag(...)
If you only expect 2 choices then an if () is likely
to produce better code that the above.
The actual implementation can be hidden inside a #define
or static inline function.
David
^ permalink raw reply
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