socsvn commit: r337258 - in soc2018/sduo/head/sys: dev/vale_vlan modules/vale_vlan net

sduo at FreeBSD.org sduo at FreeBSD.org
Mon May 28 20:05:55 UTC 2018


Author: sduo
Date: Mon May 28 20:05:50 2018
New Revision: 337258
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=337258

Log:
  VLAN can now be created, and modified, through system calls. sys/net/vale_vlan_user.h contains the data structures passed between user and kernel space.

Added:
  soc2018/sduo/head/sys/net/vale_vlan_user.h
Modified:
  soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan.c
  soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan_freebsd.c
  soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan_kern.h
  soc2018/sduo/head/sys/modules/vale_vlan/Makefile

Modified: soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan.c
==============================================================================
--- soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan.c	Mon May 28 19:59:53 2018	(r337257)
+++ soc2018/sduo/head/sys/dev/vale_vlan/vale_vlan.c	Mon May 28 20:05:50 2018	(r337258)
@@ -146,8 +146,6 @@
 
 
 
-#define MAX_VLAN_ID 4096
-
 struct vlan_lookup_data {
 	uint32_t trunk_port;
 	uint16_t port_to_vlan[NM_BDG_MAXPORTS];
@@ -156,6 +154,95 @@
 
 
 
+/* must be called with GLOBAL_LOCK */
+static void
+initialize_lookup_data(struct vlan_lookup_data *l_data)
+{
+	int i;
+
+	l_data->trunk_port = NM_BDG_NOPORT;
+	for (i = 0; i < NM_BDG_MAXPORTS; ++i) {
+		l_data->port_to_vlan[i] = 0x000;
+	}
+	for (i = 0; i < MAX_VLAN_ID; ++i) {
+		l_data->vlan_to_port[i] = NM_BDG_NOPORT;
+	}
+}
+
+
+
+struct port_elem {
+	struct port port_desc;
+	vv_list_entry(port_elem) list;
+};
+
+
+
+/* for each vlan conf there is only one 'modified bridge',
+ * therefore we can store a lookup data structure directly inside
+ * the struct which describes the configuration
+ */
+struct vale_vlan_conf {
+	struct vlan_lookup_data l_data;
+	char conf_name[NETMAP_REQ_IFNAMSIZ];
+	void *vlan_bdg_auth_tokens[MAX_VLAN_ID];
+	void *mod_bdg_auth_token;
+	uint32_t number_of_ports[MAX_VLAN_ID];
+	vv_list_declare(list_head, port_elem) port_list;
+};
+
+
+
+/* there is one 'vlan_id bridge' with a specific vlan_id per configuration,
+ * therefore we only need the configuration name and vlan_id to create
+ * a unique bridge name
+ */
+static inline void
+get_vlan_bdg_name(char *bridge_name, size_t len, const char *conf_name,
+	uint16_t vlan_id)
+{
+
+	snprintf(bridge_name, len, "valeV%d%s:", vlan_id, conf_name);
+}
+
+
+
+static inline void
+get_ap_name(char *port_name, size_t len, const char *conf_name,
+	uint16_t vlan_id)
+{
+
+	snprintf(port_name, len, "%sAP%d", conf_name, vlan_id);
+}
+
+
+
+/* there is one 'modified bridge' per configuration, therefore we
+ * only need the configuration name to create a unique bridge name
+ */
+static inline void
+get_modified_bdg_name(char *bridge_name, size_t len, const char *conf_name)
+{
+
+	snprintf(bridge_name, len, "valeV%sTP:", conf_name);
+}
+
+
+
+static void
+initialize_conf(struct vale_vlan_conf *conf)
+{
+
+	initialize_lookup_data(&(conf->l_data));
+	conf->conf_name[0] = '\0';
+	bzero(conf->vlan_bdg_auth_tokens, sizeof(conf->vlan_bdg_auth_tokens));
+	conf->mod_bdg_auth_token = NULL;
+	bzero(conf->number_of_ports, sizeof(conf->number_of_ports));
+	vv_list_head_init(&conf->port_list);
+}
+
+
+
 static uint32_t
 vlan_lookup(struct nm_bdg_fwd *ft, uint8_t *dst_ring,
 	struct netmap_vp_adapter *vpna, void *lookup_data)
@@ -200,19 +287,240 @@
 
 
 
-/* must be called with GLOBAL_LOCK */
-static void
-initialize_lookup_data(struct vlan_lookup_data *l_data)
+static inline int
+modify_bdg(struct vale_vlan_conf *conf, const char *bdg_name)
+{
+
+	D("Trying to modify bdg '%s' for conf '%s'", bdg_name, conf->conf_name);
+	return netmap_bdg_regops(bdg_name, &vlan_ops, &conf->l_data,
+		conf->mod_bdg_auth_token);
+}
+
+
+
+static inline int
+reset_bdg(struct vale_vlan_conf *conf, const char *bdg_name)
+{
+
+	D("Trying to reset bdg '%s' for conf '%s'", bdg_name, conf->conf_name);
+	return netmap_bdg_regops(bdg_name, NULL, NULL,
+		conf->mod_bdg_auth_token);
+}
+
+
+
+#define MAX_VLAN_CONFS 4
+/* used to access currently active vlan confs */
+static uint16_t vlan_conf_index[MAX_VLAN_CONFS];
+static struct vale_vlan_conf vlan_confs[MAX_VLAN_CONFS];
+static uint16_t active_vlan_conf = 0;
+
+
+
+/* Fails if conf alredy exists or we're out of space */
+static int
+vale_vlan_create_conf(const char *conf_name, uint16_t *conf_index)
 {
+	uint16_t free_conf = MAX_VLAN_CONFS;
+	char modified_bdg_name[IF_NAMESIZE];
+	struct vale_vlan_conf *conf = NULL;
+	void *auth_token = NULL;
+	int ret = 0;
 	int i;
 
-	l_data->trunk_port = NM_BDG_NOPORT;
-	for (i = 0; i < NM_BDG_MAXPORTS; ++i) {
-		l_data->port_to_vlan[i] = 0x000;
+	if (active_vlan_conf == MAX_VLAN_CONFS) {
+		nm_prinf("vale_vlan: maximum number of"
+			"configurations reached\n");
+		return ENOMEM;
+	}
+
+	for (i = 0; i < MAX_VLAN_CONFS; ++i) {
+		if (strcmp(vlan_confs[i].conf_name, conf_name) == 0) {
+			nm_prinf("vale_vlan: a configuration named"
+				"'%s' alredy exists\n", conf_name);
+			return EEXIST;
+		} else if (vlan_confs[i].conf_name[0] == '\0') {
+			/* a free slot is represented by an empty conf_name */
+			free_conf = i;
+		}
+	}
+
+	/* create bridge in exclusive mode */
+	get_modified_bdg_name(modified_bdg_name, sizeof(modified_bdg_name),
+		conf_name);
+	auth_token = netmap_bdg_create(modified_bdg_name, &ret);
+	if (auth_token == NULL || ret != 0) {
+		D("Error %d during bridge '%s' creation",
+			ret, modified_bdg_name);
+		return ret;
+	}
+
+	vlan_conf_index[active_vlan_conf++] = free_conf;
+	conf = &vlan_confs[free_conf];
+	initialize_conf(conf);
+	strncpy(conf->conf_name, conf_name, sizeof(conf->conf_name));
+	conf->mod_bdg_auth_token = auth_token;
+	*conf_index = free_conf;
+
+	ret = modify_bdg(conf, modified_bdg_name);
+	if (ret) {
+		int ret2;
+		D("Error %d during bridge '%s' regops()",
+			ret, modified_bdg_name);
+		ret2 = netmap_bdg_destroy(modified_bdg_name,
+			conf->mod_bdg_auth_token);
+		if (ret2) {
+			/* cannot happen */
+			D("Error %d during bridge '%s' destroy(), "
+				"this should never happen",
+				ret2, modified_bdg_name);
+		}
+		initialize_conf(conf);
+		--active_vlan_conf;
+		return ret;
+	}
+	vv_try_module_get();
+
+	nm_prinf("vale_vlan: successfully created "
+		"configuration '%s'\n", conf_name);
+	return 0;
+}
+
+
+
+/* Fails if the conf doesn't exist
+ *
+ * must be called with GLOBAL_LOCK
+ */
+static int
+vale_vlan_select_conf(const char *conf_name, uint16_t *conf_index)
+{
+	int i;
+
+	for (i = 0; i < active_vlan_conf; ++i) {
+		int index = vlan_conf_index[i];
+		if (strcmp(vlan_confs[index].conf_name, conf_name) == 0) {
+			*conf_index = index;
+			nm_prinf("vale_vlan: successfully selected "
+				"configuration '%s'\n", conf_name);
+			return 0;
+		}
+	}
+
+	nm_prinf("vale_vlan: a configuration named '%s' doesn't exist\n",
+		conf_name);
+	return ENXIO;
+}
+
+
+
+/* Fails if the conf doesn't exist or the modified bridge isn't empty
+ *
+ * must be called with GLOBAL_LOCK
+ */
+static int
+vale_vlan_delete_conf(const char *conf_name)
+{
+	uint16_t conf_index = MAX_VLAN_CONFS;
+	char modified_bdg_name[IF_NAMESIZE];
+	struct vale_vlan_conf *conf = NULL;
+	uint16_t i;
+	int ret;
+
+	for (i = 0; i < active_vlan_conf; ++i) {
+		int index = vlan_conf_index[i];
+		if (strcmp(vlan_confs[index].conf_name, conf_name) == 0) {
+			conf = &vlan_confs[index];
+			conf_index = i;
+			break;
+		}
+	}
+
+	if (!conf || i == active_vlan_conf) {
+		/* conf doesn't exist */
+		return ENXIO;
 	}
+
+	/* redundant check */
 	for (i = 0; i < MAX_VLAN_ID; ++i) {
-		l_data->vlan_to_port[i] = NM_BDG_NOPORT;
+		if (conf->number_of_ports[i] != 0) {
+			D("conf->number_of_ports[%d] = %d",
+				i, conf->number_of_ports[i]);
+			return EBUSY;
+		}
+	}
+
+	get_modified_bdg_name(modified_bdg_name, sizeof(modified_bdg_name),
+		conf_name);
+	ret = netmap_bdg_destroy(modified_bdg_name,
+		conf->mod_bdg_auth_token);
+	if (ret) {
+		/* cannot happen (?) */
+		D("Error %d during bridge '%s' destroy(), SHOULD NOT HAPPEN",
+			ret, modified_bdg_name);
+		return ret;
 	}
+
+	conf->conf_name[0] = '\0';	/* marks conf slot as free */
+	vlan_conf_index[conf_index] = vlan_conf_index[--active_vlan_conf];
+	vv_module_put();
+	return 0;
+}
+
+
+/* returns 0 if conf_index isn't a possible index or if 
+ * the conf entry isn't in use
+ *
+ * must be called with GLOBAL_LOCK
+ */
+static int
+does_conf_exist(int conf_index)
+{
+
+	if (conf_index < 0 || conf_index >= MAX_VLAN_CONFS) {
+		return 0;
+	}
+	return vlan_confs[conf_index].conf_name[0] != '\0';
+}
+
+
+
+#define NM_API_VERSION 12
+
+
+
+static void *
+modify_trunk_port(void *private_data, void *callback_data, int *error)
+{
+	struct vlan_lookup_data *l_data = private_data;
+	uint32_t *new_trunk_port = callback_data;
+
+	l_data->trunk_port = *new_trunk_port;
+	*error = 0;
+	return l_data;
+}
+
+
+
+struct mod_access_port {
+	uint32_t old_port_index;
+	uint32_t new_port_index;
+	uint16_t old_vlan_id;
+	uint16_t new_vlan_id;
+};
+
+
+
+static void *
+modify_access_port(void *private_data, void *callback_data, int *error)
+{
+	struct vlan_lookup_data *l_data = private_data;
+	struct mod_access_port *mod = callback_data;
+
+	l_data->port_to_vlan[mod->old_port_index] = mod->new_vlan_id;
+	l_data->vlan_to_port[mod->old_vlan_id] = mod->new_port_index;
+	*error = 0;
+	return l_data;
 }
 
 
@@ -227,7 +535,7 @@
 	D("Trying to create port '%s'", name);
 
 	bzero(&hdr, sizeof(hdr));
-	hdr.nr_version = NETMAP_API;
+	hdr.nr_version = NM_API_VERSION;
 	hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
 	strncpy(hdr.nr_name, name, sizeof(hdr.nr_name));
 
@@ -264,6 +572,54 @@
 
 
 static int
+attach_port_list(struct vale_vlan_conf *conf, const char *bdg_name,
+    const char *port_name, uint8_t port_type, uint16_t vlan_id)
+{
+	struct port_elem *p_elem = NULL;
+
+	p_elem = vv_malloc(sizeof(struct port_elem));
+	if (!p_elem) {
+		return EFAULT;
+	}
+
+	vv_list_elem_init(p_elem, list);
+	p_elem->port_desc.vlan_id = vlan_id;
+	p_elem->port_desc.port_type = port_type;
+	snprintf(p_elem->port_desc.bdg_name,
+		sizeof(p_elem->port_desc.bdg_name), "%s", bdg_name);
+	snprintf(p_elem->port_desc.port_name,
+		sizeof(p_elem->port_desc.port_name), "%s", port_name);
+	vv_list_insert_head(&conf->port_list, p_elem, list);
+	return 0;
+}
+
+
+
+static int
+detach_port_list(struct vale_vlan_conf *conf, const char *port_name)
+{
+	struct port_elem *cursor = NULL;
+	struct port_elem *next = NULL;
+
+	vv_list_foreach_safe(cursor, &conf->port_list, list, next) {
+		if (strcmp(cursor->port_desc.port_name, port_name) == 0) {
+			vv_list_remove(cursor, list);
+			vv_free(cursor);
+			return 0;
+		}
+	}
+
+	return ENXIO;
+}
+
+
+
+static int detach_trunk_port(struct vale_vlan_conf *, const char *, uint16_t);
+static int detach_vlan_port(struct vale_vlan_conf *, const char *, uint16_t);
+
+
+
+static int
 attach_port(const char *bdg_name, const char *port_name, void *auth_token,
 	uint32_t *port_index)
 {
@@ -276,7 +632,7 @@
 	nmr_att.reg.nr_mode = NR_REG_ALL_NIC;
 
 	bzero(&hdr, sizeof(hdr));
-	hdr.nr_version = NETMAP_API;
+	hdr.nr_version = NM_API_VERSION;
 	hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
 	hdr.nr_body = (uint64_t)&nmr_att;
 	snprintf(hdr.nr_name, sizeof(hdr.nr_name), "%s%s", bdg_name, port_name);
@@ -286,9 +642,7 @@
 		vv_try_module_get();
 
 	}
-	if (port_index != NULL) {
-		*port_index = nmr_att.port_index;
-	}
+	*port_index = nmr_att.port_index;
 	return ret;
 }
 
@@ -306,7 +660,7 @@
 	bzero(&nmr_det, sizeof(nmr_det));
 
 	bzero(&hdr, sizeof(hdr));
-	hdr.nr_version = NETMAP_API;
+	hdr.nr_version = NM_API_VERSION;
 	hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
 	hdr.nr_body = (uint64_t)&nmr_det;
 	snprintf(hdr.nr_name, sizeof(hdr.nr_name), "%s%s", bdg_name, port_name);
@@ -315,214 +669,707 @@
 	if (ret == 0) {
 		vv_module_put();
 	}
-	if (port_index != NULL) {
-		*port_index = nmr_det.port_index;
+	*port_index = nmr_det.port_index;
+	return ret;
+}
+
+
+
+static int
+attach_vlan_port(struct vale_vlan_conf *conf, const char *port_name,
+	uint16_t vlan_id)
+{
+	void *vlan_bdg_auth_token = conf->vlan_bdg_auth_tokens[vlan_id];
+	uint32_t port_index = NM_BDG_NOPORT;
+	char modified_bdg_name[IF_NAMESIZE];
+	char vlan_bdg_name[IF_NAMESIZE];
+	struct mod_access_port mod_ap;
+	char ap_name[IF_NAMESIZE];
+	int ret = 0;
+
+	D("Trying to attach port '%s' with vlan id: %d to conf '%s'",
+		port_name, vlan_id, conf->conf_name);
+	if (vlan_id == 0x000 || vlan_id == 0xFFF) {
+		return EINVAL;
+	}
+	get_modified_bdg_name(modified_bdg_name, sizeof(modified_bdg_name),
+		conf->conf_name);
+	get_vlan_bdg_name(vlan_bdg_name, sizeof(vlan_bdg_name), conf->conf_name,
+		vlan_id);
+
+	if (conf->number_of_ports[vlan_id] == 0) {
+		/* we need to create a bridge in exclusive mode */
+		vlan_bdg_auth_token = netmap_bdg_create(vlan_bdg_name, &ret);
+		if (vlan_bdg_auth_token == NULL || ret != 0) {
+			return ret;
+		}
+
+		conf->vlan_bdg_auth_tokens[vlan_id] = vlan_bdg_auth_token;
+	}
+
+	ret = attach_port(vlan_bdg_name, port_name, vlan_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		goto l_destroy_vlan_bdg;
+	}
+
+	if (++conf->number_of_ports[vlan_id] != 1) {
+		/* an access port has alredy been created and attached to the
+		 * modified bridge
+		 */
+		return ret;
+	}
+
+	/* we need to create an access port and attach it
+	 * to the modified bridge
+	 */
+	get_ap_name(ap_name, sizeof(ap_name), conf->conf_name, vlan_id);
+	ret = create_vale_port(ap_name);
+	if (ret) {
+		goto l_detach_vlan_port;
+	}
+
+	ret = attach_port(vlan_bdg_name, ap_name, vlan_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		goto l_destroy_access_port;
+	}
+
+	ret = attach_port(modified_bdg_name, ap_name,
+		conf->mod_bdg_auth_token, &port_index);
+	if (ret) {
+		goto l_detach_access_port_vlan_bdg;
+	}
+
+	/* this can fail only if bdg_name doesn't exist or hasn't been modified
+	 * by us, and in either case we would have alredy failed one of our
+	 * previous call
+	 */
+	mod_ap.old_port_index = mod_ap.new_port_index = port_index;
+	mod_ap.old_vlan_id = mod_ap.new_vlan_id = vlan_id;
+	nm_bdg_update_private_data(modified_bdg_name, modify_access_port,
+		&mod_ap, conf->mod_bdg_auth_token);
+
+	return ret;
+
+l_detach_access_port_vlan_bdg:
+	/* cannot fail */
+	detach_port(vlan_bdg_name, ap_name, vlan_bdg_auth_token, &port_index);
+
+l_destroy_access_port:
+	/* cannot fail */
+	destroy_vale_port(ap_name);
+
+l_detach_vlan_port:
+	/* cannot fail */
+	detach_port(vlan_bdg_name, port_name, vlan_bdg_auth_token, &port_index);
+	--conf->number_of_ports[vlan_id];
+
+l_destroy_vlan_bdg:
+	if (conf->number_of_ports[vlan_id] == 0) {
+		/* we need to destroy the vlan bridge only when we fail
+		 * something after creating it
+		 */
+		conf->vlan_bdg_auth_tokens[vlan_id] = NULL;
+		/* cannot fail */
+		netmap_bdg_destroy(vlan_bdg_name, vlan_bdg_auth_token);
+	}
+
+	return ret;
+}
+
+
+
+static int
+attach_trunk_port(struct vale_vlan_conf *conf, const char *port_name,
+	uint16_t vlan_id)
+{
+	uint32_t port_index = NM_BDG_NOPORT;
+	char mod_bdg_name[IF_NAMESIZE];
+	int ret = 0;
+
+	if (vlan_id != 0xFFF || conf->l_data.trunk_port != NM_BDG_NOPORT) {
+		return EINVAL;
 	}
+
+	get_modified_bdg_name(mod_bdg_name, sizeof(mod_bdg_name),
+		conf->conf_name);
+	ret = attach_port(mod_bdg_name, port_name, conf->mod_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		return ret;
+	}
+
+	/* this can't fail because we have the bridge in exclusive mode */
+	nm_bdg_update_private_data(mod_bdg_name, modify_trunk_port,
+		&port_index, conf->mod_bdg_auth_token);
 	return ret;
 }
 
 
-#define VALE_V1A "valev1A:"
-#define VALE_V1B "valev1B:"
-#define VALE_V2A "valev2A:"
-#define VALE_V2B "valev2B:"
-#define VALE_V500B "valev500B:"
-#define VALE_MODA "valemodA:"
-#define VALE_MODB "valemodB:"
 
-void *token_v1_A;
-void *token_v1_B;
-void *token_v2_A;
-void *token_v2_B;
-void *token_v500_B;
-void *token_A;
-void *token_B;
 
-struct vlan_lookup_data data_A;
-struct vlan_lookup_data data_B;
+static int
+action_attach(struct vale_vlan_conf *conf, const char *port_name,
+	uint8_t port_type, uint16_t vlan_id)
+{
+	char bdg_name[IF_NAMESIZE];
+	int ret = 0;
 
+	switch (port_type){
+	case TRUNK_PORT:
+		ret = attach_trunk_port(conf, port_name, vlan_id);
+		if (ret) {
+			return ret;
+		}
+		get_modified_bdg_name(bdg_name, sizeof(bdg_name),
+			conf->conf_name);
+		break;
 
+	case VLAN_PORT:
+		ret = attach_vlan_port(conf, port_name, vlan_id);
+		if (ret) {
+			return ret;
+		}
+		get_vlan_bdg_name(bdg_name, sizeof(bdg_name), conf->conf_name,
+			vlan_id);
+		break;
 
-static void
-create_ports(void)
+	default:
+		return EINVAL;
+	}
+
+
+	ret = attach_port_list(conf, bdg_name, port_name, port_type, vlan_id);
+	if (ret) {
+		switch (port_type){
+		case TRUNK_PORT:
+			/* cannot fail */
+			detach_trunk_port(conf, port_name, vlan_id);
+			break;
+
+		case VLAN_PORT:
+			/* cannot fail */
+			detach_vlan_port(conf, port_name, vlan_id);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+
+
+static int
+action_create_and_attach(struct vale_vlan_conf *conf, const char *port_name,
+	uint8_t port_type, uint16_t vlan_id)
 {
+	int ret = 0;
+
+	ret = create_vale_port(port_name);
+	if (ret) {
+		return ret;
+	}
+
+	ret = action_attach(conf, port_name, port_type, vlan_id);
+	if (ret) {
+		/* cannot fail */
+		destroy_vale_port(port_name);
+	}
 
-	create_vale_port("v1");
-	create_vale_port("v2");
-	create_vale_port("v3");
-	create_vale_port("v4");
-	create_vale_port("v5");
-	create_vale_port("v6");
-	create_vale_port("vtp");
-	create_vale_port("ap1A");
-	create_vale_port("ap1B");
-	create_vale_port("ap2A");
-	create_vale_port("ap2B");
-	create_vale_port("ap500B");
+	return ret;
 }
 
 
 
-static void
-create_bridges(void)
+static int
+detach_trunk_port(struct vale_vlan_conf *conf, const char *port_name,
+	uint16_t vlan_id)
 {
-	int ret;
+	uint32_t port_index = NM_BDG_NOPORT;
+	char bdg_name[IF_NAMESIZE];
+	int ret = 0;
+
+	if (vlan_id != 0xFFF) {
+		return EINVAL;
+	}
 
-	token_A = netmap_bdg_create(VALE_MODA, &ret);
-	token_B = netmap_bdg_create(VALE_MODB, &ret);
-	token_v1_A = netmap_bdg_create(VALE_V1A, &ret);
-	token_v1_B = netmap_bdg_create(VALE_V1B, &ret);
-	token_v2_A = netmap_bdg_create(VALE_V2A, &ret);
-	token_v2_B = netmap_bdg_create(VALE_V2B, &ret);
-	token_v500_B = netmap_bdg_create(VALE_V500B, &ret);
+	get_modified_bdg_name(bdg_name, sizeof(bdg_name), conf->conf_name);
+	ret = detach_port(bdg_name, port_name, conf->mod_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		return ret;
+	}
+
+	port_index = NM_BDG_NOPORT;
+	/* this can't fail because we have the bridge in exlusive mode */
+	nm_bdg_update_private_data(bdg_name, modify_trunk_port,
+		&port_index, conf->mod_bdg_auth_token);
+	return ret;
 }
 
 
 
-static void
-connect_ports(void)
+static int
+detach_vlan_port(struct vale_vlan_conf *conf, const char *port_name,
+	uint16_t vlan_id)
 {
+	struct mod_access_port mod_access_port;
+	uint32_t port_index = NM_BDG_NOPORT;
+	void *vlan_bdg_auth_token = NULL;
+	char modified_bdg_name[IF_NAMESIZE];
+	char vlan_bdg_name[IF_NAMESIZE];
+	char ap_name[IF_NAMESIZE];
+	int ret = 0;
+
+	if (vlan_id == 0x000 || vlan_id == 0xFFF) {
+		return EINVAL;
+	}
+	get_vlan_bdg_name(vlan_bdg_name, sizeof(vlan_bdg_name), conf->conf_name,
+		vlan_id);
+	get_modified_bdg_name(modified_bdg_name, sizeof(modified_bdg_name),
+		conf->conf_name);
+	get_ap_name(ap_name, sizeof(ap_name), conf->conf_name, vlan_id);
+	vlan_bdg_auth_token = conf->vlan_bdg_auth_tokens[vlan_id];
+
+	ret = detach_port(vlan_bdg_name, port_name, vlan_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		return ret;
+	}
+
+	if (--conf->number_of_ports[vlan_id] != 0) {
+		/* there are still other vlan port on this vlan bridge */
+		return ret;
+	}
+
+	/* we have just detached the last vlan port on this bridge, we need
+	 * to remove (and destroy) the access port and the bridge as well
+	 */
+	ret = detach_port(modified_bdg_name, ap_name,
+		conf->mod_bdg_auth_token, &port_index);
+	if (ret) {
+		goto l_attach_vlan_port;
+	}
+
+	ret = detach_port(vlan_bdg_name, ap_name, vlan_bdg_auth_token,
+		&port_index);
+	if (ret) {
+		goto l_attach_access_port_mod_bdg;
+	}
+
+	ret = destroy_vale_port(ap_name);
+	if (ret) {
+		goto l_attach_access_port_vlan_bdg;
+	}
+
+	ret = netmap_bdg_destroy(vlan_bdg_name, vlan_bdg_auth_token);
+	if (ret) {
+		/* cannot happen (?) */
+		goto l_create_access_port;
+	}
 
-	attach_port(VALE_V1A, "v1", token_v1_A, NULL);
-	attach_port(VALE_V1A, "v2", token_v1_A, NULL);
-	attach_port(VALE_V1A, "ap1A", token_v1_A, NULL);
+	mod_access_port.old_port_index = port_index;
+	mod_access_port.new_port_index = NM_BDG_NOPORT;
+	mod_access_port.old_vlan_id = vlan_id;
+	mod_access_port.new_vlan_id = 0x000;
+	/* this can't fail because we have the bridge in exlusive mode */
+	nm_bdg_update_private_data(modified_bdg_name, modify_access_port,
+		&mod_access_port, conf->mod_bdg_auth_token);
 
-	attach_port(VALE_V2A, "v3", token_v2_A, NULL);
-	attach_port(VALE_V2A, "v3", token_v2_A, NULL);
-	attach_port(VALE_V2A, "ap2A", token_v2_A, NULL);
 
-	attach_port(VALE_V1B, "v4", token_v1_B, NULL);
-	attach_port(VALE_V1B, "ap1B", token_v1_B, NULL);
+	return ret;
 
-	attach_port(VALE_V2B, "v5", token_v2_B, NULL);
-	attach_port(VALE_V2B, "ap2B", token_v2_B, NULL);
+l_create_access_port:
+	create_vale_port(ap_name); /* cannot fail */
 
-	attach_port(VALE_V500B, "v6", token_v500_B, NULL);
-	attach_port(VALE_V500B, "ap500B", token_v500_B, NULL);
+l_attach_access_port_vlan_bdg:
+	/* cannot fail */
+	attach_port(vlan_bdg_name, ap_name, vlan_bdg_auth_token, &port_index);
+
+l_attach_access_port_mod_bdg:
+	/* cannot fail */
+	attach_port(modified_bdg_name, ap_name, conf->mod_bdg_auth_token,
+		&port_index);
+
+l_attach_vlan_port:
+	/* cannot fail */
+	attach_port(vlan_bdg_name, port_name, vlan_bdg_auth_token, &port_index);
+	++conf->number_of_ports[vlan_id];
 
-	attach_port(VALE_MODA, "ap1A", token_A, NULL);
-	attach_port(VALE_MODA, "ap2A", token_A, NULL);
-	attach_port(VALE_MODA, "vtp", token_A, NULL);
+	return ret;
 
-	attach_port(VALE_MODB, "ap1B", token_B, NULL);
-	attach_port(VALE_MODB, "ap2B", token_B, NULL);
-	attach_port(VALE_MODB, "ap500B", token_B, NULL);
-	attach_port(VALE_MODB, "vtp", token_B, NULL);
 }
 
 
 
-static void
-delete_ports(void)
+static int
+search_vlan_id_of(struct vale_vlan_conf *conf, const char *port_name,
+	uint16_t *vlan_id)
 {
+	struct port_elem *p_elem = NULL;
 
-	destroy_vale_port("v1");
-	destroy_vale_port("v2");
-	destroy_vale_port("v3");
-	destroy_vale_port("v4");
-	destroy_vale_port("v5");
-	destroy_vale_port("v6");
-	destroy_vale_port("vtp");
-	destroy_vale_port("ap1A");
-	destroy_vale_port("ap1B");
-	destroy_vale_port("ap2A");
-	destroy_vale_port("ap2B");
-	destroy_vale_port("ap500B");
+	vv_list_foreach(p_elem, &conf->port_list, list) {
+		if (strcmp(p_elem->port_desc.port_name, port_name) == 0) {
+			*vlan_id = p_elem->port_desc.vlan_id;
+			return 0;
+		}
+	}
+	return ENXIO;
 }
 
 
 
-static void
-delete_bridges(void)
+static int
+search_trunk_port_of(struct vale_vlan_conf *conf, char *trunk_port_name)
 {
+	struct port_elem *p_elem = NULL;
 
-	netmap_bdg_destroy(VALE_MODA, &token_A);
-	netmap_bdg_destroy(VALE_MODB, &token_B);
-	netmap_bdg_destroy(VALE_V1A, &token_v1_A);
-	netmap_bdg_destroy(VALE_V1B, &token_v1_B);
-	netmap_bdg_destroy(VALE_V2A, &token_v2_A);
-	netmap_bdg_destroy(VALE_V2B, &token_v2_B);
-	netmap_bdg_destroy(VALE_V500B, &token_v500_B);
+	vv_list_foreach(p_elem, &conf->port_list, list) {
+		if (p_elem->port_desc.port_type == TRUNK_PORT) {
+			snprintf(trunk_port_name, IF_NAMESIZE, "%s",
+				p_elem->port_desc.port_name);
+			return 0;
+		}
+	}
+	return ENXIO;
 }
 
 
 
-static void
-detach_ports(void)
+static int
+action_detach(struct vale_vlan_conf *conf, char *port_name, uint8_t port_type,
+	uint16_t vlan_id)
 {
+	int ret = 0;
+
+	switch (port_type) {
+	case TRUNK_PORT:
+		if (port_name[0] == '\0') {
+			ret = search_trunk_port_of(conf, port_name);
+			if (ret) {
+				return ret;
+			}
+		}
+		ret = detach_trunk_port(conf, port_name, vlan_id);
+		if (ret) {
+			return ret;
+		}
+		break;
 
+	case VLAN_PORT:
+		if (vlan_id == 0xFFF) {
+			ret = search_vlan_id_of(conf, port_name, &vlan_id);
+			if (ret) {
+				return ret;
+			}
+		}
 
-	detach_port(VALE_MODB, "vtp", token_B, NULL);
-	detach_port(VALE_MODB, "ap500B", token_B, NULL);
-	detach_port(VALE_MODB, "ap2B", token_B, NULL);
-	detach_port(VALE_MODB, "ap1B", token_B, NULL);
+		ret = detach_vlan_port(conf, port_name, vlan_id);
+		if (ret) {
+			return ret;
+		}
+		break;
 
+	default:
+		return EINVAL;
+	}
 
-	detach_port(VALE_MODA, "vtp", token_A, NULL);
-	detach_port(VALE_MODA, "ap2A", token_A, NULL);
-	detach_port(VALE_MODA, "ap1A", token_A, NULL);
+	ret = detach_port_list(conf, port_name);
+	if (ret) {
+		switch (port_type){
+		case TRUNK_PORT:
+			ret = attach_trunk_port(conf, port_name, vlan_id);
+			break;
+
+		case VLAN_PORT:
+			ret = attach_vlan_port(conf, port_name, vlan_id);
+			break;
+		}
+	}
 
+	return ret;
+}
 
-	detach_port(VALE_V500B, "ap500B", token_v500_B, NULL);
-	detach_port(VALE_V500B, "v6", token_v500_B, NULL);
 
-	detach_port(VALE_V2B, "ap2B", token_v2_B, NULL);
-	detach_port(VALE_V2B, "v5", token_v2_B, NULL);
 
-	detach_port(VALE_V1B, "ap1B", token_v1_B, NULL);
-	detach_port(VALE_V1B, "v4", token_v1_B, NULL);
+static int
+action_detach_and_destroy(struct vale_vlan_conf *conf, char *port_name,
+	uint8_t port_type, uint16_t vlan_id)
+{
+	int ret = 0;
 
-	detach_port(VALE_V2A, "ap2A", token_v2_A, NULL);
-	detach_port(VALE_V2A, "v3", token_v2_A, NULL);
-	detach_port(VALE_V2A, "v3", token_v2_A, NULL);
+	ret = action_detach(conf, port_name, port_type, vlan_id);
+	if (ret) {
+		return ret;
+	}
 
-	detach_port(VALE_V1A, "ap1A", token_v1_A, NULL);
-	detach_port(VALE_V1A, "v2", token_v1_A, NULL);
-	detach_port(VALE_V1A, "v1", token_v1_A, NULL);
+	ret = destroy_vale_port(port_name);
+	if (ret) {
+		/* cannot fail */
+		action_attach(conf, port_name, port_type, vlan_id);
+	}
+	return ret;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-soc-all mailing list