Extend bridge command to configure and retrieve ageing interval for bridge
devices.  Netlink messaging is used to configure and retrieve the ageing
interval.

Signed-off-by: Premkumar Jonnala <pjonn...@broadcom.com>

---

diff --git a/bridge/br_common.h b/bridge/br_common.h
index 169a162..85cca68 100644
--- a/bridge/br_common.h
+++ b/bridge/br_common.h
@@ -5,12 +5,15 @@ extern int print_fdb(const struct sockaddr_nl *who,
                     struct nlmsghdr *n, void *arg);
 extern int print_mdb(const struct sockaddr_nl *who,
                     struct nlmsghdr *n, void *arg);
+extern int print_ageinfo(const struct sockaddr_nl *who,
+                        struct nlmsghdr *n, void *arg);
 
 extern int do_fdb(int argc, char **argv);
 extern int do_mdb(int argc, char **argv);
 extern int do_monitor(int argc, char **argv);
 extern int do_vlan(int argc, char **argv);
 extern int do_link(int argc, char **argv);
+extern int do_ageing(int argc, char **argv);
 
 extern int preferred_family;
 extern int show_stats;
diff --git a/bridge/bridge.c b/bridge/bridge.c
index eaf09c8..cf193d5 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c
@@ -31,7 +31,7 @@ static void usage(void)
 {
        fprintf(stderr,
 "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
-"where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
+"where OBJECT := { link | fdb | mdb | vlan | monitor | ageing }\n"
 "      OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
 "                   -o[neline] | -t[imestamp] | -n[etns] name |\n"
 "                   -c[ompressvlans] }\n");
@@ -53,6 +53,7 @@ static const struct cmd {
        { "mdb",        do_mdb },
        { "vlan",       do_vlan },
        { "monitor",    do_monitor },
+       { "ageing",      do_ageing },
        { "help",       do_help },
        { 0 }
 };
diff --git a/bridge/fdb.c b/bridge/fdb.c
index bd7e4f9..55c96f7 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -21,6 +21,7 @@
 #include <linux/neighbour.h>
 #include <string.h>
 #include <limits.h>
+#include <errno.h>
 
 #include "libnetlink.h"
 #include "br_common.h"
@@ -371,6 +372,161 @@ static int fdb_modify(int cmd, int flags, int argc, char 
**argv)
        return 0;
 }
 
