]>
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 | ||
54aa4d79 SH |
33 | static int is_up(const struct ifinfomsg *ifi) |
34 | { | |
35 | return (ifi->ifi_flags & IFF_UP) && (ifi->ifi_flags & IFF_RUNNING); | |
36 | } | |
96e20123 | 37 | |
ad02a0eb SH |
38 | static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, |
39 | void *arg) | |
40 | { | |
41 | FILE *fp = arg; | |
42 | struct ifinfomsg *ifi = NLMSG_DATA(n); | |
96e20123 | 43 | struct rtattr * tb[IFLA_MAX+1]; |
ad02a0eb | 44 | int len = n->nlmsg_len; |
54aa4d79 | 45 | int master = -1; |
ad02a0eb | 46 | char b1[IFNAMSIZ]; |
ad02a0eb | 47 | |
96e20123 SH |
48 | if (n->nlmsg_type == NLMSG_DONE) |
49 | return 0; | |
54aa4d79 | 50 | |
ad02a0eb | 51 | len -= NLMSG_LENGTH(sizeof(*ifi)); |
54aa4d79 | 52 | if (len < 0) |
96e20123 | 53 | return -1; |
54aa4d79 | 54 | |
96e20123 SH |
55 | if (ifi->ifi_family != AF_BRIDGE && ifi->ifi_family != AF_UNSPEC) |
56 | return 0; | |
ad02a0eb | 57 | |
96e20123 SH |
58 | if (n->nlmsg_type != RTM_NEWLINK && |
59 | n->nlmsg_type != RTM_DELLINK) | |
60 | return 0; | |
ad02a0eb SH |
61 | |
62 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); | |
63 | ||
96e20123 | 64 | /* Check if we got this from bonding */ |
54aa4d79 SH |
65 | if (tb[IFLA_MASTER] && ifi->ifi_family != AF_BRIDGE) |
66 | return 0; | |
67 | ||
68 | /* Check if hearing our own state changes */ | |
69 | if (n->nlmsg_type == RTM_NEWLINK && tb[IFLA_PROTINFO]) { | |
70 | uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]); | |
71 | ||
72 | if (state != BR_STATE_DISABLED) | |
73 | return 0; | |
74 | } | |
ad02a0eb | 75 | |
ad02a0eb | 76 | if (tb[IFLA_IFNAME] == NULL) { |
54aa4d79 SH |
77 | fprintf(stderr, "BUG: nil ifname\n"); |
78 | return -1; | |
ad02a0eb SH |
79 | } |
80 | ||
81 | if (n->nlmsg_type == RTM_DELLINK) | |
54aa4d79 | 82 | fprintf(fp, "Deleted "); |
ad02a0eb SH |
83 | |
84 | fprintf(fp, "%d: %s ", ifi->ifi_index, | |
54aa4d79 | 85 | (const char*)RTA_DATA(tb[IFLA_IFNAME])); |
ad02a0eb SH |
86 | |
87 | if (tb[IFLA_MASTER]) { | |
54aa4d79 SH |
88 | master = *(int*)RTA_DATA(tb[IFLA_MASTER]); |
89 | fprintf(fp, "master %s ", if_indextoname(master, b1)); | |
ad02a0eb SH |
90 | } |
91 | ||
ad02a0eb SH |
92 | fprintf(fp, "\n"); |
93 | fflush(fp); | |
54aa4d79 SH |
94 | |
95 | ||
96 | bridge_notify(master, ifi->ifi_index, | |
97 | (n->nlmsg_type == RTM_NEWLINK), | |
98 | is_up(ifi)); | |
99 | ||
ad02a0eb SH |
100 | return 0; |
101 | } | |
102 | ||
103 | #if 0 | |
104 | static void usage(void) | |
105 | { | |
106 | fprintf(stderr, "Usage: brmon\n"); | |
107 | exit(-1); | |
108 | } | |
109 | ||
110 | static int matches(const char *cmd, const char *pattern) | |
111 | { | |
112 | int len = strlen(cmd); | |
113 | if (len > strlen(pattern)) | |
114 | return -1; | |
115 | return memcmp(pattern, cmd, len); | |
116 | } | |
117 | ||
96e20123 SH |
118 | int |
119 | main(int argc, char **argv) | |
ad02a0eb SH |
120 | { |
121 | struct rtnl_handle rth; | |
122 | unsigned groups = ~RTMGRP_TC; | |
123 | int llink = 0; | |
124 | int laddr = 0; | |
125 | ||
126 | while (argc > 1) { | |
127 | if (matches(argv[1], "-Version") == 0) { | |
128 | printf("brmon %s\n", SNAPSHOT); | |
129 | exit(0); | |
130 | } else if (matches(argv[1], "link") == 0) { | |
96e20123 | 131 | llink=1; |
ad02a0eb SH |
132 | groups = 0; |
133 | } else if (matches(argv[1], "bridge") == 0) { | |
96e20123 | 134 | laddr=1; |
ad02a0eb SH |
135 | groups = 0; |
136 | } else if (strcmp(argv[1], "all") == 0) { | |
137 | groups = ~RTMGRP_TC; | |
138 | } else if (matches(argv[1], "help") == 0) { | |
139 | usage(); | |
140 | } else { | |
96e20123 | 141 | fprintf(stderr, "Argument \"%s\" is unknown, try \"rtmon help\".\n", argv[1]); |
ad02a0eb SH |
142 | exit(-1); |
143 | } | |
96e20123 | 144 | argc--; argv++; |
ad02a0eb SH |
145 | } |
146 | ||
147 | if (llink) | |
148 | groups |= RTMGRP_LINK; | |
149 | ||
150 | if (rtnl_open(&rth, groups) < 0) | |
151 | exit(1); | |
152 | ||
153 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { | |
154 | perror("Cannot send dump request"); | |
155 | exit(1); | |
156 | } | |
157 | ||
158 | if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) { | |
159 | fprintf(stderr, "Dump terminated\n"); | |
160 | return 1; | |
161 | } | |
162 | ||
163 | if (rtnl_listen(&rth, dump_msg, stdout) < 0) | |
164 | exit(2); | |
165 | ||
166 | exit(0); | |
167 | } | |
168 | #endif | |
169 | ||
170 | #include "bridge_ctl.h" | |
171 | #include "epoll_loop.h" | |
172 | ||
173 | struct rtnl_handle rth; | |
174 | struct epoll_event_handler br_handler; | |
175 | ||
176 | struct rtnl_handle rth_state; | |
177 | ||
178 | void br_ev_handler(uint32_t events, struct epoll_event_handler *h) | |
179 | { | |
96e20123 SH |
180 | if (rtnl_listen(&rth, dump_msg, stdout) < 0) { |
181 | fprintf(stderr, "Error on bridge monitoring socket\n"); | |
182 | exit(-1); | |
183 | } | |
ad02a0eb SH |
184 | } |
185 | ||
186 | int init_bridge_ops(void) | |
187 | { | |
96e20123 SH |
188 | if (rtnl_open(&rth, ~RTMGRP_TC) < 0) { |
189 | fprintf(stderr, "Couldn't open rtnl socket for monitoring\n"); | |
190 | return -1; | |
191 | } | |
54aa4d79 | 192 | |
96e20123 SH |
193 | if (rtnl_open(&rth_state, 0) < 0) { |
194 | fprintf(stderr, "Couldn't open rtnl socket for setting state\n"); | |
195 | return -1; | |
196 | } | |
197 | ||
198 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { | |
199 | fprintf(stderr, "Cannot send dump request: %m\n"); | |
200 | return -1; | |
201 | } | |
54aa4d79 | 202 | |
96e20123 SH |
203 | if (rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0) { |
204 | fprintf(stderr, "Dump terminated\n"); | |
205 | return -1; | |
206 | } | |
207 | ||
208 | if (fcntl(rth.fd, F_SETFL, O_NONBLOCK) < 0) { | |
209 | fprintf(stderr, "Error setting O_NONBLOCK: %m\n"); | |
210 | return -1; | |
211 | } | |
212 | ||
213 | br_handler.fd = rth.fd; | |
214 | br_handler.arg = NULL; | |
215 | br_handler.handler = br_ev_handler; | |
54aa4d79 | 216 | |
96e20123 SH |
217 | if (add_epoll(&br_handler) < 0) |
218 | return -1; | |
54aa4d79 | 219 | |
96e20123 | 220 | return 0; |
ad02a0eb SH |
221 | } |
222 | ||
223 | /* Send message. Response is through bridge_notify */ | |
224 | void bridge_get_configuration(void) | |
225 | { | |
96e20123 SH |
226 | if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { |
227 | fprintf(stderr, "Cannot send dump request: %m\n"); | |
228 | } | |
ad02a0eb | 229 | } |