changeset 1166:8b3cf974c66d draft

An implementation for brctl (ethernet bridge control).
author Ashwini Sharma <ak.ashwini1981@gmail.com>
date Thu, 26 Dec 2013 09:37:03 -0600
parents 3c438a08d1fb
children 17387db4d979
files toys/pending/brctl.c
diffstat 1 files changed, 339 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/pending/brctl.c	Thu Dec 26 09:37:03 2013 -0600
@@ -0,0 +1,339 @@
+/* brctl.c - ethernet bridge control
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard
+
+USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
+
+config BRCTL
+  bool "brctl"
+  default n
+  help
+    Usage: brctl COMMAND [BRIDGE [INTERFACE]]
+
+    Manage ethernet bridges
+
+    Commands:
+    show                  Show a list of bridges
+    addbr BRIDGE          Create BRIDGE
+    delbr BRIDGE          Delete BRIDGE
+    addif BRIDGE IFACE    Add IFACE to BRIDGE
+    delif BRIDGE IFACE    Delete IFACE from BRIDGE
+    setageing BRIDGE TIME Set ageing time
+    setfd BRIDGE TIME     Set bridge forward delay
+    sethello BRIDGE TIME  Set hello time
+    setmaxage BRIDGE TIME Set max message age
+    setpathcost BRIDGE PORT COST   Set path cost
+    setportprio BRIDGE PORT PRIO   Set port priority
+    setbridgeprio BRIDGE PRIO      Set bridge priority
+    stp BRIDGE [1/yes/on|0/no/off] STP on/off
+*/
+
+#define FOR_brctl
+#include "toys.h"
+#include <linux/if_bridge.h>
+
+GLOBALS(
+    int sockfd;
+)
+#define MAX_BRIDGES 1024 //same is no of ports supported
+
+static void get_ports(char *bridge, int *indices)
+{
+  struct ifreq ifr;                              
+  int ifindices[MAX_BRIDGES];
+  unsigned long args[4] = { BRCTL_GET_PORT_LIST,
+    (unsigned long) ifindices, MAX_BRIDGES, 0 };
+
+  memset(ifindices, 0, MAX_BRIDGES);
+  args[1] = (unsigned long)ifindices;
+  strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+  if (indices) memcpy(indices, ifindices, sizeof(ifindices));
+}
+
+void get_br_info(char *bridge, struct __bridge_info *info)
+{
+  struct ifreq ifr;
+  unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
+    (unsigned long) info, 0, 0 };
+
+  memset(info, 0, sizeof(*info));
+  strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+
+  if (ioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr) < 0) {
+    perror_msg("%s: can't get info %s\n", bridge, strerror(errno));
+    return;
+  }
+}
+
+void br_show(char **argv)
+{
+  struct __bridge_info info;
+  int num, cnt, i, j, ifindices[MAX_BRIDGES], pindices[MAX_BRIDGES];
+  unsigned long args[4] = { BRCTL_GET_BRIDGES,
+    (unsigned long)ifindices, MAX_BRIDGES,0 };
+  char br[IF_NAMESIZE], ifn[IF_NAMESIZE];
+
+  num = ioctl(TT.sockfd, SIOCGIFBR, args); //ret is num of bridges found
+  if (num < 0) error_exit("get bridges fail");
+  printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
+
+  for (i = 0; i < num; i++) {
+    unsigned char *id;
+
+    if (!if_indextoname(ifindices[i], br)) perror_exit("interface not found");
+    get_br_info(br, &info);
+    id = (unsigned char*)&(info.bridge_id);
+    printf("%s\t\t",br);
+    printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", id[0], id[1], 
+        id[2], id[3], id[4], id[5], id[6], id[7]);
+    printf("\t%s\t\t",(info.stp_enabled)?"yes" : "no");
+
+    memset(pindices, 0, sizeof(pindices));
+    get_ports(br, pindices);
+    for (j = 0, cnt = 0; j < MAX_BRIDGES; j++) {
+      if (!pindices[j]) continue;
+      if (!if_indextoname(pindices[j], ifn)) {
+        error_msg("no name for index :%d", pindices[j]);
+        continue;
+      }
+      if (cnt) printf("\n\t\t\t\t\t\t\t");
+      printf("%s", ifn);
+      cnt++;
+    }
+    xputc('\n');
+  }
+}
+
+void br_addbr(char **argv)
+{
+  char br[IFNAMSIZ];                
+  unsigned long args[4] = {BRCTL_ADD_BRIDGE, (unsigned long) br, 0, 0};
+
+#ifdef SIOCBRADDBR
+  xioctl(TT.sockfd, SIOCBRADDBR, argv[0]);
+#else            
+  strncpy(br, argv[0], IFNAMSIZ);   
+  xioctl(TT.sockfd, SIOCSIFBR, args);
+#endif
+}
+
+void br_delbr(char **argv)
+{
+  char br[IFNAMSIZ];
+  unsigned long args[4] = {BRCTL_DEL_BRIDGE, (unsigned long) br, 0, 0};
+
+#ifdef SIOCBRDELBR
+  xioctl(TT.sockfd, SIOCBRDELBR, argv[0]);
+#else
+  strncpy(br, argv[0], IFNAMSIZ);
+  xioctl(TT.sockfd, SIOCSIFBR, args);
+#endif
+}
+
+void br_addif(char **argv)
+{
+  int index;
+  struct ifreq ifr;
+  unsigned long args[4] = {BRCTL_ADD_IF, 0, 0, 0};
+
+  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s", argv[1]);
+#ifdef SIOCBRADDIF
+  ifr.ifr_ifindex = index;
+  xioctl(TT.sockfd, SIOCBRADDIF, &ifr);
+#else
+  args[1] = index;
+  strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+#endif
+}
+
+void br_delif(char **argv)
+{
+  int index;                             
+  struct ifreq ifr;                      
+  unsigned long args[4] = {BRCTL_DEL_IF, 0, 0, 0};
+
+  if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s",argv[1]);
+#ifdef SIOCBRDELIF
+  ifr.ifr_ifindex = ifindex;
+  xioctl(TT.sockfd, SIOCBRDELIF, &ifr);
+#else
+  args[1] = index;     
+  strncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
+  ifr.ifr_data = (char *)args;  
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+#endif
+}
+
+static void strtotimeval(struct timeval *tv, char *time)
+{
+  double secs;
+
+  if (sscanf(time, "%lf", &secs) != 1) error_exit("time format not proper");
+  tv->tv_sec = secs;
+  tv->tv_usec = 1000000 * (secs - tv->tv_sec);
+}
+
+static unsigned long tv_to_jify(struct timeval *tv)
+{                       
+  unsigned long long jify;
+
+  jify = 1000000ULL * tv->tv_sec + tv->tv_usec;
+  return (jify/10000);
+}                  
+
+void set_time(char *br, unsigned long cmd, unsigned long val)
+{
+  struct ifreq ifr;
+  unsigned long args[4] = {cmd, val, 0, 0};
+
+  strncpy(ifr.ifr_name, br, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+}
+
+void br_set_ageing_time(char **argv)     
+{
+  struct timeval tv;
+
+  strtotimeval(&tv, argv[1]);
+  set_time(argv[0], BRCTL_SET_AGEING_TIME, tv_to_jify(&tv));
+}
+
+void br_set_fwd_delay(char **argv)
+{
+  struct timeval tv;
+
+  strtotimeval(&tv, argv[1]);
+  set_time(argv[0], BRCTL_SET_BRIDGE_FORWARD_DELAY, tv_to_jify(&tv));
+}
+
+void br_set_hello_time(char **argv)
+{
+  struct timeval tv;                        
+
+  strtotimeval(&tv, argv[1]);               
+  set_time(argv[0], BRCTL_SET_BRIDGE_HELLO_TIME, tv_to_jify(&tv));
+}
+
+void br_set_max_age(char **argv)
+{
+  struct timeval tv;                        
+
+  strtotimeval(&tv, argv[1]);               
+  set_time(argv[0], BRCTL_SET_BRIDGE_MAX_AGE, tv_to_jify(&tv));
+}
+
+void br_set_bridge_prio(char **argv)
+{
+  int prio;
+
+  if (sscanf(argv[1], "%i", &prio) != 1) error_exit("prio not proper");
+  set_time(argv[0], BRCTL_SET_BRIDGE_PRIORITY, prio);
+}
+
+void br_set_stp(char **argv)
+{
+  int i;
+  struct stp {
+    char *n;
+    int set;
+  } ss[] = {{"1", 1}, {"yes", 1},{"on", 1},
+    {"0", 0}, {"no", 0},{"off", 0}};
+
+  for (i = 0; i < ARRAY_LEN(ss); i++) {
+    if (!strcmp(ss[i].n, argv[1])) break;
+  }
+  if (i >= ARRAY_LEN(ss)) error_exit("invalid stp state");
+  set_time(argv[0], BRCTL_SET_BRIDGE_STP_STATE, ss[i].set);
+}
+
+void set_cost_prio(char *br, char *port, unsigned long cmd, unsigned long val)
+{
+  struct ifreq ifr;
+  int i, index, pindices[MAX_BRIDGES];
+  unsigned long args[4] = {cmd, 0, val, 0};
+  
+  if (!(index = if_nametoindex(port))) error_exit("invalid port");
+  
+  memset(pindices, 0, sizeof(pindices));
+  get_ports(br, pindices);
+  for (i = 0; i < MAX_BRIDGES; i++) {
+    if (index == pindices[i]) break;
+  }
+  if (i >= MAX_BRIDGES) error_exit("%s not in bridge", port);
+  args[1] = i;
+  strncpy(ifr.ifr_name, br, IFNAMSIZ);
+  ifr.ifr_data = (char *)args;
+  xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
+}
+
+void br_set_path_cost(char **argv)
+{
+  int cost;
+
+  cost = atolx_range(argv[2], 0, INT_MAX);
+  set_cost_prio(argv[0], argv[1], BRCTL_SET_PATH_COST, cost);
+}
+
+void br_set_port_prio(char **argv)
+{ 
+  int prio;
+
+  prio = atolx_range(argv[2], 0, INT_MAX);
+  set_cost_prio(argv[0], argv[1], BRCTL_SET_PORT_PRIORITY, prio);
+
+}
+
+void brctl_main(void)
+{
+  int i;
+  struct cmds {
+    char *cmd;
+    int nargs;
+    void (*f)(char **argv);
+  } cc[] = {{"show", 0, br_show},
+    {"addbr", 1, br_addbr}, {"delbr", 1, br_delbr},
+    {"addif", 2, br_addif}, {"delif", 2, br_delif},
+    {"setageing", 2, br_set_ageing_time},
+    {"setfd", 2, br_set_fwd_delay},
+    {"sethello", 2, br_set_hello_time},
+    {"setmaxage", 2, br_set_max_age},
+    {"setpathcost", 3, br_set_path_cost},
+    {"setportprio", 3, br_set_port_prio},
+    {"setbridgeprio", 2, br_set_bridge_prio},
+    {"stp", 2, br_set_stp},
+  };
+
+  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
+  while (*toys.optargs) {
+    for (i = 0; i < ARRAY_LEN(cc); i++) {
+      struct cmds *t = cc + i;
+
+      if (strcmp(t->cmd, *toys.optargs)) continue;
+
+      toys.optargs++, toys.optc--;
+      if (toys.optc < t->nargs) {            
+        toys.exithelp++;
+        error_exit("check args");
+      }
+      t->f(toys.optargs);
+      toys.optargs += t->nargs;
+      toys.optc -= t->nargs;
+      break;
+    }
+
+    if (i == ARRAY_LEN(cc)) {
+      toys.exithelp++;
+      error_exit("invalid option '%s'", *toys.optargs);
+    }
+  }
+  xclose(TT.sockfd);
+}