1 #include <sys/socket.h>
4 #include <sys/syscall.h>
6 #include <linux/rtnetlink.h>
7 #include <linux/sockios.h>
8 #include <linux/if_vlan.h>
9 #include <linux/if_bridge.h>
16 #include <netlink/msg.h>
17 #include <netlink/attr.h>
18 #include <netlink/socket.h>
19 #include <libubox/uloop.h>
25 static int sock_ioctl
= -1;
26 static struct nl_sock
*sock_rtnl
= NULL
;
27 static struct nl_sock
*sock_rtnl_event
= NULL
;
29 static void handler_rtnl_event(struct uloop_fd
*u
, unsigned int events
);
30 static int cb_rtnl_event(struct nl_msg
*msg
, void *arg
);
31 static struct uloop_fd rtnl_event
= {.cb
= handler_rtnl_event
};
32 static struct nl_cb
*nl_cb_rtnl_event
;
36 sock_ioctl
= socket(AF_LOCAL
, SOCK_DGRAM
, 0);
37 fcntl(sock_ioctl
, F_SETFD
, fcntl(sock_ioctl
, F_GETFD
) | FD_CLOEXEC
);
39 // Prepare socket for routing / address control
40 sock_rtnl
= nl_socket_alloc();
44 if (nl_connect(sock_rtnl
, NETLINK_ROUTE
))
47 // Prepare socket for link events
48 nl_cb_rtnl_event
= nl_cb_alloc(NL_CB_DEFAULT
);
49 if (!nl_cb_rtnl_event
)
52 nl_cb_set(nl_cb_rtnl_event
, NL_CB_VALID
, NL_CB_CUSTOM
,
55 sock_rtnl_event
= nl_socket_alloc();
59 if (nl_connect(sock_rtnl_event
, NETLINK_ROUTE
))
60 goto error_free_event
;
62 // Receive network link events form kernel
63 nl_socket_add_membership(sock_rtnl_event
, RTNLGRP_LINK
);
65 rtnl_event
.fd
= nl_socket_get_fd(sock_rtnl_event
);
66 uloop_fd_add(&rtnl_event
, ULOOP_READ
| ULOOP_EDGE_TRIGGER
);
71 nl_socket_free(sock_rtnl_event
);
72 sock_rtnl_event
= NULL
;
74 nl_cb_put(nl_cb_rtnl_event
);
75 nl_cb_rtnl_event
= NULL
;
77 nl_socket_free(sock_rtnl
);
82 // If socket is ready for reading parse netlink events
83 static void handler_rtnl_event(struct uloop_fd
*u
, unsigned int events
)
85 nl_recvmsgs(sock_rtnl_event
, nl_cb_rtnl_event
);
88 // Evaluate netlink messages
89 static int cb_rtnl_event(struct nl_msg
*msg
, void *arg
)
91 struct nlmsghdr
*nh
= nlmsg_hdr(msg
);
92 struct ifinfomsg
*ifi
= NLMSG_DATA(nh
);
93 struct nlattr
*nla
[__IFLA_MAX
];
95 if (nh
->nlmsg_type
!= RTM_DELLINK
&& nh
->nlmsg_type
!= RTM_NEWLINK
)
98 nlmsg_parse(nh
, sizeof(*ifi
), nla
, __IFLA_MAX
- 1, NULL
);
99 if (!nla
[IFLA_IFNAME
])
102 struct device
*dev
= device_get(RTA_DATA(nla
[IFLA_IFNAME
]), false);
106 dev
->ifindex
= ifi
->ifi_index
;
107 device_set_present(dev
, (nh
->nlmsg_type
== RTM_NEWLINK
));
113 static int system_rtnl_call(struct nl_msg
*msg
)
115 int s
= -(nl_send_auto_complete(sock_rtnl
, msg
)
116 || nl_wait_for_ack(sock_rtnl
));
121 int system_bridge_delbr(struct device
*bridge
)
123 return ioctl(sock_ioctl
, SIOCBRDELBR
, bridge
->ifname
);
126 static int system_bridge_if(const char *bridge
, struct device
*dev
, int cmd
, void *data
)
130 ifr
.ifr_ifindex
= dev
->ifindex
;
133 strncpy(ifr
.ifr_name
, bridge
, sizeof(ifr
.ifr_name
));
134 return ioctl(sock_ioctl
, cmd
, &ifr
);
137 int system_bridge_addif(struct device
*bridge
, struct device
*dev
)
139 return system_bridge_if(bridge
->ifname
, dev
, SIOCBRADDIF
, NULL
);
142 int system_bridge_delif(struct device
*bridge
, struct device
*dev
)
144 return system_bridge_if(bridge
->ifname
, dev
, SIOCBRDELIF
, NULL
);
147 static bool system_is_bridge(const char *name
, char *buf
, int buflen
)
151 snprintf(buf
, buflen
, "/sys/devices/virtual/net/%s/bridge", name
);
152 if (stat(buf
, &st
) < 0)
158 static char *system_get_bridge(const char *name
, char *buf
, int buflen
)
164 snprintf(buf
, buflen
, "/sys/devices/virtual/net/*/brif/%s/bridge", name
);
165 if (glob(buf
, GLOB_NOSORT
, NULL
, &gl
) < 0)
168 if (gl
.gl_pathc
== 0)
171 len
= readlink(gl
.gl_pathv
[0], buf
, buflen
);
176 path
= strrchr(buf
, '/');
183 static int system_if_resolve(struct device
*dev
)
186 strncpy(ifr
.ifr_name
, dev
->ifname
, sizeof(ifr
.ifr_name
));
187 if (!ioctl(sock_ioctl
, SIOCGIFINDEX
, &ifr
))
188 return ifr
.ifr_ifindex
;
193 static int system_if_flags(const char *ifname
, unsigned add
, unsigned rem
)
196 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
197 ioctl(sock_ioctl
, SIOCGIFFLAGS
, &ifr
);
198 ifr
.ifr_flags
|= add
;
199 ifr
.ifr_flags
&= ~rem
;
200 return ioctl(sock_ioctl
, SIOCSIFFLAGS
, &ifr
);
204 * Clear bridge (membership) state and bring down device
206 void system_if_clear_state(struct device
*dev
)
211 dev
->ifindex
= system_if_resolve(dev
);
215 system_if_flags(dev
->ifname
, 0, IFF_UP
);
217 if (system_is_bridge(dev
->ifname
, buf
, sizeof(buf
))) {
218 D(SYSTEM
, "Delete existing bridge named '%s'\n", dev
->ifname
);
219 system_bridge_delbr(dev
);
223 bridge
= system_get_bridge(dev
->ifname
, buf
, sizeof(buf
));
225 D(SYSTEM
, "Remove device '%s' from bridge '%s'\n", dev
->ifname
, bridge
);
226 system_bridge_if(bridge
, dev
, SIOCBRDELIF
, NULL
);
230 static inline unsigned long
231 sec_to_jiffies(int val
)
233 return (unsigned long) val
* 100;
236 int system_bridge_addbr(struct device
*bridge
, struct bridge_config
*cfg
)
238 unsigned long args
[4] = {};
240 if (ioctl(sock_ioctl
, SIOCBRADDBR
, bridge
->ifname
) < 0)
243 args
[0] = BRCTL_SET_BRIDGE_STP_STATE
;
244 args
[1] = !!cfg
->stp
;
245 system_bridge_if(bridge
->ifname
, NULL
, SIOCDEVPRIVATE
, &args
);
247 args
[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY
;
248 args
[1] = sec_to_jiffies(cfg
->forward_delay
);
249 system_bridge_if(bridge
->ifname
, NULL
, SIOCDEVPRIVATE
, &args
);
251 if (cfg
->flags
& BRIDGE_OPT_AGEING_TIME
) {
252 args
[0] = BRCTL_SET_AGEING_TIME
;
253 args
[1] = sec_to_jiffies(cfg
->ageing_time
);
254 system_bridge_if(bridge
->ifname
, NULL
, SIOCDEVPRIVATE
, &args
);
257 if (cfg
->flags
& BRIDGE_OPT_HELLO_TIME
) {
258 args
[0] = BRCTL_SET_BRIDGE_HELLO_TIME
;
259 args
[1] = sec_to_jiffies(cfg
->hello_time
);
260 system_bridge_if(bridge
->ifname
, NULL
, SIOCDEVPRIVATE
, &args
);
263 if (cfg
->flags
& BRIDGE_OPT_MAX_AGE
) {
264 args
[0] = BRCTL_SET_BRIDGE_MAX_AGE
;
265 args
[1] = sec_to_jiffies(cfg
->max_age
);
266 system_bridge_if(bridge
->ifname
, NULL
, SIOCDEVPRIVATE
, &args
);
272 static int system_vlan(struct device
*dev
, int id
)
274 struct vlan_ioctl_args ifr
= {
275 .cmd
= SET_VLAN_NAME_TYPE_CMD
,
276 .u
.name_type
= VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD
,
279 ioctl(sock_ioctl
, SIOCSIFVLAN
, &ifr
);
282 ifr
.cmd
= DEL_VLAN_CMD
;
285 ifr
.cmd
= ADD_VLAN_CMD
;
288 strncpy(ifr
.device1
, dev
->ifname
, sizeof(ifr
.device1
));
289 return ioctl(sock_ioctl
, SIOCSIFVLAN
, &ifr
);
292 int system_vlan_add(struct device
*dev
, int id
)
294 return system_vlan(dev
, id
);
297 int system_vlan_del(struct device
*dev
)
299 return system_vlan(dev
, -1);
302 int system_if_up(struct device
*dev
)
304 dev
->ifindex
= system_if_resolve(dev
);
305 return system_if_flags(dev
->ifname
, IFF_UP
, 0);
308 int system_if_down(struct device
*dev
)
310 return system_if_flags(dev
->ifname
, 0, IFF_UP
);
313 int system_if_check(struct device
*dev
)
315 device_set_present(dev
, (system_if_resolve(dev
) >= 0));
319 static int system_addr(struct device
*dev
, struct device_addr
*addr
, int cmd
)
321 int alen
= ((addr
->flags
& DEVADDR_FAMILY
) == DEVADDR_INET4
) ? 4 : 16;
322 struct ifaddrmsg ifa
= {
323 .ifa_family
= (alen
== 4) ? AF_INET
: AF_INET6
,
324 .ifa_prefixlen
= addr
->mask
,
325 .ifa_index
= dev
->ifindex
,
328 struct nl_msg
*msg
= nlmsg_alloc_simple(cmd
, 0);
332 nlmsg_append(msg
, &ifa
, sizeof(ifa
), 0);
333 nla_put(msg
, IFA_LOCAL
, alen
, &addr
->addr
);
334 return system_rtnl_call(msg
);
337 int system_add_address(struct device
*dev
, struct device_addr
*addr
)
339 return system_addr(dev
, addr
, RTM_NEWADDR
);
342 int system_del_address(struct device
*dev
, struct device_addr
*addr
)
344 return system_addr(dev
, addr
, RTM_DELADDR
);
347 static int system_rt(struct device
*dev
, struct device_route
*route
, int cmd
)
349 int alen
= ((route
->flags
& DEVADDR_FAMILY
) == DEVADDR_INET4
) ? 4 : 16;
353 have_gw
= !!route
->nexthop
.in
.s_addr
;
355 have_gw
= route
->nexthop
.in6
.s6_addr32
[0] ||
356 route
->nexthop
.in6
.s6_addr32
[1] ||
357 route
->nexthop
.in6
.s6_addr32
[2] ||
358 route
->nexthop
.in6
.s6_addr32
[3];
360 unsigned char scope
= (cmd
== RTM_DELROUTE
) ? RT_SCOPE_NOWHERE
:
361 (have_gw
) ? RT_SCOPE_UNIVERSE
: RT_SCOPE_LINK
;
364 .rtm_family
= (alen
== 4) ? AF_INET
: AF_INET6
,
365 .rtm_dst_len
= route
->mask
,
366 .rtm_table
= RT_TABLE_MAIN
,
367 .rtm_protocol
= RTPROT_BOOT
,
369 .rtm_type
= (cmd
== RTM_DELROUTE
) ? 0: RTN_UNICAST
,
372 struct nl_msg
*msg
= nlmsg_alloc_simple(cmd
, 0);
376 nlmsg_append(msg
, &rtm
, sizeof(rtm
), 0);
379 nla_put(msg
, RTA_DST
, alen
, &route
->addr
);
382 nla_put(msg
, RTA_GATEWAY
, alen
, &route
->nexthop
);
384 if (route
->flags
& DEVADDR_DEVICE
)
385 nla_put_u32(msg
, RTA_OIF
, dev
->ifindex
);
387 return system_rtnl_call(msg
);
390 int system_add_route(struct device
*dev
, struct device_route
*route
)
392 return system_rt(dev
, route
, RTM_NEWROUTE
);
395 int system_del_route(struct device
*dev
, struct device_route
*route
)
397 return system_rt(dev
, route
, RTM_DELROUTE
);
400 time_t system_get_rtime(void)
405 if (syscall(__NR_clock_gettime
, CLOCK_MONOTONIC
, &ts
) == 0)
408 if (gettimeofday(&tv
, NULL
) == 0)