]>
Commit | Line | Data |
---|---|---|
ad02a0eb SH |
1 | /* |
2 | * brmon.c RTnetlink listener. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Stephen Hemminger <shemminger@osdl.org> | |
10 | * | |
11 | * Modified by Srinivas Aji <Aji_Srinivas@emc.com> for use | |
12 | * in RSTP daemon. - 2006-09-01 | |
13 | */ | |
14 | ||
15 | #include <stdio.h> | |
16 | #include <stdlib.h> | |
17 | #include <unistd.h> | |
18 | #include <syslog.h> | |
19 | #include <fcntl.h> | |
20 | #include <sys/socket.h> | |
21 | #include <sys/time.h> | |
22 | #include <net/if.h> | |
23 | #include <netinet/in.h> | |
24 | #include <linux/if_bridge.h> | |
25 | #include <string.h> | |
26 | ||
27 | #include "libnetlink.h" | |
28 | ||
29 | #include "bridge_ctl.h" | |
30 | ||
31 | static const char SNAPSHOT[] = "v0.1"; | |
32 | ||
ad02a0eb SH |
33 | static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, |
34 | void *arg) | |
35 | { | |
36 | FILE *fp = arg; | |
37 | struct ifinfomsg *ifi = NLMSG_DATA(n); | |
96e20123 | 38 | struct rtattr * tb[IFLA_MAX+1]; |
ad02a0eb | 39 | int len = n->nlmsg_len; |
54aa4d79 | 40 | int master = -1; |
ad02a0eb | 41 | char b1[IFNAMSIZ]; |
ad02a0eb | 42 | |
96e20123 SH |
43 | if (n->nlmsg_type == NLMSG_DONE) |
44 | return 0; | |
54aa4d79 | 45 | |
ad02a0eb | 46 | len -= NLMSG_LENGTH(sizeof(*ifi)); |
54aa4d79 | 47 | if (len < 0) |
96e20123 | 48 | return -1; |
54aa4d79 | 49 | |
96e20123 SH |
50 | if (ifi->ifi_family != AF_BRIDGE && ifi->ifi_family != AF_UNSPEC) |
51 | return 0; | |
ad02a0eb | 52 | |
96e20123 SH |
53 | if (n->nlmsg_type != RTM_NEWLINK && |
54 | n->nlmsg_type != RTM_DELLINK) | |
55 | return 0; | |
ad02a0eb SH |
56 | |
57 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); | |
58 | ||
96e20123 | 59 | /* Check if we got this from bonding */ |
54aa4d79 SH |
60 | if (tb[IFLA_MASTER] && ifi->ifi_family != AF_BRIDGE) |
61 | return 0; | |
62 | ||
63 | /* Check if hearing our own state changes */ | |
64 | if (n->nlmsg_type == RTM_NEWLINK && tb[IFLA_PROTINFO]) { | |
65 | uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]); | |
66 | ||
67 | if (state != BR_STATE_DISABLED) | |
68 | return 0; | |
69 | } | |
ad02a0eb | 70 | |
ad02a0eb | 71 | if (tb[IFLA_IFNAME] == NULL) { |
54aa4d79 SH |
72 | fprintf(stderr, "BUG: nil ifname\n"); |
73 | return -1; | |
ad02a0eb SH |
74 | } |
75 | ||
76 | if (n->nlmsg_type == RTM_DELLINK) | |
54aa4d79 | 77 | fprintf(fp, "Deleted "); |
ad02a0eb SH |
78 | |
79 | fprintf(fp, "%d: %s ", ifi->ifi_index, | |
54aa4d79 | 80 | (const char*)RTA_DATA(tb[IFLA_IFNAME])); |
ad02a0eb SH |
81 | |
82 | if (tb[IFLA_MASTER]) { | |
54aa4d79 SH |
83 | master = *(int*)RTA_DATA(tb[IFLA_MASTER]); |
84 | fprintf(fp, "master %s ", if_indextoname(master, b1)); | |
ad02a0eb SH |
85 | } |
86 | ||
ad02a0eb SH |
87 | fprintf(fp, "\n"); |
88 | fflush(fp); | |
54aa4d79 SH |
89 | |
90 | ||
91 | bridge_notify(master, ifi->ifi_index, | |
92 | (n->nlmsg_type == RTM_NEWLINK), | |
968d3d40 | 93 | ifi->ifi_flags); |
54aa4d79 | 94 | |
ad02a0eb SH |
95 | return 0; |
96 | } | |
97 | ||
98 | #if 0 | |
99 | static void usage(void) | |
100 | { | |
101 | fprintf(stderr, "Usage: brmon\n"); | |
102 | exit(-1); | |
103 | } | |
104 | ||
105 | static int matches(const char *cmd, const char *pattern) | |
106 | { | |
107 | int len = strlen(cmd); | |
108 | if (len > strlen(pattern)) | |
109 | return -1; | |
110 | return memcmp(pattern, cmd, len); | |
111 | } | |
112 | ||
96e20123 SH |
113 | int |
114 | main(int argc, char **argv) | |
ad02a0eb SH |
115 | { |
116 | struct rtnl_handle rth; | |
117 | unsigned groups = ~RTMGRP_TC; | |
118 | int llink = 0; | |
119 | int laddr = 0; | |
120 | ||
121 | while (argc > 1) { | |
122 | if (matches(argv[1], "-Version") == 0) { | |
123 | printf("brmon %s\n", SNAPSHOT); | |
124 | exit(0); | |
125 | } else if (matches(argv[1], "link") == 0) { | |
96e20123 | 126 | llink=1; |
ad02a0eb SH |
127 | groups = 0; |
128 | } else if (matches(argv[1], "bridge") == 0) { | |
96e20123 | 129 | laddr=1; |
ad02a0eb SH |
130 | groups = 0; |
131 | } else if (strcmp(argv[1], "all") == 0) { | |
132 | groups = ~RTMGRP_TC; | |
133 | } else if (matches(argv[1], "help") == 0) { | |
134 | usage(); | |
135 | } else { | |
96e20123 | 136 | fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); |
ad02a0eb SH |
137 | exit(-1); |
138 | } | |
96e20123 | 139 | argc--; argv++; |
ad02a0eb SH |
140 | } |
141 | ||
142 | if (llink) | |
143 | groups |= RTMGRP_LINK; | |
144 | ||
145 | if (rtnl_open(&rth, groups) < 0) | |
146 | exit(1); | |
147 | ||
148 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { | |
149 | perror("Cannot send dump request"); | |
150 | exit(1); | |
151 | } | |
152 | ||
153 | if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) { | |
154 | fprintf(stderr, "Dump terminated\n"); | |
155 | return 1; | |
156 | } | |
157 | ||
158 | if (rtnl_listen(&rth, dump_msg, stdout) < 0) | |
159 | exit(2); | |
160 | ||
161 | exit(0); | |
162 | } | |
163 | #endif | |
164 | ||
165 | #include "bridge_ctl.h" | |
166 | #include "epoll_loop.h" | |
167 | ||
168 | struct rtnl_handle rth; | |
169 | struct epoll_event_handler br_handler; | |
170 | ||
171 | struct rtnl_handle rth_state; | |
172 | ||
173 | void br_ev_handler(uint32_t events, struct epoll_event_handler *h) | |
174 | { | |
96e20123 SH |
175 | if (rtnl_listen(&rth, dump_msg, stdout) < 0) { |
176 | fprintf(stderr, "Error on bridge monitoring socket\n"); | |
177 | exit(-1); | |
178 | } | |
ad02a0eb SH |
179 | } |
180 | ||
181 | int init_bridge_ops(void) | |
182 | { | |
96e20123 SH |
183 | if (rtnl_open(&rth, ~RTMGRP_TC) < 0) { |
184 | fprintf(stderr, "Couldn't open rtnl socket for monitoring\n"); | |
185 | return -1; | |
186 | } | |
54aa4d79 | 187 | |
96e20123 SH |
188 | if (rtnl_open(&rth_state, 0) < 0) { |
189 | fprintf(stderr, "Couldn't open rtnl socket for setting state\n"); | |
190 | return -1; | |
191 | } | |
192 | ||
193 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { | |
194 | fprintf(stderr, "Cannot send dump request: %m\n"); | |
195 | return -1; | |
196 | } | |
54aa4d79 | 197 | |
96e20123 SH |
198 | if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) { |
199 | fprintf(stderr, "Dump terminated\n"); | |
200 | return -1; | |
201 | } | |
202 | ||
203 | if (fcntl(rth.fd, F_SETFL, O_NONBLOCK) < 0) { | |
204 | fprintf(stderr, "Error setting O_NONBLOCK: %m\n"); | |
205 | return -1; | |
206 | } | |
207 | ||
208 | br_handler.fd = rth.fd; | |
209 | br_handler.arg = NULL; | |
210 | br_handler.handler = br_ev_handler; | |
54aa4d79 | 211 | |
96e20123 SH |
212 | if (add_epoll(&br_handler) < 0) |
213 | return -1; | |
54aa4d79 | 214 | |
96e20123 | 215 | return 0; |
ad02a0eb SH |
216 | } |
217 | ||
218 | /* Send message. Response is through bridge_notify */ | |
219 | void bridge_get_configuration(void) | |
220 | { | |
96e20123 SH |
221 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { |
222 | fprintf(stderr, "Cannot send dump request: %m\n"); | |
223 | } | |
ad02a0eb | 224 | } |