netifd: propagate error code on netifd_reload()
[project/netifd.git] / veth.c
1 /*
2  * netifd - network interface daemon
3  * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4  * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5  * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2
9  * as published by the Free Software Foundation
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <assert.h>
20 #include <errno.h>
21 #include <net/ethernet.h>
22
23 #ifdef linux
24 #include <netinet/ether.h>
25 #endif
26
27 #include "netifd.h"
28 #include "device.h"
29 #include "interface.h"
30 #include "system.h"
31
32 enum {
33         VETH_ATTR_MACADDR,
34         VETH_ATTR_PEER_NAME,
35         VETH_ATTR_PEER_MACADDR,
36         __VETH_ATTR_MAX
37 };
38
39 static const struct blobmsg_policy veth_attrs[__VETH_ATTR_MAX] = {
40         [VETH_ATTR_MACADDR] = { "macaddr", BLOBMSG_TYPE_STRING },
41         [VETH_ATTR_PEER_NAME]  = { "peer_name", BLOBMSG_TYPE_STRING },
42         [VETH_ATTR_PEER_MACADDR] = { "peer_macaddr", BLOBMSG_TYPE_STRING },
43 };
44
45 static const struct uci_blob_param_list veth_attr_list = {
46         .n_params = __VETH_ATTR_MAX,
47         .params = veth_attrs,
48
49         .n_next = 1,
50         .next = { &device_attr_list },
51 };
52
53 struct veth {
54         struct device dev;
55
56         device_state_cb set_state;
57
58         struct blob_attr *config_data;
59         struct veth_config config;
60 };
61
62 static int
63 veth_set_down(struct veth *veth)
64 {
65         veth->set_state(&veth->dev, false);
66         system_veth_del(&veth->dev);
67
68         return 0;
69 }
70
71 static int
72 veth_set_up(struct veth *veth)
73 {
74         int ret;
75
76         ret = system_veth_add(&veth->dev, &veth->config);
77         if (ret < 0)
78                 return ret;
79
80         ret = veth->set_state(&veth->dev, true);
81         if (ret)
82                 goto delete;
83
84         return 0;
85
86 delete:
87         system_veth_del(&veth->dev);
88         return ret;
89 }
90
91 static int
92 veth_set_state(struct device *dev, bool up)
93 {
94         struct veth *veth;
95
96         D(SYSTEM, "veth_set_state(%s, %u)\n", dev->ifname, up);
97
98         veth = container_of(dev, struct veth, dev);
99         if (up)
100                 return veth_set_up(veth);
101         else
102                 return veth_set_down(veth);
103 }
104
105 static void
106 veth_free(struct device *dev)
107 {
108         struct veth *veth;
109
110         veth = container_of(dev, struct veth, dev);
111         free(veth->config_data);
112         free(veth);
113 }
114
115 static void
116 veth_dump_info(struct device *dev, struct blob_buf *b)
117 {
118         struct veth *veth;
119
120         veth = container_of(dev, struct veth, dev);
121         if (veth->config.flags & VETH_OPT_PEER_NAME)
122                 blobmsg_add_string(b, "peer", veth->config.peer_name);
123         system_if_dump_info(dev, b);
124 }
125
126 static void
127 veth_config_init(struct device *dev)
128 {
129         device_set_present(dev, true);
130 }
131
132 static void
133 veth_apply_settings(struct veth *veth, struct blob_attr **tb)
134 {
135         struct veth_config *cfg = &veth->config;
136         struct blob_attr *cur;
137         struct ether_addr *ea;
138
139         cfg->flags = 0;
140
141         if ((cur = tb[VETH_ATTR_MACADDR]))
142         {
143                 ea = ether_aton(blobmsg_data(cur));
144                 if (ea) {
145                         memcpy(cfg->macaddr, ea, 6);
146                         cfg->flags |= VETH_OPT_MACADDR;
147                 }
148         }
149
150         if ((cur = tb[VETH_ATTR_PEER_NAME]))
151         {
152                 strncpy(cfg->peer_name, blobmsg_get_string(cur), sizeof(cfg->peer_name)-1);
153                 cfg->flags |= VETH_OPT_PEER_NAME;
154         }
155
156         if ((cur = tb[VETH_ATTR_PEER_MACADDR]))
157         {
158                 ea = ether_aton(blobmsg_data(cur));
159                 if (ea) {
160                         memcpy(cfg->peer_macaddr, ea, 6);
161                         cfg->flags |= VETH_OPT_PEER_MACADDR;
162                 }
163         }
164 }
165
166 static enum dev_change_type
167 veth_reload(struct device *dev, struct blob_attr *attr)
168 {
169         struct blob_attr *tb_dev[__DEV_ATTR_MAX];
170         struct blob_attr *tb_mv[__VETH_ATTR_MAX];
171         enum dev_change_type ret = DEV_CONFIG_APPLIED;
172         struct veth *veth;
173
174         veth = container_of(dev, struct veth, dev);
175         attr = blob_memdup(attr);
176
177         blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, tb_dev,
178                 blob_data(attr), blob_len(attr));
179         blobmsg_parse(veth_attrs, __VETH_ATTR_MAX, tb_mv,
180                 blob_data(attr), blob_len(attr));
181
182         device_init_settings(dev, tb_dev);
183         veth_apply_settings(veth, tb_mv);
184
185         if (veth->config_data) {
186                 struct blob_attr *otb_dev[__DEV_ATTR_MAX];
187                 struct blob_attr *otb_mv[__VETH_ATTR_MAX];
188
189                 blobmsg_parse(device_attr_list.params, __DEV_ATTR_MAX, otb_dev,
190                         blob_data(veth->config_data), blob_len(veth->config_data));
191
192                 if (uci_blob_diff(tb_dev, otb_dev, &device_attr_list, NULL))
193                     ret = DEV_CONFIG_RESTART;
194
195                 blobmsg_parse(veth_attrs, __VETH_ATTR_MAX, otb_mv,
196                         blob_data(veth->config_data), blob_len(veth->config_data));
197
198                 if (uci_blob_diff(tb_mv, otb_mv, &veth_attr_list, NULL))
199                     ret = DEV_CONFIG_RESTART;
200
201                 veth_config_init(dev);
202         }
203
204         free(veth->config_data);
205         veth->config_data = attr;
206         return ret;
207 }
208
209 static struct device *
210 veth_create(const char *name, struct device_type *devtype,
211         struct blob_attr *attr)
212 {
213         struct veth *veth;
214         struct device *dev = NULL;
215
216         veth = calloc(1, sizeof(*veth));
217         if (!veth)
218                 return NULL;
219
220         dev = &veth->dev;
221         device_init(dev, devtype, name);
222         dev->config_pending = true;
223
224         veth->set_state = dev->set_state;
225         dev->set_state = veth_set_state;
226
227         dev->hotplug_ops = NULL;
228
229         veth_reload(dev, attr);
230
231         return dev;
232 }
233
234 static struct device_type veth_device_type = {
235         .name = "veth",
236         .config_params = &veth_attr_list,
237         .create = veth_create,
238         .config_init = veth_config_init,
239         .reload = veth_reload,
240         .free = veth_free,
241         .dump_info = veth_dump_info,
242 };
243
244 static void __init veth_device_type_init(void)
245 {
246         device_type_add(&veth_device_type);
247 }