From: darkcoven Date: Sun, 22 Sep 2013 13:53:28 +0000 (+0200) Subject: Optimize port based VLAN code, send only modified VLANs X-Git-Url: https://git.sur5r.net/?p=ngadmin;a=commitdiff_plain;h=40e4cae9c4a7127cd23eaaad319b2d7ce1c96f5c Optimize port based VLAN code, send only modified VLANs --- diff --git a/lib/src/vlan.c b/lib/src/vlan.c index 9bd14c6..09d6850 100644 --- a/lib/src/vlan.c +++ b/lib/src/vlan.c @@ -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;