+void
+lnet_ni_free(struct lnet_ni *ni)
+{
+ int i;
+
+ lnet_net_remove_cpts(ni->ni_cpts, ni->ni_ncpts, ni->ni_net);
+
+ if (ni->ni_refs != NULL)
+ cfs_percpt_free(ni->ni_refs);
+
+ if (ni->ni_tx_queues != NULL)
+ cfs_percpt_free(ni->ni_tx_queues);
+
+ if (ni->ni_cpts != NULL)
+ cfs_expr_list_values_free(ni->ni_cpts, ni->ni_ncpts);
+
+ for (i = 0; i < LNET_INTERFACES_NUM &&
+ ni->ni_interfaces[i] != NULL; i++) {
+ LIBCFS_FREE(ni->ni_interfaces[i],
+ strlen(ni->ni_interfaces[i]) + 1);
+ }
+
+ /* release reference to net namespace */
+ if (ni->ni_net_ns != NULL)
+ put_net(ni->ni_net_ns);
+
+ LIBCFS_FREE(ni, sizeof(*ni));
+}
+
+void
+lnet_net_free(struct lnet_net *net)
+{
+ struct list_head *tmp, *tmp2;
+ struct lnet_ni *ni;
+
+ LASSERT(list_empty(&net->net_ni_zombie));
+
+ /*
+ * delete any nis that haven't been added yet. This could happen
+ * if there is a failure on net startup
+ */
+ list_for_each_safe(tmp, tmp2, &net->net_ni_added) {
+ ni = list_entry(tmp, struct lnet_ni, ni_netlist);
+ list_del_init(&ni->ni_netlist);
+ lnet_ni_free(ni);
+ }
+
+ /* delete any nis which have been started. */
+ list_for_each_safe(tmp, tmp2, &net->net_ni_list) {
+ ni = list_entry(tmp, struct lnet_ni, ni_netlist);
+ list_del_init(&ni->ni_netlist);
+ lnet_ni_free(ni);
+ }
+
+ if (net->net_cpts != NULL)
+ LIBCFS_FREE(net->net_cpts,
+ sizeof(*net->net_cpts) * net->net_ncpts);
+
+ LIBCFS_FREE(net, sizeof(*net));
+}
+
+struct lnet_net *
+lnet_net_alloc(__u32 net_id, struct list_head *net_list)
+{
+ struct lnet_net *net;
+
+ if (!lnet_net_unique(net_id, net_list, NULL)) {
+ CERROR("Duplicate net %s. Ignore\n",
+ libcfs_net2str(net_id));
+ return NULL;
+ }
+
+ LIBCFS_ALLOC(net, sizeof(*net));
+ if (net == NULL) {
+ CERROR("Out of memory creating network %s\n",
+ libcfs_net2str(net_id));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&net->net_list);
+ INIT_LIST_HEAD(&net->net_ni_list);
+ INIT_LIST_HEAD(&net->net_ni_added);
+ INIT_LIST_HEAD(&net->net_ni_zombie);
+ spin_lock_init(&net->net_lock);
+
+ net->net_id = net_id;
+ net->net_last_alive = ktime_get_real_seconds();
+ net->net_state = LNET_NET_STATE_INIT;
+
+ /* initialize global paramters to undefiend */
+ net->net_tunables.lct_peer_timeout = -1;
+ net->net_tunables.lct_max_tx_credits = -1;
+ net->net_tunables.lct_peer_tx_credits = -1;
+ net->net_tunables.lct_peer_rtr_credits = -1;
+
+ if (net_list)
+ list_add_tail(&net->net_list, net_list);
+
+ return net;
+}
+
+static int
+lnet_ni_add_interface(struct lnet_ni *ni, char *iface)
+{
+ int niface = 0;
+
+ if (ni == NULL)
+ return -ENOMEM;
+
+ if (!lnet_ni_unique_ni(ni->ni_interfaces, iface))
+ return -EINVAL;
+
+ /* Allocate a separate piece of memory and copy
+ * into it the string, so we don't have
+ * a depencency on the tokens string. This way we
+ * can free the tokens at the end of the function.
+ * The newly allocated ni_interfaces[] can be
+ * freed when freeing the NI */
+ while (niface < LNET_INTERFACES_NUM &&
+ ni->ni_interfaces[niface] != NULL)
+ niface++;
+
+ if (niface >= LNET_INTERFACES_NUM) {
+ LCONSOLE_ERROR_MSG(0x115, "Too many interfaces "
+ "for net %s\n",
+ libcfs_net2str(LNET_NIDNET(ni->ni_nid)));
+ return -EINVAL;
+ }
+
+ LIBCFS_ALLOC(ni->ni_interfaces[niface],
+ strlen(iface) + 1);
+
+ if (ni->ni_interfaces[niface] == NULL) {
+ CERROR("Can't allocate net interface name\n");
+ return -ENOMEM;
+ }
+
+ strncpy(ni->ni_interfaces[niface], iface,
+ strlen(iface) + 1);
+
+ return 0;
+}
+
+static struct lnet_ni *
+lnet_ni_alloc_common(struct lnet_net *net, char *iface)