Reworking layer2 subsystem
[oonf.git] / src-plugins / eth_listener / eth_listener.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <linux/sockios.h>
43 #include <net/if.h>
44 #include <sys/ioctl.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <unistd.h>
48
49 #include "common/common_types.h"
50 #include "config/cfg_schema.h"
51 #include "core/oonf_plugins.h"
52 #include "subsystems/oonf_clock.h"
53 #include "subsystems/oonf_interface.h"
54 #include "subsystems/oonf_layer2.h"
55 #include "subsystems/oonf_timer.h"
56
57 #include "eth_listener/eth_listener.h"
58 #include "eth_listener/ethtool-copy.h"
59
60 /* definitions */
61 struct _eth_config {
62   uint64_t interval;
63 };
64
65 /* prototypes */
66 static int _init(void);
67 static void _cleanup(void);
68
69 static void _cb_transmission_event(void *);
70 static void _cb_config_changed(void);
71
72 /* configuration */
73 static struct cfg_schema_entry _eth_entries[] = {
74   CFG_MAP_CLOCK_MIN(_eth_config, interval, "interval", "60.0",
75       "Interval between two linklayer information updates", 100),
76 };
77
78 static struct cfg_schema_section _eth_section = {
79   .type = OONF_PLUGIN_GET_NAME(),
80   .cb_delta_handler = _cb_config_changed,
81   .entries = _eth_entries,
82   .entry_count = ARRAYSIZE(_eth_entries),
83 };
84
85 static struct _eth_config _config;
86
87 /* plugin declaration */
88 struct oonf_subsystem eth_listener_subsystem = {
89   .name = OONF_PLUGIN_GET_NAME(),
90   .descr = "OONF ethernet listener plugin",
91   .author = "Henning Rogge",
92
93   .cfg_section = &_eth_section,
94
95   .init = _init,
96   .cleanup = _cleanup,
97 };
98 DECLARE_OONF_PLUGIN(eth_listener_subsystem);
99
100 /* timer for generating netlink requests */
101 static struct oonf_timer_info _transmission_timer_info = {
102   .name = "nl80211 listener timer",
103   .callback = _cb_transmission_event,
104   .periodic = true,
105 };
106
107 static struct oonf_timer_entry _transmission_timer = {
108   .info = &_transmission_timer_info
109 };
110
111 static int _ioctl_fd;
112 static uint32_t _l2_origin;
113
114 static int
115 _init(void) {
116   _ioctl_fd = socket(AF_INET, SOCK_DGRAM, 0);
117   if (_ioctl_fd == -1) {
118     return -1;
119   }
120
121   oonf_timer_add(&_transmission_timer_info);
122   _l2_origin = oonf_layer2_register_origin();
123
124   return 0;
125 }
126
127 static void
128 _cleanup(void) {
129   oonf_layer2_unregister_origin(_l2_origin);
130
131   oonf_timer_stop(&_transmission_timer);
132   oonf_timer_remove(&_transmission_timer_info);
133
134   close (_ioctl_fd);
135 }
136
137 static void
138 _cb_transmission_event(void *ptr __attribute((unused))) {
139   struct oonf_layer2_net *l2net;
140   struct oonf_interface *interf;
141   struct ethtool_cmd cmd;
142   struct ifreq req;
143   int64_t ethspeed;
144   int err;
145
146   avl_for_each_element(&oonf_interface_tree, interf, _node) {
147     /* layer-2 object for this interface */
148     l2net = oonf_layer2_net_get(&interf->data.mac);
149
150     /* initialize ethtool command */
151     memset(&cmd, 0, sizeof(cmd));
152     cmd.cmd = ETHTOOL_GSET;
153
154     /* initialize interface request */
155     memset(&req, 0, sizeof(req));
156     req.ifr_data = (void *)&cmd;
157     strscpy(req.ifr_name, "eth0", IF_NAMESIZE);
158
159     /* request ethernet information from kernel */
160     err = ioctl(_ioctl_fd, SIOCETHTOOL, &req);
161     if (err != 0) {
162       if (l2net != NULL) {
163         oonf_layer2_net_remove(l2net, _l2_origin);
164       }
165       continue;
166     }
167
168     if (l2net == NULL) {
169       l2net = oonf_layer2_net_add(&interf->data.mac);
170       if (l2net == NULL) {
171         continue;
172       }
173
174       /* copy interface static values */
175       l2net->if_index = interf->data.index;
176       strscpy(l2net->if_name, interf->data.name, sizeof(l2net->if_name));
177       l2net->if_type = OONF_LAYER2_TYPE_ETHERNET;
178     }
179
180     /* get ethernet linkspeed */
181     ethspeed = ethtool_cmd_speed(&cmd);
182     ethspeed *= 1000 * 1000;
183
184     /* set corresponding database entries */
185     oonf_layer2_set_value(&l2net->neighdata[OONF_LAYER2_NEIGH_RX_BITRATE],
186         _l2_origin, ethspeed);
187     oonf_layer2_set_value(&l2net->neighdata[OONF_LAYER2_NEIGH_TX_BITRATE],
188         _l2_origin, ethspeed);
189     oonf_layer2_set_value(&l2net->data[OONF_LAYER2_NET_MAX_BITRATE],
190         _l2_origin, ethspeed);
191   }
192 }
193
194 static void
195 _cb_config_changed(void) {
196   if (cfg_schema_tobin(&_config, _eth_section.post,
197       _eth_entries, ARRAYSIZE(_eth_entries))) {
198     OONF_WARN(LOG_ETH, "Could not convert %s config to bin",
199         OONF_PLUGIN_GET_NAME());
200     return;
201   }
202
203   oonf_timer_set_ext(&_transmission_timer, 1, _config.interval);
204 }