]> git.sur5r.net Git - ngadmin/blob - lib/src/vlan.c
Optimize port based VLAN code, send only modified VLANs
[ngadmin] / lib / src / vlan.c
1
2 #include <ngadmin.h>
3
4 #include <attr.h>
5 #include <protocol.h>
6
7 #include "lib.h"
8 #include "network.h"
9
10
11 int ngadmin_getVLANType (struct ngadmin *nga, int *t)
12 {
13         List *attr;
14         struct attr *at;
15         int ret = ERR_OK;
16         
17         
18         if (nga == NULL || t == NULL)
19                 return ERR_INVARG;
20         else if (nga->current == NULL)
21                 return ERR_NOTLOG;
22         
23         
24         attr = createEmptyList();
25         pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
26         ret=readRequest(nga, attr);
27         if (ret != ERR_OK)
28                 goto end;
29         
30         filterAttributes(attr, ATTR_VLAN_TYPE, ATTR_END);
31         
32         *t = VLAN_DISABLED;
33         
34         if (attr->first != NULL) {
35                 at = attr->first->data;
36                 *t =(int)*(char*)at->data;
37         }
38         
39         
40 end:
41         destroyList(attr, (void(*)(void*))freeAttr);
42         
43         
44         return ret;
45 }
46
47
48 int ngadmin_setVLANType (struct ngadmin *nga, int t)
49 {
50         List *attr;
51         
52         
53         if (nga == NULL || t < 1 || t > 4)
54                 return ERR_INVARG;
55         else if (nga->current == NULL)
56                 return ERR_NOTLOG;
57         
58         
59         attr = createEmptyList();
60         pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
61         
62         
63         return writeRequest(nga, attr);
64 }
65
66
67 int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports)
68 {
69         List *attr;
70         ListNode *ln;
71         struct attr *at;
72         int ret = ERR_OK;
73         struct attr_vlan_conf *avc;
74         struct swi_attr *sa;
75         int port;
76         
77         
78         if (nga == NULL || ports== NULL)
79                 return ERR_INVARG;
80         
81         sa = nga->current;
82         if (sa == NULL)
83                 return ERR_NOTLOG;
84         
85         
86         attr = createEmptyList();
87         pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
88         ret = readRequest(nga, attr);
89         if (ret != ERR_OK)
90                 goto end;
91         
92         filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
93         
94         memset(ports, 0, sa->ports);
95         
96         for (ln = attr->first; ln != NULL; ln = ln->next) {
97                 at = ln->data;
98                 avc = at->data;
99
100                 if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
101                         return ERR_INVARG;
102                 
103                 for (port = 0; port < sa->ports; port++) {
104                         if (avc->ports[port] == VLAN_UNTAGGED)
105                                 ports[port] = avc->vlan;
106                 }
107         }
108         
109         
110 end:
111         destroyList(attr, (void(*)(void*))freeAttr);
112         
113         
114         return ret;
115 }
116
117
118 int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
119 {
120         List *conf_old = NULL, *conf_new = NULL;
121         ListNode *ln;
122         struct attr *at;
123         struct swi_attr *sa;
124         struct attr_vlan_conf *avc_old, *avc_new;
125         int ret = ERR_OK, port;
126         bool change;
127         
128         
129         if (nga == NULL || ports == NULL)
130                 return ERR_INVARG;
131         
132         sa = nga->current;
133         if (sa == NULL)
134                 return ERR_NOTLOG;
135         
136         /* if nothing is to be changed, do nothing */
137         for (port = 0; port < sa->ports && ports[port] == 0; port++);
138         if (port == sa->ports)
139                 goto end;
140         
141         /* read old config */
142         conf_old = createEmptyList();
143         pushBackList(conf_old, newEmptyAttr(ATTR_VLAN_PORT_CONF));
144         ret = readRequest(nga, conf_old);
145         if (ret != ERR_OK)
146                 goto end;
147         
148         filterAttributes(conf_old, ATTR_VLAN_PORT_CONF, ATTR_END);
149         
150         /* check if the switch is in port mode */
151         if (conf_old->first == NULL) {
152                 ret = ERR_INVARG;
153                 goto end;
154         } else {
155                 at = conf_old->first->data;
156                 if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) {
157                         ret = ERR_INVARG;
158                         goto end;
159                 }
160         }
161         
162         /* merge old config with requested config */
163         conf_new = createEmptyList();
164         
165         for (ln = conf_old->first; ln != NULL; ln = ln->next) {
166                 at = ln->data;
167                 avc_old = at->data;
168                 
169                 /* check if there is a change on this VLAN */
170                 change = false;
171                 for (port = 0; !change && port < sa->ports; port++) {
172                         if (ports[port] == 0)
173                                 continue;
174                         if (ports[port] == avc_old->vlan && avc_old->ports[port] == VLAN_NO)
175                                 change = true;
176                         if (ports[port] != avc_old->vlan && avc_old->ports[port] == VLAN_UNTAGGED)
177                                 change = true;
178                 }
179                 
180                 /* if the VLAN is not changed, no need to send it to the switch */
181                 if (!change)
182                         continue;
183                 
184                 /* compute new VLAN configuration */
185                 avc_new = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
186                 avc_new->vlan = avc_old->vlan;
187                 
188                 for (port = 0; port < sa->ports; port++) {
189                         if (ports[port] == 0)
190                                 avc_new->ports[port] = avc_old->ports[port];
191                         else if (ports[port] == avc_new->vlan)
192                                 avc_new->ports[port] = VLAN_UNTAGGED;
193                         else
194                                 avc_new->ports[port] = VLAN_NO;
195                 }
196                 
197                 pushBackList(conf_new, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc_new));
198         }
199         
200         /* if no VLAN is changed, no need to send anything to the switch */
201         if (conf_new->first == NULL)
202                 goto end;
203         
204         /* send new configuration to the switch */
205         ret = writeRequest(nga, conf_new);
206         conf_new = NULL;
207         
208 end:
209         destroyList(conf_old, (void(*)(void*))freeAttr);
210         destroyList(conf_new, (void(*)(void*))freeAttr);
211         
212         
213         return ret;
214 }
215
216
217 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
218 {
219         List *attr;
220         ListNode *ln;
221         struct attr *at;
222         int ret = ERR_OK, total;
223         struct attr_vlan_conf *avc;
224         struct swi_attr *sa;
225         
226         
227         if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
228                 return ERR_INVARG;
229         
230         sa = nga->current;
231         if (sa == NULL)
232                 return ERR_NOTLOG;
233         
234         
235         total = *nb;
236         *nb = 0;
237         
238         attr = createEmptyList();
239         pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
240         ret = readRequest(nga, attr);
241         if (ret != ERR_OK)
242                 goto end;
243         
244         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
245         
246         memset(vlans, 0, total * sizeof(unsigned short));
247         memset(ports, 0, total * sa->ports);
248         
249         for (ln = attr->first; ln != NULL; ln = ln->next) {
250                 at = ln->data;
251                 avc = at->data;
252                 
253                 if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
254                         return ERR_INVARG;
255                 
256                 *vlans = avc->vlan;
257                 memcpy(ports, avc->ports, sa->ports);
258                 
259                 vlans++;
260                 ports += sa->ports;
261                 (*nb)++;
262                 
263                 if (*nb > total)
264                         break; /* no more room */
265         }
266         
267         
268 end:
269         destroyList(attr, (void(*)(void*))freeAttr);
270         
271         
272         return ret;
273 }
274
275
276 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports)
277 {
278         List *attr;
279         ListNode *ln;
280         struct attr *at;
281         int ret = ERR_OK;
282         struct attr_vlan_conf *avc;
283         
284         
285         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
286                 return ERR_INVARG;
287         else if (nga->current == NULL)
288                 return ERR_NOTLOG;
289         
290         
291         attr = createEmptyList();
292         pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
293         ret = readRequest(nga, attr);
294         if (ret != ERR_OK)
295                 goto end;
296         
297         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
298         
299         memset(ports, 0, nga->current->ports);
300         
301         for (ln = attr->first; ln != NULL; ln = ln->next) {
302                 at = ln->data;
303                 avc = at->data;
304                 if (avc->vlan == vlan) {
305                         memcpy(ports, avc->ports, nga->current->ports);
306                         break;
307                 }
308         }
309         
310         
311 end:
312         destroyList(attr, (void(*)(void*))freeAttr);
313         
314         
315         return ret;
316 }
317
318
319 int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports)
320 {
321         List *attr = NULL;
322         struct attr *at;
323         struct swi_attr *sa;
324         struct attr_vlan_conf *avc;
325         int ret = ERR_OK, port;
326         
327         
328         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
329                 return ERR_INVARG;
330         
331         sa = nga->current;
332         if (sa == NULL)
333                 return ERR_NOTLOG;
334         
335         
336         /* if nothing is to be changed, do nothing */
337         for (port = 0; port < sa->ports && ports[port] == VLAN_UNSPEC; port++);
338         if (port == sa->ports )
339                 goto end;
340         
341         
342         attr = createEmptyList();
343         avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
344         if (avc == NULL)
345                 return ERR_MEM;
346         
347         avc->vlan = vlan;
348         
349         /* if all is to be changed, we do not need to read old config */
350         if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
351                 
352                 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
353                 ret = readRequest(nga, attr);
354                 if (ret != ERR_OK)
355                         goto end;
356                 
357                 filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
358                 
359                 if (attr->first != NULL) {
360                         at = attr->first->data;
361                         memcpy(avc, at->data, sizeof(struct attr_vlan_conf) + sa->ports);
362                 }
363                 
364                 clearList(attr, (void(*)(void*))freeAttr);
365         }
366         
367         
368         /* apply changes */
369         for (port = 0; port < sa->ports; port++) {
370                 if (ports[port] != VLAN_UNSPEC)
371                         avc->ports[port] = ports[port];
372         }
373         
374         
375         pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
376         ret = writeRequest(nga, attr);
377         attr = NULL;
378         
379         
380 end:
381         destroyList(attr, (void(*)(void*))freeAttr);
382         
383         
384         return ret;
385 }
386
387
388 int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
389 {
390         List *attr;
391         
392         
393         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
394                 return ERR_INVARG;
395         else if (nga->current == NULL)
396                 return ERR_NOTLOG;
397         
398         
399         attr = createEmptyList();
400         pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
401         
402         
403         return writeRequest(nga, attr);
404 }
405
406
407 int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
408 {
409         List *attr;
410         ListNode *ln;
411         struct attr *at;
412         int ret = ERR_OK;
413         struct attr_pvid *ap;
414         
415         
416         if (nga == NULL || ports == NULL)
417                 return ERR_INVARG;
418         else if (nga->current == NULL)
419                 return ERR_NOTLOG;
420         
421         
422         attr = createEmptyList();
423         pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
424         ret = readRequest(nga, attr);
425         if (ret != ERR_OK)
426                 goto end;
427         
428         filterAttributes(attr, ATTR_VLAN_PVID, ATTR_END);
429         
430         memset(ports, 0, nga->current->ports * sizeof(unsigned short));
431         
432         for (ln = attr->first; ln != NULL; ln = ln->next) {
433                 at = ln->data;
434                 ap = at->data;
435                 ports[ap->port - 1] = ap->vlan;
436         }
437         
438         
439 end:
440         destroyList(attr, (void(*)(void*))freeAttr);
441         
442         
443         return ret;
444 }
445
446
447 int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan)
448 {
449         List *attr;
450         struct attr_pvid *ap;
451         
452         
453         if (nga == NULL || port < 1 || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
454                 return ERR_INVARG;
455         else if (nga->current == NULL)
456                 return ERR_NOTLOG;
457         else if (port > nga->current->ports)
458                 return ERR_INVARG;
459         
460         
461         attr = createEmptyList();
462         ap = malloc(sizeof(struct attr_pvid));
463         if (ap == NULL)
464                 return ERR_MEM;
465         ap->port = port;
466         ap->vlan = vlan;
467         
468         pushBackList(attr, newAttr(ATTR_VLAN_PVID, sizeof(struct attr_pvid), ap));
469         
470         
471         return writeRequest(nga, attr);
472 }
473
474