]> git.ipfire.org Git - people/ms/rstp.git/blob - brmon.c
4afe5e19ea678c192c59f1c6ee0f6fababcc1b9d
[people/ms/rstp.git] / brmon.c
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
33
34 /* RFC 2863 operational status */
35 enum {
36 IF_OPER_UNKNOWN,
37 IF_OPER_NOTPRESENT,
38 IF_OPER_DOWN,
39 IF_OPER_LOWERLAYERDOWN,
40 IF_OPER_TESTING,
41 IF_OPER_DORMANT,
42 IF_OPER_UP,
43 };
44
45 /* link modes */
46 enum {
47 IF_LINK_MODE_DEFAULT,
48 IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
49 };
50
51 static const char *port_states[] = {
52 [BR_STATE_DISABLED] = "disabled",
53 [BR_STATE_LISTENING] = "listening",
54 [BR_STATE_LEARNING] = "learning",
55 [BR_STATE_FORWARDING] = "forwarding",
56 [BR_STATE_BLOCKING] = "blocking",
57 };
58
59
60 static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
61 void *arg)
62 {
63 FILE *fp = arg;
64 struct ifinfomsg *ifi = NLMSG_DATA(n);
65 struct rtattr * tb[IFLA_MAX+1];
66 int len = n->nlmsg_len;
67 char b1[IFNAMSIZ];
68 int af_family = ifi->ifi_family;
69
70 if (n->nlmsg_type == NLMSG_DONE)
71 return 0;
72
73 len -= NLMSG_LENGTH(sizeof(*ifi));
74 if (len < 0) {
75 return -1;
76 }
77
78 #if 0
79
80 if (filter.ifindex && ifi->ifi_index != filter.ifindex)
81 return 0;
82
83 if (filter.up && !(ifi->ifi_flags&IFF_UP))
84 return 0;
85 #endif
86 if (ifi->ifi_family != AF_BRIDGE && ifi->ifi_family != AF_UNSPEC)
87 return 0;
88
89 if (n->nlmsg_type != RTM_NEWLINK &&
90 n->nlmsg_type != RTM_DELLINK)
91 return 0;
92
93 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
94
95 /* Check if we got this from bonding */
96 if (tb[IFLA_MASTER] && af_family != AF_BRIDGE)
97 return 0;
98
99 /* Check for BPDU */
100 if (tb[IFLA_PRIORITY] && af_family == AF_BRIDGE) {
101 bridge_bpdu_rcv(ifi->ifi_index,
102 RTA_DATA(tb[IFLA_PRIORITY]),
103 RTA_PAYLOAD(tb[IFLA_PRIORITY]));
104 return 0;
105 }
106
107 if (tb[IFLA_IFNAME] == NULL) {
108 fprintf(stderr, "BUG: nil ifname\n");
109 return -1;
110 }
111
112 if (n->nlmsg_type == RTM_DELLINK)
113 fprintf(fp, "Deleted ");
114
115 fprintf(fp, "%d: %s ", ifi->ifi_index,
116 tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
117
118
119 if (tb[IFLA_OPERSTATE]) {
120 int state = *(int*)RTA_DATA(tb[IFLA_OPERSTATE]);
121 switch (state) {
122 case IF_OPER_UNKNOWN:
123 fprintf(fp, "Unknown "); break;
124 case IF_OPER_NOTPRESENT:
125 fprintf(fp, "Not Present "); break;
126 case IF_OPER_DOWN:
127 fprintf(fp, "Down "); break;
128 case IF_OPER_LOWERLAYERDOWN:
129 fprintf(fp, "Lowerlayerdown "); break;
130 case IF_OPER_TESTING:
131 fprintf(fp, "Testing "); break;
132 case IF_OPER_DORMANT:
133 fprintf(fp, "Dormant "); break;
134 case IF_OPER_UP:
135 fprintf(fp, "Up "); break;
136 default:
137 fprintf(fp, "State(%d) ", state);
138 }
139 }
140
141 if (tb[IFLA_MTU])
142 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
143
144 if (tb[IFLA_MASTER]) {
145 fprintf(fp, "master %s ",
146 if_indextoname(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
147 }
148
149 if (tb[IFLA_PROTINFO]) {
150 uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]);
151 if (state <= BR_STATE_BLOCKING)
152 fprintf(fp, "state %s", port_states[state]);
153 else
154 fprintf(fp, "state (%d)", state);
155 }
156
157
158 fprintf(fp, "\n");
159 fflush(fp);
160 {
161 int newlink = (n->nlmsg_type == RTM_NEWLINK);
162 int up = 0;
163 if (newlink && tb[IFLA_OPERSTATE]) {
164 int state = *(int*)RTA_DATA(tb[IFLA_OPERSTATE]);
165 up = (state == IF_OPER_UP) || (state == IF_OPER_UNKNOWN);
166 }
167
168 bridge_notify((tb[IFLA_MASTER]?*(int*)RTA_DATA(tb[IFLA_MASTER]):-1),
169 ifi->ifi_index, newlink, up);
170 }
171 return 0;
172 }
173
174 #if 0
175 static void usage(void)
176 {
177 fprintf(stderr, "Usage: brmon\n");
178 exit(-1);
179 }
180
181 static int matches(const char *cmd, const char *pattern)
182 {
183 int len = strlen(cmd);
184 if (len > strlen(pattern))
185 return -1;
186 return memcmp(pattern, cmd, len);
187 }
188
189 int
190 main(int argc, char **argv)
191 {
192 struct rtnl_handle rth;
193 unsigned groups = ~RTMGRP_TC;
194 int llink = 0;
195 int laddr = 0;
196
197 while (argc > 1) {
198 if (matches(argv[1], "-Version") == 0) {
199 printf("brmon %s\n", SNAPSHOT);
200 exit(0);
201 } else if (matches(argv[1], "link") == 0) {
202 llink=1;
203 groups = 0;
204 } else if (matches(argv[1], "bridge") == 0) {
205 laddr=1;
206 groups = 0;
207 } else if (strcmp(argv[1], "all") == 0) {
208 groups = ~RTMGRP_TC;
209 } else if (matches(argv[1], "help") == 0) {
210 usage();
211 } else {
212 fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]);
213 exit(-1);
214 }
215 argc--; argv++;
216 }
217
218 if (llink)
219 groups |= RTMGRP_LINK;
220
221 if (rtnl_open(&rth, groups) < 0)
222 exit(1);
223
224 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
225 perror("Cannot send dump request");
226 exit(1);
227 }
228
229 if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) {
230 fprintf(stderr, "Dump terminated\n");
231 return 1;
232 }
233
234 if (rtnl_listen(&rth, dump_msg, stdout) < 0)
235 exit(2);
236
237 exit(0);
238 }
239 #endif
240
241 #include "bridge_ctl.h"
242 #include "epoll_loop.h"
243
244 struct rtnl_handle rth;
245 struct epoll_event_handler br_handler;
246
247 struct rtnl_handle rth_state;
248
249 void br_ev_handler(uint32_t events, struct epoll_event_handler *h)
250 {
251 if (rtnl_listen(&rth, dump_msg, stdout) < 0) {
252 fprintf(stderr, "Error on bridge monitoring socket\n");
253 exit(-1);
254 }
255 }
256
257 int init_bridge_ops(void)
258 {
259 if (rtnl_open(&rth, ~RTMGRP_TC) < 0) {
260 fprintf(stderr, "Couldn't open rtnl socket for monitoring\n");
261 return -1;
262 }
263
264 if (rtnl_open(&rth_state, 0) < 0) {
265 fprintf(stderr, "Couldn't open rtnl socket for setting state\n");
266 return -1;
267 }
268
269 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
270 fprintf(stderr, "Cannot send dump request: %m\n");
271 return -1;
272 }
273
274 if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) {
275 fprintf(stderr, "Dump terminated\n");
276 return -1;
277 }
278
279 if (fcntl(rth.fd, F_SETFL, O_NONBLOCK) < 0) {
280 fprintf(stderr, "Error setting O_NONBLOCK: %m\n");
281 return -1;
282 }
283
284 br_handler.fd = rth.fd;
285 br_handler.arg = NULL;
286 br_handler.handler = br_ev_handler;
287
288 if (add_epoll(&br_handler) < 0)
289 return -1;
290
291 return 0;
292 }
293
294 /* Send message. Response is through bridge_notify */
295 void bridge_get_configuration(void)
296 {
297 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
298 fprintf(stderr, "Cannot send dump request: %m\n");
299 }
300 }