mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-15 22:15:13 +08:00
8589eb4efd
Every tool in the iproute2 package have one or more function to show an help message to the user. Some of these functions print the help line by line with a series of printf call, e.g. ip/xfrm_state.c does 60 fprintf calls. If we group all the calls to a single one and just concatenate strings, we save a lot of libc calls and thus object size. The size difference of the compiled binaries calculated with bloat-o-meter is: ip/ip: add/remove: 0/0 grow/shrink: 5/15 up/down: 103/-4796 (-4693) Total: Before=672591, After=667898, chg -0.70% ip/rtmon: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-54 (-54) Total: Before=48879, After=48825, chg -0.11% tc/tc: add/remove: 0/2 grow/shrink: 31/10 up/down: 882/-6133 (-5251) Total: Before=351912, After=346661, chg -1.49% bridge/bridge: add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-459 (-459) Total: Before=70502, After=70043, chg -0.65% misc/lnstat: add/remove: 0/1 grow/shrink: 1/0 up/down: 48/-486 (-438) Total: Before=9960, After=9522, chg -4.40% tipc/tipc: add/remove: 0/0 grow/shrink: 1/1 up/down: 18/-62 (-44) Total: Before=79182, After=79138, chg -0.06% While at it, indent some strings which were starting at column 0, and use tabs where possible, to have a consistent style across helps. Signed-off-by: Matteo Croce <mcroce@redhat.com> Signed-off-by: David Ahern <dsahern@gmail.com>
251 lines
5.5 KiB
C
251 lines
5.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* q_atm.c ATM.
|
|
*
|
|
* Hacked 1998-2000 by Werner Almesberger, EPFL ICA
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
#include <atm.h>
|
|
#include <linux/atmdev.h>
|
|
#include <linux/atmarp.h>
|
|
|
|
#include "utils.h"
|
|
#include "tc_util.h"
|
|
|
|
|
|
#define MAX_HDR_LEN 64
|
|
|
|
|
|
static int atm_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|
struct nlmsghdr *n, const char *dev)
|
|
{
|
|
if (argc) {
|
|
fprintf(stderr, "Usage: atm\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void explain(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: ... atm ( pvc ADDR | svc ADDR [ sap SAP ] ) [ qos QOS ] [ sndbuf BYTES ]\n"
|
|
" [ hdr HEX... ] [ excess ( CLASSID | clp ) ] [ clip ]\n");
|
|
}
|
|
|
|
|
|
static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
|
|
struct nlmsghdr *n, const char *dev)
|
|
{
|
|
struct sockaddr_atmsvc addr = {};
|
|
struct atm_qos qos;
|
|
struct atm_sap sap;
|
|
unsigned char hdr[MAX_HDR_LEN];
|
|
__u32 excess = 0;
|
|
struct rtattr *tail;
|
|
int sndbuf = 0;
|
|
int hdr_len = -1;
|
|
int set_clip = 0;
|
|
int s;
|
|
|
|
(void) text2qos("aal5,ubr:sdu=9180,rx:none", &qos, 0);
|
|
(void) text2sap("blli:l2=iso8802", &sap, 0);
|
|
while (argc > 0) {
|
|
if (!strcmp(*argv, "pvc")) {
|
|
NEXT_ARG();
|
|
if (text2atm(*argv, (struct sockaddr *) &addr,
|
|
sizeof(addr), T2A_PVC | T2A_NAME) < 0) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"svc")) {
|
|
NEXT_ARG();
|
|
if (text2atm(*argv, (struct sockaddr *) &addr,
|
|
sizeof(addr), T2A_SVC | T2A_NAME) < 0) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"qos")) {
|
|
NEXT_ARG();
|
|
if (text2qos(*argv, &qos, 0) < 0) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"sndbuf")) {
|
|
char *end;
|
|
|
|
NEXT_ARG();
|
|
sndbuf = strtol(*argv, &end, 0);
|
|
if (*end) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"sap")) {
|
|
NEXT_ARG();
|
|
if (addr.sas_family != AF_ATMSVC ||
|
|
text2sap(*argv, &sap, T2A_NAME) < 0) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"hdr")) {
|
|
unsigned char *ptr;
|
|
char *walk;
|
|
|
|
NEXT_ARG();
|
|
ptr = hdr;
|
|
for (walk = *argv; *walk; walk++) {
|
|
int tmp;
|
|
|
|
if (ptr == hdr+MAX_HDR_LEN) {
|
|
fprintf(stderr, "header is too long\n");
|
|
return -1;
|
|
}
|
|
if (*walk == '.') continue;
|
|
if (!isxdigit(walk[0]) || !walk[1] ||
|
|
!isxdigit(walk[1])) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
sscanf(walk, "%2x", &tmp);
|
|
*ptr++ = tmp;
|
|
walk++;
|
|
}
|
|
hdr_len = ptr-hdr;
|
|
} else if (!strcmp(*argv,"excess")) {
|
|
NEXT_ARG();
|
|
if (!strcmp(*argv, "clp")) excess = 0;
|
|
else if (get_tc_classid(&excess, *argv)) {
|
|
explain();
|
|
return -1;
|
|
}
|
|
} else if (!strcmp(*argv,"clip")) {
|
|
set_clip = 1;
|
|
} else {
|
|
explain();
|
|
return 1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
s = socket(addr.sas_family, SOCK_DGRAM, 0);
|
|
if (s < 0) {
|
|
perror("socket");
|
|
return -1;
|
|
}
|
|
if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) {
|
|
perror("SO_ATMQOS");
|
|
return -1;
|
|
}
|
|
if (sndbuf)
|
|
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
|
|
perror("SO_SNDBUF");
|
|
return -1;
|
|
}
|
|
if (addr.sas_family == AF_ATMSVC && setsockopt(s, SOL_ATM, SO_ATMSAP,
|
|
&sap, sizeof(sap)) < 0) {
|
|
perror("SO_ATMSAP");
|
|
return -1;
|
|
}
|
|
if (connect(s, (struct sockaddr *) &addr, addr.sas_family == AF_ATMPVC ?
|
|
sizeof(struct sockaddr_atmpvc) : sizeof(addr)) < 0) {
|
|
perror("connect");
|
|
return -1;
|
|
}
|
|
if (set_clip)
|
|
if (ioctl(s, ATMARP_MKIP, 0) < 0) {
|
|
perror("ioctl ATMARP_MKIP");
|
|
return -1;
|
|
}
|
|
tail = addattr_nest(n, 1024, TCA_OPTIONS);
|
|
addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s));
|
|
if (excess)
|
|
addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
|
|
if (hdr_len != -1)
|
|
addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
|
|
addattr_nest_end(n, tail);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static int atm_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
|
{
|
|
struct rtattr *tb[TCA_ATM_MAX+1];
|
|
char buffer[MAX_ATM_ADDR_LEN+1];
|
|
|
|
if (opt == NULL)
|
|
return 0;
|
|
|
|
parse_rtattr_nested(tb, TCA_ATM_MAX, opt);
|
|
if (tb[TCA_ATM_ADDR]) {
|
|
if (RTA_PAYLOAD(tb[TCA_ATM_ADDR]) <
|
|
sizeof(struct sockaddr_atmpvc))
|
|
fprintf(stderr, "ATM: address too short\n");
|
|
else {
|
|
if (atm2text(buffer, MAX_ATM_ADDR_LEN,
|
|
RTA_DATA(tb[TCA_ATM_ADDR]), A2T_PRETTY | A2T_NAME) <
|
|
0) fprintf(stderr, "atm2text error\n");
|
|
fprintf(f, "pvc %s ", buffer);
|
|
}
|
|
}
|
|
if (tb[TCA_ATM_HDR]) {
|
|
int i;
|
|
const __u8 *hdr = RTA_DATA(tb[TCA_ATM_HDR]);
|
|
|
|
fprintf(f, "hdr");
|
|
for (i = 0; i < RTA_PAYLOAD(tb[TCA_ATM_HDR]); i++)
|
|
fprintf(f, "%c%02x", i ? '.' : ' ', hdr[i]);
|
|
if (!i) fprintf(f, " .");
|
|
fprintf(f, " ");
|
|
}
|
|
if (tb[TCA_ATM_EXCESS]) {
|
|
__u32 excess;
|
|
|
|
if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS]) < sizeof(excess))
|
|
fprintf(stderr, "ATM: excess class ID too short\n");
|
|
else {
|
|
excess = rta_getattr_u32(tb[TCA_ATM_EXCESS]);
|
|
if (!excess) fprintf(f, "excess clp ");
|
|
else {
|
|
char buf[64];
|
|
|
|
print_tc_classid(buf, sizeof(buf), excess);
|
|
fprintf(f, "excess %s ", buf);
|
|
}
|
|
}
|
|
}
|
|
if (tb[TCA_ATM_STATE]) {
|
|
static const char *map[] = { ATM_VS2TXT_MAP };
|
|
int state;
|
|
|
|
if (RTA_PAYLOAD(tb[TCA_ATM_STATE]) < sizeof(state))
|
|
fprintf(stderr, "ATM: state field too short\n");
|
|
else {
|
|
state = rta_getattr_u32(tb[TCA_ATM_STATE]);
|
|
fprintf(f, "%s ", map[state]);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct qdisc_util atm_qdisc_util = {
|
|
.id = "atm",
|
|
.parse_qopt = atm_parse_opt,
|
|
.print_qopt = atm_print_opt,
|
|
.parse_copt = atm_parse_class_opt,
|
|
.print_copt = atm_print_opt,
|
|
};
|