1 /*
2 * Get/set/delete bridge with netlink
3 *
4 * Authors: Stephen Hemminger <shemminger@vyatta.com>
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/socket.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include "SNAPSHOT.h"
15 #include "utils.h"
16 #include "br_common.h"
17 #include "namespace.h"
18
19 struct rtnl_handle rth = { .fd = -1 };
20 int preferred_family = AF_UNSPEC;
21 int oneline;
22 int show_stats;
23 int show_details;
24 int compress_vlans;
25 int json_output;
26 int timestamp;
27 char *batch_file;
28 int force;
29 const char *_SL_;
30
31 static void usage(void) __attribute__((noreturn));
32
usage(void)33 static void usage(void)
34 {
35 fprintf(stderr,
36 "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
37 " bridge [ -force ] -batch filename\n"
38 "where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
39 " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
40 " -o[neline] | -t[imestamp] | -n[etns] name |\n"
41 " -c[ompressvlans] -j{son} }\n");
42 exit(-1);
43 }
44
do_help(int argc,char ** argv)45 static int do_help(int argc, char **argv)
46 {
47 usage();
48 }
49
50
51 static const struct cmd {
52 const char *cmd;
53 int (*func)(int argc, char **argv);
54 } cmds[] = {
55 { "link", do_link },
56 { "fdb", do_fdb },
57 { "mdb", do_mdb },
58 { "vlan", do_vlan },
59 { "monitor", do_monitor },
60 { "help", do_help },
61 { 0 }
62 };
63
do_cmd(const char * argv0,int argc,char ** argv)64 static int do_cmd(const char *argv0, int argc, char **argv)
65 {
66 const struct cmd *c;
67
68 for (c = cmds; c->cmd; ++c) {
69 if (matches(argv0, c->cmd) == 0)
70 return c->func(argc-1, argv+1);
71 }
72
73 fprintf(stderr,
74 "Object \"%s\" is unknown, try \"bridge help\".\n", argv0);
75 return -1;
76 }
77
batch(const char * name)78 static int batch(const char *name)
79 {
80 char *line = NULL;
81 size_t len = 0;
82 int ret = EXIT_SUCCESS;
83
84 if (name && strcmp(name, "-") != 0) {
85 if (freopen(name, "r", stdin) == NULL) {
86 fprintf(stderr,
87 "Cannot open file \"%s\" for reading: %s\n",
88 name, strerror(errno));
89 return EXIT_FAILURE;
90 }
91 }
92
93 if (rtnl_open(&rth, 0) < 0) {
94 fprintf(stderr, "Cannot open rtnetlink\n");
95 return EXIT_FAILURE;
96 }
97
98 cmdlineno = 0;
99 while (getcmdline(&line, &len, stdin) != -1) {
100 char *largv[100];
101 int largc;
102
103 largc = makeargs(line, largv, 100);
104 if (largc == 0)
105 continue; /* blank line */
106
107 if (do_cmd(largv[0], largc, largv)) {
108 fprintf(stderr, "Command failed %s:%d\n",
109 name, cmdlineno);
110 ret = EXIT_FAILURE;
111 if (!force)
112 break;
113 }
114 }
115 if (line)
116 free(line);
117
118 rtnl_close(&rth);
119 return ret;
120 }
121
122 int
main(int argc,char ** argv)123 main(int argc, char **argv)
124 {
125 while (argc > 1) {
126 const char *opt = argv[1];
127
128 if (strcmp(opt, "--") == 0) {
129 argc--; argv++;
130 break;
131 }
132 if (opt[0] != '-')
133 break;
134 if (opt[1] == '-')
135 opt++;
136
137 if (matches(opt, "-help") == 0) {
138 usage();
139 } else if (matches(opt, "-Version") == 0) {
140 printf("bridge utility, 0.0\n");
141 exit(0);
142 } else if (matches(opt, "-stats") == 0 ||
143 matches(opt, "-statistics") == 0) {
144 ++show_stats;
145 } else if (matches(opt, "-details") == 0) {
146 ++show_details;
147 } else if (matches(opt, "-oneline") == 0) {
148 ++oneline;
149 } else if (matches(opt, "-timestamp") == 0) {
150 ++timestamp;
151 } else if (matches(opt, "-family") == 0) {
152 argc--;
153 argv++;
154 if (argc <= 1)
155 usage();
156 if (strcmp(argv[1], "inet") == 0)
157 preferred_family = AF_INET;
158 else if (strcmp(argv[1], "inet6") == 0)
159 preferred_family = AF_INET6;
160 else if (strcmp(argv[1], "help") == 0)
161 usage();
162 else
163 invarg("invalid protocol family", argv[1]);
164 } else if (strcmp(opt, "-4") == 0) {
165 preferred_family = AF_INET;
166 } else if (strcmp(opt, "-6") == 0) {
167 preferred_family = AF_INET6;
168 } else if (matches(opt, "-netns") == 0) {
169 NEXT_ARG();
170 if (netns_switch(argv[1]))
171 exit(-1);
172 } else if (matches(opt, "-compressvlans") == 0) {
173 ++compress_vlans;
174 } else if (matches(opt, "-force") == 0) {
175 ++force;
176 } else if (matches(opt, "-json") == 0) {
177 ++json_output;
178 } else if (matches(opt, "-batch") == 0) {
179 argc--;
180 argv++;
181 if (argc <= 1)
182 usage();
183 batch_file = argv[1];
184 } else {
185 fprintf(stderr,
186 "Option \"%s\" is unknown, try \"bridge help\".\n",
187 opt);
188 exit(-1);
189 }
190 argc--; argv++;
191 }
192
193 _SL_ = oneline ? "\\" : "\n";
194
195 if (batch_file)
196 return batch(batch_file);
197
198 if (rtnl_open(&rth, 0) < 0)
199 exit(1);
200
201 if (argc > 1)
202 return do_cmd(argv[1], argc-1, argv+1);
203
204 rtnl_close(&rth);
205 usage();
206 }
207