]> git.ipfire.org Git - people/ms/mstpd.git/blob - brmon.c
driver hooks for creating/deleting new MSTI
[people/ms/mstpd.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 <vitas@nppfactor.kiev.ua>
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
22 #include "libnetlink.h"
23 #include "bridge_ctl.h"
24 #include "netif_utils.h"
25 #include "epoll_loop.h"
26
27 /* RFC 2863 operational status */
28 enum
29 {
30 IF_OPER_UNKNOWN,
31 IF_OPER_NOTPRESENT,
32 IF_OPER_DOWN,
33 IF_OPER_LOWERLAYERDOWN,
34 IF_OPER_TESTING,
35 IF_OPER_DORMANT,
36 IF_OPER_UP,
37 };
38
39 /* link modes */
40 enum
41 {
42 IF_LINK_MODE_DEFAULT,
43 IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
44 };
45
46 static const char *port_states[] =
47 {
48 [BR_STATE_DISABLED] = "disabled",
49 [BR_STATE_LISTENING] = "listening",
50 [BR_STATE_LEARNING] = "learning",
51 [BR_STATE_FORWARDING] = "forwarding",
52 [BR_STATE_BLOCKING] = "blocking",
53 };
54
55 static struct rtnl_handle rth;
56 static struct epoll_event_handler br_handler;
57
58 struct rtnl_handle rth_state;
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 bool newlink, up;
70 int br_index;
71
72 if(n->nlmsg_type == NLMSG_DONE)
73 return 0;
74
75 len -= NLMSG_LENGTH(sizeof(*ifi));
76 if(len < 0)
77 {
78 return -1;
79 }
80
81 if(af_family != AF_BRIDGE && af_family != AF_UNSPEC)
82 return 0;
83
84 if(n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
85 return 0;
86
87 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
88
89 /* Check if we got this from bonding */
90 if(tb[IFLA_MASTER] && af_family != AF_BRIDGE)
91 return 0;
92
93 if(tb[IFLA_IFNAME] == NULL)
94 {
95 fprintf(stderr, "BUG: nil ifname\n");
96 return -1;
97 }
98
99 if(n->nlmsg_type == RTM_DELLINK)
100 fprintf(fp, "Deleted ");
101
102 fprintf(fp, "%d: %s ", ifi->ifi_index, (char*)RTA_DATA(tb[IFLA_IFNAME]));
103
104 if(tb[IFLA_OPERSTATE])
105 {
106 int state = *(int*)RTA_DATA(tb[IFLA_OPERSTATE]);
107 switch (state)
108 {
109 case IF_OPER_UNKNOWN:
110 fprintf(fp, "Unknown ");
111 break;
112 case IF_OPER_NOTPRESENT:
113 fprintf(fp, "Not Present ");
114 break;
115 case IF_OPER_DOWN:
116 fprintf(fp, "Down ");
117 break;
118 case IF_OPER_LOWERLAYERDOWN:
119 fprintf(fp, "Lowerlayerdown ");
120 break;
121 case IF_OPER_TESTING:
122 fprintf(fp, "Testing ");
123 break;
124 case IF_OPER_DORMANT:
125 fprintf(fp, "Dormant ");
126 break;
127 case IF_OPER_UP:
128 fprintf(fp, "Up ");
129 break;
130 default:
131 fprintf(fp, "State(%d) ", state);
132 }
133 }
134
135 if(tb[IFLA_MTU])
136 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
137
138 if(tb[IFLA_MASTER])
139 {
140 fprintf(fp, "master %s ",
141 if_indextoname(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
142 }
143
144 if(tb[IFLA_PROTINFO])
145 {
146 uint8_t state = *(uint8_t *)RTA_DATA(tb[IFLA_PROTINFO]);
147 if(state <= BR_STATE_BLOCKING)
148 fprintf(fp, "state %s", port_states[state]);
149 else
150 fprintf(fp, "state (%d)", state);
151 }
152
153 fprintf(fp, "\n");
154 fflush(fp);
155
156 newlink = (n->nlmsg_type == RTM_NEWLINK);
157 up = false;
158 if(newlink && tb[IFLA_OPERSTATE])
159 {
160 int state = *(uint8_t*)RTA_DATA(tb[IFLA_OPERSTATE]);
161 up = (state == IF_OPER_UP) || (state == IF_OPER_UNKNOWN);
162 }
163
164 if(tb[IFLA_MASTER])
165 br_index = *(int*)RTA_DATA(tb[IFLA_MASTER]);
166 else if(is_bridge((char*)RTA_DATA(tb[IFLA_IFNAME])))
167 br_index = ifi->ifi_index;
168 else
169 br_index = -1;
170
171 bridge_notify(br_index, ifi->ifi_index, newlink, up);
172
173 return 0;
174 }
175
176 static inline void br_ev_handler(uint32_t events, struct epoll_event_handler *h)
177 {
178 if(rtnl_listen(&rth, dump_msg, stdout) < 0)
179 {
180 fprintf(stderr, "Error on bridge monitoring socket\n");
181 exit(-1);
182 }
183 }
184
185 int init_bridge_ops(void)
186 {
187 if(rtnl_open(&rth, ~RTMGRP_TC) < 0)
188 {
189 fprintf(stderr, "Couldn't open rtnl socket for monitoring\n");
190 return -1;
191 }
192
193 if(rtnl_open(&rth_state, 0) < 0)
194 {
195 fprintf(stderr, "Couldn't open rtnl socket for setting state\n");
196 return -1;
197 }
198
199 if(rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0)
200 {
201 fprintf(stderr, "Cannot send dump request: %m\n");
202 return -1;
203 }
204
205 if(rtnl_dump_filter(&rth, dump_msg, stdout, NULL, NULL) < 0)
206 {
207 fprintf(stderr, "Dump terminated\n");
208 return -1;
209 }
210
211 if(fcntl(rth.fd, F_SETFL, O_NONBLOCK) < 0)
212 {
213 fprintf(stderr, "Error setting O_NONBLOCK: %m\n");
214 return -1;
215 }
216
217 br_handler.fd = rth.fd;
218 br_handler.arg = NULL;
219 br_handler.handler = br_ev_handler;
220
221 if(add_epoll(&br_handler) < 0)
222 return -1;
223
224 return 0;
225 }