netif_utils: correctly close fd on read error
[project/ustp.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 * Modified by Srinivas Aji <Aji_Srinivas@emc.com>
11 * for use in RSTP daemon. - 2006-09-01
12 * Modified by Vitalii Demianets <dvitasgs@gmail.com>
13 * for use in MSTP daemon. - 2011-07-18
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <netinet/in.h>
20 #include <linux/if_bridge.h>
21 #include <libubox/uloop.h>
22
23 #include "log.h"
24 #include "libnetlink.h"
25 #include "bridge_ctl.h"
26 #include "netif_utils.h"
27 #include "worker.h"
28
29 /* RFC 2863 operational status */
30 enum
31 {
32 IF_OPER_UNKNOWN,
33 IF_OPER_NOTPRESENT,
34 IF_OPER_DOWN,
35 IF_OPER_LOWERLAYERDOWN,
36 IF_OPER_TESTING,
37 IF_OPER_DORMANT,
38 IF_OPER_UP,
39 };
40
41 /* link modes */
42 enum
43 {
44 IF_LINK_MODE_DEFAULT,
45 IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
46 };
47
48 static const char *port_states[] =
49 {
50 [BR_STATE_DISABLED] = "disabled",
51 [BR_STATE_LISTENING] = "listening",
52 [BR_STATE_LEARNING] = "learning",
53 [BR_STATE_FORWARDING] = "forwarding",
54 [BR_STATE_BLOCKING] = "blocking",
55 };
56
57 static struct rtnl_handle rth;
58 static struct uloop_fd ufd;
59
60 struct rtnl_handle rth_state;
61
62 static int dump_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
63 void *arg)
64 {
65 struct ifinfomsg *ifi = NLMSG_DATA(n);
66 struct rtattr * tb[IFLA_MAX + 1];
67 int len = n->nlmsg_len;
68 char b1[IFNAMSIZ];
69 int af_family;
70 bool newlink;
71 int br_index;
72
73 if(n->nlmsg_type == NLMSG_DONE)
74 return 0;
75
76 len -= NLMSG_LENGTH(sizeof(*ifi));
77 if(len < 0)
78 {
79 return -1;
80 }
81
82 af_family = ifi->ifi_family;
83
84 if(af_family != AF_BRIDGE && af_family != AF_UNSPEC)
85 return 0;
86
87 if(n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
88 return 0;
89
90 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
91
92 /* Check if we got this from bonding */
93 if(tb[IFLA_MASTER] && af_family != AF_BRIDGE)
94 return 0;
95
96 if(tb[IFLA_IFNAME] == NULL)
97 {
98 ERROR("BUG: nil ifname\n");
99 return -1;
100 }
101
102 if(n->nlmsg_type == RTM_DELLINK)
103 LOG("Deleted ");
104
105 LOG("%d: %s ", ifi->ifi_index, (char*)RTA_DATA(tb[IFLA_IFNAME]));
106
107 if(tb[IFLA_OPERSTATE])
108 {
109 __u8 state = *(__u8*)RTA_DATA(tb[IFLA_OPERSTATE]);
110 switch (state)
111 {
112 case IF_OPER_UNKNOWN:
113 LOG("Unknown ");
114 break;
115 case IF_OPER_NOTPRESENT:
116 LOG("Not Present ");
117 break;
118 case IF_OPER_DOWN:
119 LOG("Down ");
120 break;
121 case IF_OPER_LOWERLAYERDOWN:
122 LOG("Lowerlayerdown ");
123 break;
124 case IF_OPER_TESTING:
125 LOG("Testing ");
126 break;
127 case IF_OPER_DORMANT:
128 LOG("Dormant ");
129 break;
130 case IF_OPER_UP:
131 LOG("Up ");
132 break;
133 default:
134 LOG("State(%d) ", state);
135 }
136 }
137
138 if(tb[IFLA_MTU])
139 LOG("mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
140
141 if(tb[IFLA_MASTER])
142 {
143 LOG("master %s ",
144 if_indextoname(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
145 }
146
147 if(tb[IFLA_PROTINFO])
148 {
149 uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]);
150 if(state <= BR_STATE_BLOCKING)
151 LOG("state %s", port_states[state]);
152 else
153 LOG("state (%d)", state);
154 }
155
156 newlink = (n->nlmsg_type == RTM_NEWLINK);
157
158 if(tb[IFLA_MASTER])
159 br_index = *(int*)RTA_DATA(tb[IFLA_MASTER]);
160 else if(is_bridge((char*)RTA_DATA(tb[IFLA_IFNAME])))
161 br_index = ifi->ifi_index;
162 else
163 br_index = -1;
164
165 bridge_notify(br_index, ifi->ifi_index, newlink, ifi->ifi_flags);
166
167 return 0;
168 }
169
170 void bridge_event_handler(void)
171 {
172 if(rtnl_listen(&rth, dump_msg, stdout) < 0)
173 {
174 ERROR("Error on bridge monitoring socket\n");
175 }
176 }
177
178 static void bridge_event_cb(struct uloop_fd *fd, unsigned int events)
179 {
180 struct worker_event ev = {
181 .type = WORKER_EV_BRIDGE_EVENT
182 };
183
184 worker_queue_event(&ev);
185 }
186
187 int init_bridge_ops(void)
188 {
189 if(rtnl_open(&rth, RTMGRP_LINK) < 0)
190 {
191 ERROR("Couldn't open rtnl socket for monitoring\n");
192 return -1;
193 }
194
195 if(rtnl_open(&rth_state, 0) < 0)
196 {
197 ERROR("Couldn't open rtnl socket for setting state\n");
198 return -1;
199 }
200
201 if(rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0)
202 {
203 ERROR("Cannot send dump request: %m\n");
204 return -1;
205 }
206
207 if(rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0)
208 {
209 ERROR("Dump terminated\n");
210 return -1;
211 }
212
213 if(fcntl(rth.fd, F_SETFL, O_NONBLOCK) < 0)
214 {
215 ERROR("Error setting O_NONBLOCK: %m\n");
216 return -1;
217 }
218
219 ufd.fd = rth.fd;
220 ufd.cb = bridge_event_cb;
221 uloop_fd_add(&ufd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
222 bridge_event_cb(&ufd, 0);
223
224 return 0;
225 }