1 /* 2 * Get/set/delete bridge with netlink 3 * 4 * Authors: Stephen Hemminger <shemminger (at) 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 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 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 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 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 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