]> git.sur5r.net Git - ngadmin/commitdiff
Optimize port based VLAN code, send only modified VLANs
authordarkcoven <admin@darkcoven.tk>
Sun, 22 Sep 2013 13:53:28 +0000 (15:53 +0200)
committerdarkcoven <admin@darkcoven.tk>
Sun, 22 Sep 2013 13:53:28 +0000 (15:53 +0200)
lib/src/vlan.c

index 9bd14c69a21449b5bba3e5aea1bca139164c6cc9..09d685017b53374cf751478480e6e9182327ec8a 100644 (file)
@@ -117,13 +117,13 @@ end:
 
 int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
 {
-       List *attr = NULL;
+       List *conf_old = NULL, *conf_new = NULL;
        ListNode *ln;
        struct attr *at;
        struct swi_attr *sa;
-       struct attr_vlan_conf *avc;
+       struct attr_vlan_conf *avc_old, *avc_new;
        int ret = ERR_OK, port;
-       unsigned char vlan;
+       bool change;
        
        
        if (nga == NULL || ports == NULL)
@@ -135,47 +135,79 @@ int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
        
        /* if nothing is to be changed, do nothing */
        for (port = 0; port < sa->ports && ports[port] == 0; port++);
-       if (port == sa->ports )
+       if (port == sa->ports)
                goto end;
        
-       attr = createEmptyList();
-
-       if (memchr(ports, 0, sa->ports) != NULL) {
-               /* if at least one port is unchanged, we need to read old config */
-               pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
-               ret = readRequest(nga, attr);
-               if (ret != ERR_OK)
-                       goto end;
-               
-               filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
-               /* FIXME: check if the returned array effectively contains correct data */
+       /* read old config */
+       conf_old = createEmptyList();
+       pushBackList(conf_old, newEmptyAttr(ATTR_VLAN_PORT_CONF));
+       ret = readRequest(nga, conf_old);
+       if (ret != ERR_OK)
+               goto end;
+       
+       filterAttributes(conf_old, ATTR_VLAN_PORT_CONF, ATTR_END);
+       
+       /* check if the switch is in port mode */
+       if (conf_old->first == NULL) {
+               ret = ERR_INVARG;
+               goto end;
        } else {
-               /* create an empty VLAN config */
-               for (vlan = VLAN_MIN; vlan <= VLAN_PORT_MAX; vlan++) {
-                       avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
-                       avc->vlan = vlan;
-                       memset(avc->ports, 0, sa->ports);
-                       pushBackList(attr, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
+               at = conf_old->first->data;
+               if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) {
+                       ret = ERR_INVARG;
+                       goto end;
                }
        }
        
-       for (ln = attr->first; ln != NULL; ln = ln->next) {
+       /* merge old config with requested config */
+       conf_new = createEmptyList();
+       
+       for (ln = conf_old->first; ln != NULL; ln = ln->next) {
                at = ln->data;
-               avc = at->data;
+               avc_old = at->data;
+               
+               /* check if there is a change on this VLAN */
+               change = false;
+               for (port = 0; !change && port < sa->ports; port++) {
+                       if (ports[port] == 0)
+                               continue;
+                       if (ports[port] == avc_old->vlan && avc_old->ports[port] == VLAN_NO)
+                               change = true;
+                       if (ports[port] != avc_old->vlan && avc_old->ports[port] == VLAN_UNTAGGED)
+                               change = true;
+               }
+               
+               /* if the VLAN is not changed, no need to send it to the switch */
+               if (!change)
+                       continue;
+               
+               /* compute new VLAN configuration */
+               avc_new = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
+               avc_new->vlan = avc_old->vlan;
+               
                for (port = 0; port < sa->ports; port++) {
-                       if (ports[port] == avc->vlan)
-                               avc->ports[port] = VLAN_UNTAGGED;
+                       if (ports[port] == 0)
+                               avc_new->ports[port] = avc_old->ports[port];
+                       else if (ports[port] == avc_new->vlan)
+                               avc_new->ports[port] = VLAN_UNTAGGED;
                        else
-                               avc->ports[port] = VLAN_NO;
+                               avc_new->ports[port] = VLAN_NO;
                }
+               
+               pushBackList(conf_new, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc_new));
        }
        
-       ret = writeRequest(nga, attr);
-       attr = NULL;
+       /* if no VLAN is changed, no need to send anything to the switch */
+       if (conf_new->first == NULL)
+               goto end;
        
+       /* send new configuration to the switch */
+       ret = writeRequest(nga, conf_new);
+       conf_new = NULL;
        
 end:
-       destroyList(attr, (void(*)(void*))freeAttr);
+       destroyList(conf_old, (void(*)(void*))freeAttr);
+       destroyList(conf_new, (void(*)(void*))freeAttr);
        
        
        return ret;