+static void ageing_usage(void)
+{
+       fprintf(stderr, "Usage: bridge ageing interval { show | SECONDS | 
default } dev DEV\n");
+       exit(-1);
+}
+
+int print_ageinfo(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = arg;
+       struct admsg *r = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+
+       len -= NLMSG_LENGTH(sizeof(*r));
+
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len%d\n", len);
+               return -1;
+       }
+
+       if (r->adm_family != AF_BRIDGE)
+               return 0;
+       fprintf(fp, "dev %s, ageing %d secs\n",
+               ll_index_to_name(r->adm_ifindex), r->adm_ageing_interval);
+       return 0;
+}
+
+static int do_ageing_show(char *dev)
+{
+       struct {
+               struct nlmsghdr n;
+               struct admsg adm;
+               char buf[256];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct admsg));
+       req.n.nlmsg_type = RTM_GETAGEING;
+
+       int br_ifindex = ll_name_to_index(dev);
+
+       if (br_ifindex == 0) {
+               fprintf(stderr, "Cannot find bridge device \"%s\"\n", dev);
+               return -1;
+       }
+
+       req.adm.adm_family = PF_BRIDGE;
+       req.adm.adm_ifindex = br_ifindex;
+
+       if (rtnl_dump_request(&rth, RTM_GETAGEING, &req.adm,
+                             sizeof(struct admsg)) < 0) {
+               perror("Cannot send dump request");
+               exit(1);
+       }
+
+       if (rtnl_dump_filter(&rth, print_ageinfo, stdout) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               exit(1);
+       }
+       return 0;
+}
+
+static int do_ageing_modify(int default_ageing, int interval, char *dev)
+{
+       struct {
+               struct nlmsghdr n;
+               struct admsg adm;
+               char buf[256];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct admsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+
+       if (default_ageing) {
+               req.n.nlmsg_type = RTM_SETDEFAULTAGEING;
+               req.adm.adm_ageing_interval = 0; /* Don't care */
+       } else {
+               req.n.nlmsg_type = RTM_SETAGEING;
+               req.adm.adm_ageing_interval = interval;
+       }
+
+       req.adm.adm_family = PF_BRIDGE;
+       req.adm.adm_ifindex = ll_name_to_index(dev);
+
+       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+               return -1;
+
+       return 0;
+}
+
+int do_ageing(int argc, char **argv)
+{
+       int interval = -1;
+       int default_ageing = 0;
+       char *dev = NULL;
+       int show = 0;
+
+       ll_init_map(&rth);
+
+       if (argc > 0) {
+               if (matches(*argv, "interval") == 0) {
+                       argv++;
+                       argc--;
+               } else {
+                       ageing_usage();
+                       exit(-1);
+               }
+       }
+
+       if (argc > 0) {
+               if (matches(*argv, "show") == 0) {
+                       show = 1;
+               } else if (matches(*argv, "default") == 0) {
+                       default_ageing = 1;
+                       interval = 0;
+               } else if (matches(*argv, "help") == 0) {
+                       ageing_usage();
+                       exit(-1);
+               } else {
+                       errno = 0;
+                       interval = atoi(*argv);
+                       if (errno) {
+                               ageing_usage();
+                               exit(-1);
+                       }
+               }
+               argv++;
+               argc--;
+       } else {
+               ageing_usage();
+               exit(-1);
+       }
+
+       if (argc > 0) {
+               NEXT_ARG();
+               dev = *argv;
+       } else {
+               ageing_usage();
+               exit(-1);
+       }
+
+       if (show) {
+               do_ageing_show(dev);
+               return 0;
+       } else if (default_ageing || (interval > 0)) {
+               do_ageing_modify(default_ageing, interval, dev);
+               return 0;
+       }
+
+       fprintf(stderr, "Command unknown, try \'bridge interval help\'");
+       exit(-1);
+}
+
 int do_fdb(int argc, char **argv)
 {
        ll_init_map(&rth);
diff --git a/include/libnetlink.h b/include/libnetlink.h
index 968034b..9e3f092 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -161,6 +161,14 @@ extern int rtnl_from_file(FILE *, rtnl_listen_filter_t 
handler,
 #define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
 #endif
 
+#ifndef ADA_RTA
+#define ADA_RTA(r) \
+       ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct admsg))))
+#endif
+#ifndef ADA_PAYLOAD
+#define ADA_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct admsg))
+#endif
+
 #ifndef NDTA_RTA
 #define NDTA_RTA(r) \
        ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg))))
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 913bd8e..dac6452 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -198,4 +198,11 @@ enum {
 };
 #define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
 
+struct admsg {
+       __u8 adm_family;
+       __u8 adm_pad1;
+       __u16   adm_pad2;
+       __s32 adm_ifindex;
+       __u16 adm_ageing_interval;
+};
 #endif /* _LINUX_IF_BRIDGE_H */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index a78f0b3..abc9617 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -139,6 +139,13 @@ enum {
        RTM_GETNSID = 90,
 #define RTM_GETNSID RTM_GETNSID
 
+       RTM_SETAGEING = 92,
+#define RTM_SETAGEING RTM_SETAGEING
+       RTM_SETDEFAULTAGEING = 93,
+#define RTM_SETDEFAULTAGEING RTM_SETDEFAULTAGEING
+       RTM_GETAGEING = 94,
+#define RTM_GETAGEING RTM_GETAGEING
+
        __RTM_MAX,
 #define RTM_MAX                (((__RTM_MAX + 3) & ~3) - 1)
 };
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to