Whamcloud - gitweb
LU-7734 lnet: configure local NI from DLC
authorAmir Shehata <amir.shehata@intel.com>
Fri, 29 Jan 2016 01:00:09 +0000 (17:00 -0800)
committerAmir Shehata <amir.shehata@intel.com>
Wed, 25 Jan 2017 03:10:01 +0000 (19:10 -0800)
This patch adds the ability to configure multiple network interfaces
on the same network. This can be done via the lnetctl CLI interface
or through a YAML configuration. Refer to the multi-rail HLD for
more details on the syntax.

It also deprecates ip2nets kernel parsing. All string parsing and
network maching now happens in the DLC userspace library.

New IOCTLs are added for adding/deleting local NIs, to keep backwards
compatibility with older version of the DLC and lnetctl.

The changes also include parsing and matching ip2nets syntax at the
user level and then passing down the network interfaces down to the
kernel to be configured.

Signed-off-by: Amir Shehata <amir.shehata@intel.com>
Change-Id: I19ee7dc76514beb6f34de6517d19654d6468bcec
Reviewed-on: http://review.whamcloud.com/18886
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
20 files changed:
libcfs/include/libcfs/libcfs_ioctl.h
libcfs/include/libcfs/libcfs_string.h
libcfs/include/libcfs/util/string.h
libcfs/libcfs/libcfs_string.c
libcfs/libcfs/util/string.c
lnet/include/lnet/lib-dlc.h
lnet/include/lnet/lib-lnet.h
lnet/klnds/socklnd/socklnd.c
lnet/lnet/api-ni.c
lnet/lnet/config.c
lnet/lnet/module.c
lnet/lnet/peer.c
lnet/utils/cyaml/cyaml.c
lnet/utils/cyaml/cyaml.h
lnet/utils/lnetconfig/Makefile.am
lnet/utils/lnetconfig/liblnd.h
lnet/utils/lnetconfig/liblnetconfig.c
lnet/utils/lnetconfig/liblnetconfig.h
lnet/utils/lnetconfig/liblnetconfig_lnd.c
lnet/utils/lnetctl.c

index 11292b2..9f0b284 100644 (file)
@@ -129,35 +129,25 @@ struct libcfs_debug_ioctl_data
  * number have been allocated.
  */
 #define IOCTL_CONFIG_SIZE                 struct lnet_ioctl_config_data
  * number have been allocated.
  */
 #define IOCTL_CONFIG_SIZE                 struct lnet_ioctl_config_data
-#define IOC_LIBCFS_ADD_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 81, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_DEL_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 82, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 83, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_ADD_NET                _IOWR(IOC_LIBCFS_TYPE, 84, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_DEL_NET                _IOWR(IOC_LIBCFS_TYPE, 85, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_NET                _IOWR(IOC_LIBCFS_TYPE, 86, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_CONFIG_RTR             _IOWR(IOC_LIBCFS_TYPE, 87, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_ADD_BUF                _IOWR(IOC_LIBCFS_TYPE, 88, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_BUF                _IOWR(IOC_LIBCFS_TYPE, 89, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_PEER_INFO          _IOWR(IOC_LIBCFS_TYPE, 90, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_LNET_STATS         _IOWR(IOC_LIBCFS_TYPE, 91, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_ADD_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 92, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_DEL_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 93, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_GET_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 94, \
-                                                IOCTL_CONFIG_SIZE)
-#define IOC_LIBCFS_MAX_NR                            94
+#define IOC_LIBCFS_ADD_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 81, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_DEL_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 82, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_ROUTE              _IOWR(IOC_LIBCFS_TYPE, 83, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_ADD_NET                _IOWR(IOC_LIBCFS_TYPE, 84, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_DEL_NET                _IOWR(IOC_LIBCFS_TYPE, 85, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_NET                _IOWR(IOC_LIBCFS_TYPE, 86, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_CONFIG_RTR             _IOWR(IOC_LIBCFS_TYPE, 87, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_ADD_BUF                _IOWR(IOC_LIBCFS_TYPE, 88, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_BUF                _IOWR(IOC_LIBCFS_TYPE, 89, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_PEER_INFO          _IOWR(IOC_LIBCFS_TYPE, 90, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_LNET_STATS         _IOWR(IOC_LIBCFS_TYPE, 91, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_ADD_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 92, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_DEL_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 93, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_PEER_NI            _IOWR(IOC_LIBCFS_TYPE, 94, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_ADD_LOCAL_NI                   _IOWR(IOC_LIBCFS_TYPE, 95, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_DEL_LOCAL_NI                   _IOWR(IOC_LIBCFS_TYPE, 96, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_GET_LOCAL_NI                   _IOWR(IOC_LIBCFS_TYPE, 97, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_DBG                    _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE)
+#define IOC_LIBCFS_MAX_NR                                        98
 
 extern int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data);
 
 
 extern int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data);
 
index f743fc6..3c34071 100644 (file)
@@ -82,15 +82,7 @@ int cfs_expr_list_print(char *buffer, int count,
                        struct cfs_expr_list *expr_list);
 int cfs_expr_list_values(struct cfs_expr_list *expr_list,
                         int max, __u32 **values);
                        struct cfs_expr_list *expr_list);
 int cfs_expr_list_values(struct cfs_expr_list *expr_list,
                         int max, __u32 **values);
-static inline void
-cfs_expr_list_values_free(__u32 *values, int num)
-{
-       /* This array is allocated by LIBCFS_ALLOC(), so it shouldn't be freed
-        * by OBD_FREE() if it's called by module other than libcfs & LNet,
-        * otherwise we will see fake memory leak */
-       LIBCFS_FREE(values, num * sizeof(values[0]));
-}
-
+void cfs_expr_list_values_free(__u32 *values, int num);
 void cfs_expr_list_free(struct cfs_expr_list *expr_list);
 int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
                        struct cfs_expr_list **elpp);
 void cfs_expr_list_free(struct cfs_expr_list *expr_list);
 int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
                        struct cfs_expr_list **elpp);
index 2a1c1b7..361cb81 100644 (file)
@@ -86,6 +86,7 @@ int cfs_expr_list_print(char *buffer, int count,
                        struct cfs_expr_list *expr_list);
 int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
                        struct cfs_expr_list **elpp);
                        struct cfs_expr_list *expr_list);
 int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max,
                        struct cfs_expr_list **elpp);
+void cfs_expr_list_free(struct cfs_expr_list *expr_list);
 void cfs_expr_list_free_list(struct list_head *list);
 int cfs_ip_addr_parse(char *str, int len, struct list_head *list);
 int cfs_ip_addr_match(__u32 addr, struct list_head *list);
 void cfs_expr_list_free_list(struct list_head *list);
 int cfs_ip_addr_parse(char *str, int len, struct list_head *list);
 int cfs_ip_addr_match(__u32 addr, struct list_head *list);
index bf83793..04e1dd5 100644 (file)
@@ -480,6 +480,16 @@ cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp)
 }
 EXPORT_SYMBOL(cfs_expr_list_values);
 
 }
 EXPORT_SYMBOL(cfs_expr_list_values);
 
+void
+cfs_expr_list_values_free(__u32 *values, int num)
+{
+       /* This array is allocated by LIBCFS_ALLOC(), so it shouldn't be freed
+        * by OBD_FREE() if it's called by module other than libcfs & LNet,
+        * otherwise we will see fake memory leak */
+       LIBCFS_FREE(values, num * sizeof(values[0]));
+}
+EXPORT_SYMBOL(cfs_expr_list_values_free);
+
 /**
  * Frees cfs_range_expr structures of \a expr_list.
  *
 /**
  * Frees cfs_range_expr structures of \a expr_list.
  *
index 97b5f7f..9078500 100644 (file)
@@ -327,11 +327,64 @@ cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list)
 }
 
 /**
 }
 
 /**
+ * Convert express list (\a expr_list) to an array of all matched values
+ *
+ * \retval N N is total number of all matched values
+ * \retval 0 if expression list is empty
+ * \retval < 0 for failure
+ */
+int
+cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **valpp)
+{
+       struct cfs_range_expr   *expr;
+       __u32                   *val;
+       int                     count = 0;
+       int                     i;
+
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               for (i = expr->re_lo; i <= expr->re_hi; i++) {
+                       if (((i - expr->re_lo) % expr->re_stride) == 0)
+                               count++;
+               }
+       }
+
+       if (count == 0) /* empty expression list */
+               return 0;
+
+       if (count > max)
+               return -EINVAL;
+
+       val = calloc(sizeof(val[0]), count);
+       if (val == NULL)
+               return -ENOMEM;
+
+       count = 0;
+       list_for_each_entry(expr, &expr_list->el_exprs, re_link) {
+               for (i = expr->re_lo; i <= expr->re_hi; i++) {
+                       if (((i - expr->re_lo) % expr->re_stride) == 0)
+                               val[count++] = i;
+               }
+       }
+
+       *valpp = val;
+       return count;
+}
+
+void
+cfs_expr_list_values_free(__u32 *values, int num)
+{
+       /* This array is allocated by LIBCFS_ALLOC(), so it shouldn't be freed
+        * by OBD_FREE() if it's called by module other than libcfs & LNet,
+        * otherwise we will see fake memory leak */
+       free(values);
+}
+
+/**
  * Frees cfs_range_expr structures of \a expr_list.
  *
  * \retval none
  */
  * Frees cfs_range_expr structures of \a expr_list.
  *
  * \retval none
  */
-static void
+void
 cfs_expr_list_free(struct cfs_expr_list *expr_list)
 {
        while (!list_empty(&expr_list->el_exprs)) {
 cfs_expr_list_free(struct cfs_expr_list *expr_list)
 {
        while (!list_empty(&expr_list->el_exprs)) {
index 1213eb7..1743d72 100644 (file)
 #define LNET_MAX_SHOW_NUM_CPT  128
 #define LNET_UNDEFINED_HOPS    ((__u32) -1)
 
 #define LNET_MAX_SHOW_NUM_CPT  128
 #define LNET_UNDEFINED_HOPS    ((__u32) -1)
 
+/*
+ * To allow for future enhancements to extend the tunables
+ * add a hdr to this structure, so that the version can be set
+ * and checked for backwards compatibility. Newer versions of LNet
+ * can still work with older versions of lnetctl. The restriction is
+ * that the structure can be added to and not removed from in order
+ * to not invalidate older lnetctl utilities. Moreover, the order of
+ * fields must remain the same, and new fields appended to the structure
+ *
+ * That said all existing LND tunables will be added in this structure
+ * to avoid future changes.
+ */
 struct lnet_ioctl_config_lnd_cmn_tunables {
        __u32 lct_version;
        __s32 lct_peer_timeout;
 struct lnet_ioctl_config_lnd_cmn_tunables {
        __u32 lct_version;
        __s32 lct_peer_timeout;
@@ -81,6 +93,10 @@ struct lnet_ioctl_net_config {
 /* # different router buffer pools */
 #define LNET_NRBPOOLS          (LNET_LARGE_BUF_IDX + 1)
 
 /* # different router buffer pools */
 #define LNET_NRBPOOLS          (LNET_LARGE_BUF_IDX + 1)
 
+enum lnet_dbg_task {
+       LNET_DBG_INCR_DLC_SEQ = 0
+};
+
 struct lnet_ioctl_pool_cfg {
        struct {
                __u32 pl_npages;
 struct lnet_ioctl_pool_cfg {
        struct {
                __u32 pl_npages;
@@ -125,6 +141,29 @@ struct lnet_ioctl_config_data {
        char cfg_bulk[0];
 };
 
        char cfg_bulk[0];
 };
 
+/*
+ * lnet_ioctl_config_ni
+ *  This structure describes an NI configuration. There are multiple components
+ *  when configuring an NI: Net, Interfaces, CPT list and LND tunables
+ *  A network is passed as a string to the DLC and translated using
+ *  libcfs_str2net()
+ *  An interface is the name of the system configured interface
+ *  (ex eth0, ib1)
+ *  CPT is the list of CPTS LND tunables are passed in the lic_bulk area
+ */
+struct lnet_ioctl_config_ni {
+       struct libcfs_ioctl_hdr lic_cfg_hdr;
+       lnet_nid_t              lic_nid;
+       char                    lic_ni_intf[LNET_MAX_INTERFACES][LNET_MAX_STR_LEN];
+       char                    lic_legacy_ip2nets[LNET_MAX_STR_LEN];
+       __u32                   lic_cpts[LNET_MAX_SHOW_NUM_CPT];
+       __u32                   lic_ncpts;
+       __u32                   lic_status;
+       __u32                   lic_tcp_bonding;
+       __u32                   lic_idx;
+       char                    lic_bulk[0];
+};
+
 struct lnet_peer_ni_credit_info {
        char cr_aliveness[LNET_MAX_STR_LEN];
        __u32 cr_refcount;
 struct lnet_peer_ni_credit_info {
        char cr_aliveness[LNET_MAX_STR_LEN];
        __u32 cr_refcount;
@@ -147,6 +186,24 @@ struct lnet_ioctl_peer {
        } pr_lnd_u;
 };
 
        } pr_lnd_u;
 };
 
+struct lnet_dbg_task_info {
+       /*
+        * TODO: a union can be added if the task requires more
+        * information from user space to be carried out in kernel space.
+        */
+};
+
+/*
+ * This structure is intended to allow execution of debugging tasks. This
+ * is not intended to be backwards compatible. Extra tasks can be added in
+ * the future
+ */
+struct lnet_ioctl_dbg {
+       struct libcfs_ioctl_hdr dbg_hdr;
+       enum lnet_dbg_task dbg_task;
+       char dbg_bulk[0];
+};
+
 struct lnet_ioctl_peer_cfg {
        struct libcfs_ioctl_hdr prcfg_hdr;
        lnet_nid_t prcfg_key_nid;
 struct lnet_ioctl_peer_cfg {
        struct libcfs_ioctl_hdr prcfg_hdr;
        lnet_nid_t prcfg_key_nid;
index 014ce10..87f3300 100644 (file)
@@ -470,6 +470,9 @@ lnet_net_alloc(__u32 net_type, struct list_head *netlist);
 struct lnet_ni *
 lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el,
              char *iface);
 struct lnet_ni *
 lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el,
              char *iface);
+struct lnet_ni *
+lnet_ni_alloc_w_cpt_array(struct lnet_net *net, __u32 *cpts, __u32 ncpts,
+                         char *iface);
 
 static inline int
 lnet_nid2peerhash(lnet_nid_t nid)
 
 static inline int
 lnet_nid2peerhash(lnet_nid_t nid)
@@ -494,7 +497,7 @@ extern int lnet_cpt_of_nid(lnet_nid_t nid, struct lnet_ni *ni);
 extern lnet_ni_t *lnet_nid2ni_locked(lnet_nid_t nid, int cpt);
 extern lnet_ni_t *lnet_nid2ni_addref(lnet_nid_t nid);
 extern lnet_ni_t *lnet_net2ni_locked(__u32 net, int cpt);
 extern lnet_ni_t *lnet_nid2ni_locked(lnet_nid_t nid, int cpt);
 extern lnet_ni_t *lnet_nid2ni_addref(lnet_nid_t nid);
 extern lnet_ni_t *lnet_net2ni_locked(__u32 net, int cpt);
-extern lnet_ni_t *lnet_net2ni(__u32 net);
+extern lnet_ni_t *lnet_net2ni_addref(__u32 net);
 bool lnet_is_ni_healthy_locked(struct lnet_ni *ni);
 struct lnet_net *lnet_get_net_locked(__u32 net_id);
 
 bool lnet_is_ni_healthy_locked(struct lnet_ni *ni);
 struct lnet_net *lnet_get_net_locked(__u32 net_id);
 
@@ -543,9 +546,10 @@ int lnet_rtrpools_enable(void);
 void lnet_rtrpools_disable(void);
 void lnet_rtrpools_free(int keep_pools);
 lnet_remotenet_t *lnet_find_rnet_locked(__u32 net);
 void lnet_rtrpools_disable(void);
 void lnet_rtrpools_free(int keep_pools);
 lnet_remotenet_t *lnet_find_rnet_locked(__u32 net);
-int lnet_dyn_add_ni(lnet_pid_t requested_pid,
-                   struct lnet_ioctl_config_data *conf);
-int lnet_dyn_del_ni(__u32 net);
+int lnet_dyn_add_net(struct lnet_ioctl_config_data *conf);
+int lnet_dyn_del_net(__u32 net);
+int lnet_dyn_add_ni(struct lnet_ioctl_config_ni *conf);
+int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf);
 int lnet_clear_lazy_portal(struct lnet_ni *ni, int portal, char *reason);
 struct lnet_net *lnet_get_net_locked(__u32 net_id);
 
 int lnet_clear_lazy_portal(struct lnet_ni *ni, int portal, char *reason);
 struct lnet_net *lnet_get_net_locked(__u32 net_id);
 
@@ -800,6 +804,7 @@ int lnet_find_or_create_peer_locked(lnet_nid_t dst_nid, int cpt,
                                    struct lnet_peer **peer);
 int lnet_nid2peerni_locked(struct lnet_peer_ni **lpp, lnet_nid_t nid, int cpt);
 struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid);
                                    struct lnet_peer **peer);
 int lnet_nid2peerni_locked(struct lnet_peer_ni **lpp, lnet_nid_t nid, int cpt);
 struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid);
+void lnet_peer_net_added(struct lnet_net *net);
 void lnet_peer_tables_cleanup(lnet_ni_t *ni);
 void lnet_peer_uninit(void);
 int lnet_peer_tables_create(void);
 void lnet_peer_tables_cleanup(lnet_ni_t *ni);
 void lnet_peer_uninit(void);
 int lnet_peer_tables_create(void);
index bed371c..bb08cca 100644 (file)
@@ -2749,7 +2749,8 @@ ksocknal_net_start_threads(ksock_net_t *net, __u32 *cpts, int ncpts)
        int     rc;
        int     i;
 
        int     rc;
        int     i;
 
-       LASSERT(ncpts > 0 && ncpts <= cfs_cpt_number(lnet_cpt_table()));
+       if (ncpts > 0 && ncpts > cfs_cpt_number(lnet_cpt_table()))
+               return -EINVAL;
 
        for (i = 0; i < ncpts; i++) {
                struct ksock_sched_info *info;
 
        for (i = 0; i < ncpts; i++) {
                struct ksock_sched_info *info;
index f4587da..64c912b 100644 (file)
@@ -731,17 +731,19 @@ lnet_net2ni_locked(__u32 net_id, int cpt)
 }
 
 lnet_ni_t *
 }
 
 lnet_ni_t *
-lnet_net2ni(__u32 net)
+lnet_net2ni_addref(__u32 net)
 {
        lnet_ni_t *ni;
 
        lnet_net_lock(0);
        ni = lnet_net2ni_locked(net, 0);
 {
        lnet_ni_t *ni;
 
        lnet_net_lock(0);
        ni = lnet_net2ni_locked(net, 0);
+       if (ni)
+               lnet_ni_addref_locked(ni, 0);
        lnet_net_unlock(0);
 
        return ni;
 }
        lnet_net_unlock(0);
 
        return ni;
 }
-EXPORT_SYMBOL(lnet_net2ni);
+EXPORT_SYMBOL(lnet_net2ni_addref);
 
 struct lnet_net *
 lnet_get_net_locked(__u32 net_id)
 
 struct lnet_net *
 lnet_get_net_locked(__u32 net_id)
@@ -957,6 +959,18 @@ lnet_get_net_ni_count_locked(struct lnet_net *net)
 }
 
 static inline int
 }
 
 static inline int
+lnet_get_net_ni_count_pre(struct lnet_net *net)
+{
+       struct lnet_ni  *ni;
+       int             count = 0;
+
+       list_for_each_entry(ni, &net->net_ni_added, ni_netlist)
+               count++;
+
+       return count;
+}
+
+static inline int
 lnet_get_ni_count(void)
 {
        struct lnet_ni  *ni;
 lnet_get_ni_count(void)
 {
        struct lnet_ni  *ni;
@@ -1911,21 +1925,91 @@ LNetNIFini()
 }
 EXPORT_SYMBOL(LNetNIFini);
 
 }
 EXPORT_SYMBOL(LNetNIFini);
 
+
+static int lnet_handle_dbg_task(struct lnet_ioctl_dbg *dbg,
+                               struct lnet_dbg_task_info *dbg_info)
+{
+       switch (dbg->dbg_task) {
+       case LNET_DBG_INCR_DLC_SEQ:
+               lnet_incr_dlc_seq();
+       }
+
+       return 0;
+}
+/**
+ * Grabs the ni data from the ni structure and fills the out
+ * parameters
+ *
+ * \param[in] ni network       interface structure
+ * \param[out] cfg_ni          NI config information
+ * \param[out] tun             network and LND tunables
+ */
+static void
+lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni,
+                  struct lnet_ioctl_config_lnd_tunables *tun,
+                  __u32 tun_size)
+{
+       size_t min_size = 0;
+       int i;
+
+       if (!ni || !cfg_ni || !tun)
+               return;
+
+       if (ni->ni_interfaces[0] != NULL) {
+               for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) {
+                       if (ni->ni_interfaces[i] != NULL) {
+                               strncpy(cfg_ni->lic_ni_intf[i],
+                                       ni->ni_interfaces[i],
+                                       sizeof(cfg_ni->lic_ni_intf[i]));
+                       }
+               }
+       }
+
+       cfg_ni->lic_nid = ni->ni_nid;
+       cfg_ni->lic_status = ni->ni_status->ns_status;
+       cfg_ni->lic_tcp_bonding = use_tcp_bonding;
+
+       memcpy(&tun->lt_cmn, &ni->ni_net->net_tunables, sizeof(tun->lt_cmn));
+
+       /*
+        * tun->lt_tun will always be present, but in order to be
+        * backwards compatible, we need to deal with the cases when
+        * tun->lt_tun is smaller than what the kernel has, because it
+        * comes from an older version of a userspace program, then we'll
+        * need to copy as much information as we have available space.
+        */
+       min_size = tun_size - sizeof(tun->lt_cmn);
+       memcpy(&tun->lt_tun, &ni->ni_lnd_tunables, min_size);
+
+       /* copy over the cpts */
+       if (ni->ni_ncpts == LNET_CPT_NUMBER &&
+           ni->ni_cpts == NULL)  {
+               for (i = 0; i < ni->ni_ncpts; i++)
+                       cfg_ni->lic_cpts[i] = i;
+       } else {
+               for (i = 0;
+                    ni->ni_cpts != NULL && i < ni->ni_ncpts &&
+                    i < LNET_MAX_SHOW_NUM_CPT;
+                    i++)
+                       cfg_ni->lic_cpts[i] = ni->ni_cpts[i];
+       }
+       cfg_ni->lic_ncpts = ni->ni_ncpts;
+}
+
 /**
 /**
+ * NOTE: This is a legacy function left in the code to be backwards
+ * compatible with older userspace programs. It should eventually be
+ * removed.
+ *
  * Grabs the ni data from the ni structure and fills the out
  * parameters
  *
  * \param[in] ni network       interface structure
  * Grabs the ni data from the ni structure and fills the out
  * parameters
  *
  * \param[in] ni network       interface structure
- * \param[out] cpt_count       the number of cpts the ni is on
- * \param[out] nid             Network Interface ID
- * \param[out] peer_timeout    NI peer timeout
- * \param[out] peer_tx_crdits  NI peer transmit credits
- * \param[out] peer_rtr_credits NI peer router credits
- * \param[out] max_tx_credits  NI max transmit credit
- * \param[out] net_config      Network configuration
+ * \param[out] config          config information
  */
 static void
  */
 static void
-lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_data *config)
+lnet_fill_ni_info_legacy(struct lnet_ni *ni,
+                        struct lnet_ioctl_config_data *config)
 {
        struct lnet_ioctl_net_config *net_config;
        struct lnet_ioctl_config_lnd_tunables *lnd_cfg = NULL;
 {
        struct lnet_ioctl_net_config *net_config;
        struct lnet_ioctl_config_lnd_tunables *lnd_cfg = NULL;
@@ -2072,7 +2156,7 @@ lnet_get_net_config(struct lnet_ioctl_config_data *config)
        if (ni != NULL) {
                rc = 0;
                lnet_ni_lock(ni);
        if (ni != NULL) {
                rc = 0;
                lnet_ni_lock(ni);
-               lnet_fill_ni_info(ni, config);
+               lnet_fill_ni_info_legacy(ni, config);
                lnet_ni_unlock(ni);
        }
 
                lnet_ni_unlock(ni);
        }
 
@@ -2081,49 +2165,56 @@ lnet_get_net_config(struct lnet_ioctl_config_data *config)
 }
 
 int
 }
 
 int
-lnet_dyn_add_ni(lnet_pid_t requested_pid, struct lnet_ioctl_config_data *conf)
+lnet_get_ni_config(struct lnet_ioctl_config_ni *cfg_ni,
+                  struct lnet_ioctl_config_lnd_tunables *tun,
+                  __u32 tun_size)
 {
 {
-       char                    *nets = conf->cfg_config_u.cfg_net.net_intf;
-       struct lnet_ping_info   *pinfo;
-       lnet_handle_md_t        md_handle;
-       struct lnet_net         *net;
-       struct list_head        net_head;
-       int                     rc;
-       lnet_remotenet_t        *rnet;
-       int                     net_ni_count;
-       int                     num_acceptor_nets;
-       __u32                   net_type;
-       struct lnet_ioctl_config_lnd_tunables *lnd_tunables = NULL;
-
-       INIT_LIST_HEAD(&net_head);
+       struct lnet_ni          *ni;
+       int                     cpt;
+       int                     rc = -ENOENT;
 
 
-       if (conf && conf->cfg_hdr.ioc_len > sizeof(*conf))
-               lnd_tunables = (struct lnet_ioctl_config_lnd_tunables *)conf->cfg_bulk;
+       if (!cfg_ni || !tun)
+               return -EINVAL;
 
 
-       /* Create a net/ni structures for the network string */
-       rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
-       if (rc <= 0)
-               return rc == 0 ? -EINVAL : rc;
+       cpt = lnet_net_lock_current();
 
 
-       mutex_lock(&the_lnet.ln_api_mutex);
+       ni = lnet_get_ni_idx_locked(cfg_ni->lic_idx);
 
 
-       if (rc > 1) {
-               rc = -EINVAL; /* only add one network per call */
-               goto failed0;
+       if (ni) {
+               rc = 0;
+               lnet_ni_lock(ni);
+               lnet_fill_ni_info(ni, cfg_ni, tun, tun_size);
+               lnet_ni_unlock(ni);
        }
 
        }
 
-       net = list_entry(net_head.next, struct lnet_net, net_list);
+       lnet_net_unlock(cpt);
+       return rc;
+}
+
+static int lnet_add_net_common(struct lnet_net *net,
+                              struct lnet_ioctl_config_lnd_tunables *tun)
+{
+       struct lnet_net         *netl = NULL;
+       __u32                   net_id;
+       lnet_ping_info_t        *pinfo;
+       lnet_handle_md_t        md_handle;
+       int                     rc;
+       lnet_remotenet_t        *rnet;
+       int                     net_ni_count;
+       int                     num_acceptor_nets;
 
        lnet_net_lock(LNET_LOCK_EX);
        rnet = lnet_find_rnet_locked(net->net_id);
        lnet_net_unlock(LNET_LOCK_EX);
 
        lnet_net_lock(LNET_LOCK_EX);
        rnet = lnet_find_rnet_locked(net->net_id);
        lnet_net_unlock(LNET_LOCK_EX);
-       /* make sure that the net added doesn't invalidate the current
-        * configuration LNet is keeping */
-       if (rnet != NULL) {
+       /*
+        * make sure that the net added doesn't invalidate the current
+        * configuration LNet is keeping
+        */
+       if (rnet) {
                CERROR("Adding net %s will invalidate routing configuration\n",
                CERROR("Adding net %s will invalidate routing configuration\n",
-                      nets);
+                      libcfs_net2str(net->net_id));
                rc = -EUSERS;
                rc = -EUSERS;
-               goto failed0;
+               goto failed1;
        }
 
        /*
        }
 
        /*
@@ -2132,22 +2223,22 @@ lnet_dyn_add_ni(lnet_pid_t requested_pid, struct lnet_ioctl_config_data *conf)
         * we should allocate enough slots to accomodate the number of NIs
         * which will be added.
         *
         * we should allocate enough slots to accomodate the number of NIs
         * which will be added.
         *
-        * We can use lnet_get_net_ni_count_locked() since the net is not
-        * on a public list yet, so locking is not a problem
+        * since ni hasn't been configured yet, use
+        * lnet_get_net_ni_count_pre() which checks the net_ni_added list
         */
         */
-       net_ni_count = lnet_get_net_ni_count_locked(net);
+       net_ni_count = lnet_get_net_ni_count_pre(net);
 
        rc = lnet_ping_info_setup(&pinfo, &md_handle,
                                  net_ni_count + lnet_get_ni_count(),
                                  false);
 
        rc = lnet_ping_info_setup(&pinfo, &md_handle,
                                  net_ni_count + lnet_get_ni_count(),
                                  false);
-       if (rc != 0)
-               goto failed0;
-
-       list_del_init(&net->net_list);
+       if (rc < 0)
+               goto failed1;
 
 
-       if (lnd_tunables)
+       if (tun)
                memcpy(&net->net_tunables,
                memcpy(&net->net_tunables,
-                      &lnd_tunables->lt_cmn, sizeof(lnd_tunables->lt_cmn));
+                      &tun->lt_cmn, sizeof(net->net_tunables));
+       else
+               memset(&net->net_tunables, -1, sizeof(net->net_tunables));
 
        /*
         * before starting this network get a count of the current TCP
 
        /*
         * before starting this network get a count of the current TCP
@@ -2157,48 +2248,270 @@ lnet_dyn_add_ni(lnet_pid_t requested_pid, struct lnet_ioctl_config_data *conf)
         */
        num_acceptor_nets = lnet_count_acceptor_nets();
 
         */
        num_acceptor_nets = lnet_count_acceptor_nets();
 
-       /*
-        * lnd_startup_lndnet() can deallocate 'net' even if it it returns
-        * success, because we endded up adding interfaces to an existing
-        * network. So grab the net_type now
-        */
-       net_type = LNET_NETTYP(net->net_id);
+       net_id = net->net_id;
 
        rc = lnet_startup_lndnet(net,
 
        rc = lnet_startup_lndnet(net,
-                                (lnd_tunables) ? &lnd_tunables->lt_tun : NULL);
+                                (tun) ? &tun->lt_tun : NULL);
        if (rc < 0)
        if (rc < 0)
-               goto failed1;
+               goto failed;
+
+       lnet_net_lock(LNET_LOCK_EX);
+       netl = lnet_get_net_locked(net_id);
+       lnet_net_unlock(LNET_LOCK_EX);
+
+       LASSERT(netl);
 
        /*
         * Start the acceptor thread if this is the first network
         * being added that requires the thread.
         */
 
        /*
         * Start the acceptor thread if this is the first network
         * being added that requires the thread.
         */
-       if (net_type == SOCKLND && num_acceptor_nets == 0)
+       if (netl->net_lnd->lnd_accept &&
+           num_acceptor_nets == 0)
        {
                rc = lnet_acceptor_start();
                if (rc < 0) {
                        /* shutdown the net that we just started */
                        CERROR("Failed to start up acceptor thread\n");
        {
                rc = lnet_acceptor_start();
                if (rc < 0) {
                        /* shutdown the net that we just started */
                        CERROR("Failed to start up acceptor thread\n");
-                       /*
-                        * Note that if we needed to start the acceptor
-                        * thread, then 'net' must have been the first TCP
-                        * network, therefore was unique, and therefore
-                        * wasn't deallocated by lnet_startup_lndnet()
-                        */
                        lnet_shutdown_lndnet(net);
                        lnet_shutdown_lndnet(net);
-                       goto failed1;
+                       goto failed;
                }
        }
 
                }
        }
 
+       lnet_net_lock(LNET_LOCK_EX);
+       lnet_peer_net_added(netl);
+       lnet_net_unlock(LNET_LOCK_EX);
+
        lnet_ping_target_update(pinfo, md_handle);
        lnet_ping_target_update(pinfo, md_handle);
-       mutex_unlock(&the_lnet.ln_api_mutex);
 
        return 0;
 
 
        return 0;
 
-failed1:
+failed:
        lnet_ping_md_unlink(pinfo, &md_handle);
        lnet_ping_info_free(pinfo);
        lnet_ping_md_unlink(pinfo, &md_handle);
        lnet_ping_info_free(pinfo);
-failed0:
+failed1:
+       lnet_net_free(net);
+       return rc;
+}
+
+static int lnet_handle_legacy_ip2nets(char *ip2nets,
+                                     struct lnet_ioctl_config_lnd_tunables *tun)
+{
+       struct lnet_net *net;
+       char *nets;
+       int rc;
+       struct list_head net_head;
+
+       INIT_LIST_HEAD(&net_head);
+
+       rc = lnet_parse_ip2nets(&nets, ip2nets);
+       if (rc < 0)
+               return rc;
+
+       rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&the_lnet.ln_api_mutex);
+       while (!list_empty(&net_head)) {
+               net = list_entry(net_head.next, struct lnet_net, net_list);
+               list_del_init(&net->net_list);
+               rc = lnet_add_net_common(net, tun);
+               if (rc < 0)
+                       goto out;
+       }
+
+out:
+       mutex_unlock(&the_lnet.ln_api_mutex);
+
+       while (!list_empty(&net_head)) {
+               net = list_entry(net_head.next, struct lnet_net, net_list);
+               list_del_init(&net->net_list);
+               lnet_net_free(net);
+       }
+       return rc;
+}
+
+int lnet_dyn_add_ni(struct lnet_ioctl_config_ni *conf)
+{
+       struct lnet_net *net;
+       struct lnet_ni *ni;
+       struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+       int rc;
+       __u32 net_id;
+
+       /* get the tunables if they are available */
+       if (conf->lic_cfg_hdr.ioc_len >=
+           sizeof(*conf) + sizeof(*tun))
+               tun = (struct lnet_ioctl_config_lnd_tunables *)
+                       conf->lic_bulk;
+
+       /* handle legacy ip2nets from DLC */
+       if (conf->lic_legacy_ip2nets[0] != '\0')
+               return lnet_handle_legacy_ip2nets(conf->lic_legacy_ip2nets,
+                                                 tun);
+
+       net_id = LNET_NIDNET(conf->lic_nid);
+
+       net = lnet_net_alloc(net_id, NULL);
+       if (!net)
+               return -ENOMEM;
+
+       ni = lnet_ni_alloc_w_cpt_array(net, conf->lic_cpts, conf->lic_ncpts,
+                                      conf->lic_ni_intf[0]);
+       if (!ni)
+               return -ENOMEM;
+
+       mutex_lock(&the_lnet.ln_api_mutex);
+
+       rc = lnet_add_net_common(net, tun);
+
+       mutex_unlock(&the_lnet.ln_api_mutex);
+
+       return rc;
+}
+
+int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf)
+{
+       struct lnet_net  *net;
+       struct lnet_ni *ni;
+       __u32 net_id = LNET_NIDNET(conf->lic_nid);
+       lnet_ping_info_t *pinfo;
+       lnet_handle_md_t  md_handle;
+       int               rc;
+       int               net_count;
+       __u32             addr;
+
+       /* don't allow userspace to shutdown the LOLND */
+       if (LNET_NETTYP(net_id) == LOLND)
+               return -EINVAL;
+
+       mutex_lock(&the_lnet.ln_api_mutex);
+
+       lnet_net_lock(0);
+
+       net = lnet_get_net_locked(net_id);
+       if (!net) {
+               CERROR("net %s not found\n",
+                      libcfs_net2str(net_id));
+               rc = -ENOENT;
+               goto net_unlock;
+       }
+
+       addr = LNET_NIDADDR(conf->lic_nid);
+       if (addr == 0) {
+               /* remove the entire net */
+               net_count = lnet_get_net_ni_count_locked(net);
+
+               lnet_net_unlock(0);
+
+               /* create and link a new ping info, before removing the old one */
+               rc = lnet_ping_info_setup(&pinfo, &md_handle,
+                                       lnet_get_ni_count() - net_count,
+                                       false);
+               if (rc != 0)
+                       goto out;
+
+               lnet_shutdown_lndnet(net);
+
+               if (lnet_count_acceptor_nets() == 0)
+                       lnet_acceptor_stop();
+
+               lnet_ping_target_update(pinfo, md_handle);
+
+               goto out;
+       }
+
+       ni = lnet_nid2ni_locked(conf->lic_nid, 0);
+       if (!ni) {
+               CERROR("nid %s not found \n",
+                      libcfs_nid2str(conf->lic_nid));
+               rc = -ENOENT;
+               goto net_unlock;
+       }
+
+       net_count = lnet_get_net_ni_count_locked(net);
+
+       lnet_net_unlock(0);
+
+       /* create and link a new ping info, before removing the old one */
+       rc = lnet_ping_info_setup(&pinfo, &md_handle,
+                                 lnet_get_ni_count() - 1, false);
+       if (rc != 0)
+               goto out;
+
+       lnet_shutdown_lndni(ni);
+
+       if (lnet_count_acceptor_nets() == 0)
+               lnet_acceptor_stop();
+
+       lnet_ping_target_update(pinfo, md_handle);
+
+       /* check if the net is empty and remove it if it is */
+       if (net_count == 1)
+               lnet_shutdown_lndnet(net);
+
+       goto out;
+
+net_unlock:
+       lnet_net_unlock(0);
+out:
+       mutex_unlock(&the_lnet.ln_api_mutex);
+
+       return rc;
+}
+
+/*
+ * lnet_dyn_add_net and lnet_dyn_del_net are now deprecated.
+ * They are only expected to be called for unique networks.
+ * That can be as a result of older DLC library
+ * calls. Multi-Rail DLC and beyond no longer uses these APIs.
+ */
+int
+lnet_dyn_add_net(struct lnet_ioctl_config_data *conf)
+{
+       struct lnet_net         *net;
+       struct list_head        net_head;
+       int                     rc;
+       struct lnet_ioctl_config_lnd_tunables tun;
+       char *nets = conf->cfg_config_u.cfg_net.net_intf;
+
+       INIT_LIST_HEAD(&net_head);
+
+       /* Create a net/ni structures for the network string */
+       rc = lnet_parse_networks(&net_head, nets, use_tcp_bonding);
+       if (rc <= 0)
+               return rc == 0 ? -EINVAL : rc;
+
+       mutex_lock(&the_lnet.ln_api_mutex);
+
+       if (rc > 1) {
+               rc = -EINVAL; /* only add one network per call */
+               goto failed;
+       }
+
+       net = list_entry(net_head.next, struct lnet_net, net_list);
+       list_del_init(&net->net_list);
+
+       LASSERT(lnet_net_unique(net->net_id, &the_lnet.ln_nets, NULL));
+
+       memset(&tun, sizeof(tun), 0);
+
+       tun.lt_cmn.lct_peer_timeout =
+         conf->cfg_config_u.cfg_net.net_peer_timeout;
+       tun.lt_cmn.lct_peer_tx_credits =
+         conf->cfg_config_u.cfg_net.net_peer_tx_credits;
+       tun.lt_cmn.lct_peer_rtr_credits =
+         conf->cfg_config_u.cfg_net.net_peer_rtr_credits;
+       tun.lt_cmn.lct_max_tx_credits =
+         conf->cfg_config_u.cfg_net.net_max_tx_credits;
+
+       rc = lnet_add_net_common(net, &tun);
+       if (rc != 0)
+               goto failed;
+
+       return 0;
+
+failed:
        mutex_unlock(&the_lnet.ln_api_mutex);
        while (!list_empty(&net_head)) {
                net = list_entry(net_head.next, struct lnet_net, net_list);
        mutex_unlock(&the_lnet.ln_api_mutex);
        while (!list_empty(&net_head)) {
                net = list_entry(net_head.next, struct lnet_net, net_list);
@@ -2209,7 +2522,7 @@ failed0:
 }
 
 int
 }
 
 int
-lnet_dyn_del_ni(__u32 net_id)
+lnet_dyn_del_net(__u32 net_id)
 {
        struct lnet_net  *net;
        struct lnet_ping_info *pinfo;
 {
        struct lnet_net  *net;
        struct lnet_ping_info *pinfo;
@@ -2335,6 +2648,25 @@ LNetCtl(unsigned int cmd, void *arg)
                                      &config->cfg_config_u.cfg_route.
                                        rtr_priority);
 
                                      &config->cfg_config_u.cfg_route.
                                        rtr_priority);
 
+       case IOC_LIBCFS_GET_LOCAL_NI: {
+               struct lnet_ioctl_config_ni *cfg_ni;
+               struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+               __u32 tun_size;
+
+               cfg_ni = arg;
+               /* get the tunables if they are available */
+               if (cfg_ni->lic_cfg_hdr.ioc_len <
+                   sizeof(*cfg_ni) + sizeof(*tun))
+                       return -EINVAL;
+
+               tun = (struct lnet_ioctl_config_lnd_tunables *)
+                               cfg_ni->lic_bulk;
+
+               tun_size = cfg_ni->lic_cfg_hdr.ioc_len - sizeof(*cfg_ni);
+
+               return lnet_get_ni_config(cfg_ni, tun, tun_size);
+       }
+
        case IOC_LIBCFS_GET_NET: {
                size_t total = sizeof(*config) +
                               sizeof(struct lnet_ioctl_net_config);
        case IOC_LIBCFS_GET_NET: {
                size_t total = sizeof(*config) +
                               sizeof(struct lnet_ioctl_net_config);
@@ -2505,8 +2837,22 @@ LNetCtl(unsigned int cmd, void *arg)
                data->ioc_count = rc;
                return 0;
        }
                data->ioc_count = rc;
                return 0;
        }
+
+       case IOC_LIBCFS_DBG: {
+               struct lnet_ioctl_dbg *dbg = arg;
+               struct lnet_dbg_task_info *dbg_info;
+               size_t total = sizeof(*dbg) + sizeof(*dbg_info);
+
+               if (dbg->dbg_hdr.ioc_len < total)
+                       return -EINVAL;
+
+               dbg_info = (struct lnet_dbg_task_info*) dbg->dbg_bulk;
+
+               return lnet_handle_dbg_task(dbg, dbg_info);
+       }
+
        default:
        default:
-               ni = lnet_net2ni(data->ioc_net);
+               ni = lnet_net2ni_addref(data->ioc_net);
                if (ni == NULL)
                        return -EINVAL;
 
                if (ni == NULL)
                        return -EINVAL;
 
@@ -2515,6 +2861,7 @@ LNetCtl(unsigned int cmd, void *arg)
                else
                        rc = ni->ni_net->net_lnd->lnd_ctl(ni, cmd, arg);
 
                else
                        rc = ni->ni_net->net_lnd->lnd_ctl(ni, cmd, arg);
 
+               lnet_ni_decref(ni);
                return rc;
        }
        /* not reached */
                return rc;
        }
        /* not reached */
index 34889e6..9469a11 100644 (file)
@@ -85,6 +85,9 @@ lnet_net_unique(__u32 net_id, struct list_head *netlist,
 {
        struct lnet_net  *net_l;
 
 {
        struct lnet_net  *net_l;
 
+       if (!netlist)
+               return true;
+
        list_for_each_entry(net_l, netlist, net_list) {
                if (net_l->net_id == net_id) {
                        if (net != NULL)
        list_for_each_entry(net_l, netlist, net_list) {
                if (net_l->net_id == net_id) {
                        if (net != NULL)
@@ -171,6 +174,7 @@ lnet_net_append_cpts(__u32 *cpts, __u32 ncpts, struct lnet_net *net)
                if (net->net_cpts == NULL)
                        return -ENOMEM;
                memcpy(net->net_cpts, cpts, ncpts);
                if (net->net_cpts == NULL)
                        return -ENOMEM;
                memcpy(net->net_cpts, cpts, ncpts);
+               net->net_ncpts = ncpts;
                return 0;
        }
 
                return 0;
        }
 
@@ -380,7 +384,8 @@ lnet_net_alloc(__u32 net_id, struct list_head *net_list)
        net->net_tunables.lct_peer_tx_credits = -1;
        net->net_tunables.lct_peer_rtr_credits = -1;
 
        net->net_tunables.lct_peer_tx_credits = -1;
        net->net_tunables.lct_peer_rtr_credits = -1;
 
-       list_add_tail(&net->net_list, net_list);
+       if (net_list)
+               list_add_tail(&net->net_list, net_list);
 
        return net;
 }
 
        return net;
 }
@@ -427,13 +432,11 @@ lnet_ni_add_interface(struct lnet_ni *ni, char *iface)
        return 0;
 }
 
        return 0;
 }
 
-/* allocate and add to the provided network */
-lnet_ni_t *
-lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
+static struct lnet_ni *
+lnet_ni_alloc_common(struct lnet_net *net, char *iface)
 {
        struct lnet_tx_queue    *tq;
        struct lnet_ni          *ni;
 {
        struct lnet_tx_queue    *tq;
        struct lnet_ni          *ni;
-       int                     rc;
        int                     i;
 
        if (iface != NULL)
        int                     i;
 
        if (iface != NULL)
@@ -466,7 +469,46 @@ lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
        cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
                INIT_LIST_HEAD(&tq->tq_delayed);
 
        cfs_percpt_for_each(tq, i, ni->ni_tx_queues)
                INIT_LIST_HEAD(&tq->tq_delayed);
 
-       if (el == NULL) {
+       ni->ni_net = net;
+       /* LND will fill in the address part of the NID */
+       ni->ni_nid = LNET_MKNID(net->net_id, 0);
+
+       /* Store net namespace in which current ni is being created */
+       if (current->nsproxy->net_ns != NULL)
+               ni->ni_net_ns = get_net(current->nsproxy->net_ns);
+       else
+               ni->ni_net_ns = NULL;
+
+       ni->ni_last_alive = ktime_get_real_seconds();
+       ni->ni_state = LNET_NI_STATE_INIT;
+       list_add_tail(&ni->ni_netlist, &net->net_ni_added);
+
+       /*
+        * if an interface name is provided then make sure to add in that
+        * interface name in NI
+        */
+       if (iface)
+               if (lnet_ni_add_interface(ni, iface) != 0)
+                       goto failed;
+
+       return ni;
+failed:
+       lnet_ni_free(ni);
+       return NULL;
+}
+
+/* allocate and add to the provided network */
+struct lnet_ni *
+lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
+{
+       struct lnet_ni          *ni;
+       int                     rc;
+
+       ni = lnet_ni_alloc_common(net, iface);
+       if (!ni)
+               return NULL;
+
+       if (!el) {
                ni->ni_cpts  = NULL;
                ni->ni_ncpts = LNET_CPT_NUMBER;
        } else {
                ni->ni_cpts  = NULL;
                ni->ni_ncpts = LNET_CPT_NUMBER;
        } else {
@@ -487,28 +529,42 @@ lnet_ni_alloc(struct lnet_net *net, struct cfs_expr_list *el, char *iface)
                ni->ni_ncpts = rc;
        }
 
                ni->ni_ncpts = rc;
        }
 
-       ni->ni_net = net;
-       /* LND will fill in the address part of the NID */
-       ni->ni_nid = LNET_MKNID(net->net_id, 0);
-
-       /* Store net namespace in which current ni is being created */
-       if (current->nsproxy->net_ns != NULL)
-               ni->ni_net_ns = get_net(current->nsproxy->net_ns);
-       else
-               ni->ni_net_ns = NULL;
-
-       ni->ni_last_alive = ktime_get_real_seconds();
-       ni->ni_state = LNET_NI_STATE_INIT;
        rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts, net);
        if (rc != 0)
                goto failed;
        rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts, net);
        if (rc != 0)
                goto failed;
-       list_add_tail(&ni->ni_netlist, &net->net_ni_added);
 
 
-       /* if an interface name is provided then make sure to add in that
-        * interface name in NI */
-       if (iface != NULL)
-               if (lnet_ni_add_interface(ni, iface) != 0)
+       return ni;
+failed:
+       lnet_ni_free(ni);
+       return NULL;
+}
+
+struct lnet_ni *
+lnet_ni_alloc_w_cpt_array(struct lnet_net *net, __u32 *cpts, __u32 ncpts,
+                         char *iface)
+{
+       struct lnet_ni          *ni;
+       int                     rc;
+
+       ni = lnet_ni_alloc_common(net, iface);
+       if (!ni)
+               return NULL;
+
+       if (ncpts == 0) {
+               ni->ni_cpts  = NULL;
+               ni->ni_ncpts = LNET_CPT_NUMBER;
+       } else {
+               size_t array_size = ncpts * sizeof(ni->ni_cpts[0]);
+               LIBCFS_ALLOC(ni->ni_cpts, array_size);
+               if (ni->ni_cpts == NULL)
                        goto failed;
                        goto failed;
+               memcpy(ni->ni_cpts, cpts, array_size);
+               ni->ni_ncpts = ncpts;
+       }
+
+       rc = lnet_net_append_cpts(ni->ni_cpts, ni->ni_ncpts, net);
+       if (rc != 0)
+               goto failed;
 
        return ni;
 failed:
 
        return ni;
 failed:
index c080eb4..a7190dd 100644 (file)
@@ -91,7 +91,7 @@ lnet_unconfigure (void)
 }
 
 static int
 }
 
 static int
-lnet_dyn_configure(struct libcfs_ioctl_hdr *hdr)
+lnet_dyn_configure_net(struct libcfs_ioctl_hdr *hdr)
 {
        struct lnet_ioctl_config_data *conf =
          (struct lnet_ioctl_config_data *)hdr;
 {
        struct lnet_ioctl_config_data *conf =
          (struct lnet_ioctl_config_data *)hdr;
@@ -101,19 +101,17 @@ lnet_dyn_configure(struct libcfs_ioctl_hdr *hdr)
                return -EINVAL;
 
        mutex_lock(&lnet_config_mutex);
                return -EINVAL;
 
        mutex_lock(&lnet_config_mutex);
-       if (!the_lnet.ln_niinit_self) {
+       if (the_lnet.ln_niinit_self)
+               rc = lnet_dyn_add_net(conf);
+       else
                rc = -EINVAL;
                rc = -EINVAL;
-               goto out_unlock;
-       }
-       rc = lnet_dyn_add_ni(LNET_PID_LUSTRE, conf);
-out_unlock:
        mutex_unlock(&lnet_config_mutex);
 
        return rc;
 }
 
 static int
        mutex_unlock(&lnet_config_mutex);
 
        return rc;
 }
 
 static int
-lnet_dyn_unconfigure(struct libcfs_ioctl_hdr *hdr)
+lnet_dyn_unconfigure_net(struct libcfs_ioctl_hdr *hdr)
 {
        struct lnet_ioctl_config_data *conf =
          (struct lnet_ioctl_config_data *) hdr;
 {
        struct lnet_ioctl_config_data *conf =
          (struct lnet_ioctl_config_data *) hdr;
@@ -123,12 +121,50 @@ lnet_dyn_unconfigure(struct libcfs_ioctl_hdr *hdr)
                return -EINVAL;
 
        mutex_lock(&lnet_config_mutex);
                return -EINVAL;
 
        mutex_lock(&lnet_config_mutex);
-       if (!the_lnet.ln_niinit_self) {
+       if (the_lnet.ln_niinit_self)
+               rc = lnet_dyn_del_net(conf->cfg_net);
+       else
+               rc = -EINVAL;
+       mutex_unlock(&lnet_config_mutex);
+
+       return rc;
+}
+
+static int
+lnet_dyn_configure_ni(struct libcfs_ioctl_hdr *hdr)
+{
+       struct lnet_ioctl_config_ni *conf =
+         (struct lnet_ioctl_config_ni *)hdr;
+       int                           rc;
+
+       if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf))
+               return -EINVAL;
+
+       mutex_lock(&lnet_config_mutex);
+       if (the_lnet.ln_niinit_self)
+               rc = lnet_dyn_add_ni(conf);
+       else
+               rc = -EINVAL;
+       mutex_unlock(&lnet_config_mutex);
+
+       return rc;
+}
+
+static int
+lnet_dyn_unconfigure_ni(struct libcfs_ioctl_hdr *hdr)
+{
+       struct lnet_ioctl_config_ni *conf =
+         (struct lnet_ioctl_config_ni *) hdr;
+       int                           rc;
+
+       if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf))
+               return -EINVAL;
+
+       mutex_lock(&lnet_config_mutex);
+       if (the_lnet.ln_niinit_self)
+               rc = lnet_dyn_del_ni(conf);
+       else
                rc = -EINVAL;
                rc = -EINVAL;
-               goto out_unlock;
-       }
-       rc = lnet_dyn_del_ni(conf->cfg_net);
-out_unlock:
        mutex_unlock(&lnet_config_mutex);
 
        return rc;
        mutex_unlock(&lnet_config_mutex);
 
        return rc;
@@ -155,10 +191,16 @@ lnet_ioctl(unsigned int cmd, struct libcfs_ioctl_hdr *hdr)
                return lnet_unconfigure();
 
        case IOC_LIBCFS_ADD_NET:
                return lnet_unconfigure();
 
        case IOC_LIBCFS_ADD_NET:
-               return lnet_dyn_configure(hdr);
+               return lnet_dyn_configure_net(hdr);
 
        case IOC_LIBCFS_DEL_NET:
 
        case IOC_LIBCFS_DEL_NET:
-               return lnet_dyn_unconfigure(hdr);
+               return lnet_dyn_unconfigure_net(hdr);
+
+       case IOC_LIBCFS_ADD_LOCAL_NI:
+               return lnet_dyn_configure_ni(hdr);
+
+       case IOC_LIBCFS_DEL_LOCAL_NI:
+               return lnet_dyn_unconfigure_ni(hdr);
 
        default:
                /* Passing LNET_PID_ANY only gives me a ref if the net is up
 
        default:
                /* Passing LNET_PID_ANY only gives me a ref if the net is up
index 4fd1e16..b46fa4d 100644 (file)
@@ -46,6 +46,28 @@ lnet_peer_remove_from_remote_list(struct lnet_peer_ni *lpni)
        }
 }
 
        }
 }
 
+void
+lnet_peer_net_added(struct lnet_net *net)
+{
+       struct lnet_peer_ni *lpni, *tmp;
+
+       list_for_each_entry_safe(lpni, tmp, &the_lnet.ln_remote_peer_ni_list,
+                                lpni_on_remote_peer_ni_list) {
+
+               if (LNET_NIDNET(lpni->lpni_nid) == net->net_id) {
+                       lpni->lpni_net = net;
+                       lpni->lpni_txcredits =
+                       lpni->lpni_mintxcredits =
+                               lpni->lpni_net->net_tunables.lct_peer_tx_credits;
+                       lpni->lpni_rtrcredits =
+                       lpni->lpni_minrtrcredits =
+                               lnet_peer_buffer_credits(lpni->lpni_net);
+
+                       lnet_peer_remove_from_remote_list(lpni);
+               }
+       }
+}
+
 static void
 lnet_peer_tables_destroy(void)
 {
 static void
 lnet_peer_tables_destroy(void)
 {
@@ -552,7 +574,8 @@ lnet_add_peer_ni_to_peer(lnet_nid_t key_nid, lnet_nid_t nid)
        lpni->lpni_net = lnet_get_net_locked(LNET_NIDNET(lpni->lpni_nid));
        if (lpni->lpni_net != NULL) {
                lpni->lpni_txcredits    =
        lpni->lpni_net = lnet_get_net_locked(LNET_NIDNET(lpni->lpni_nid));
        if (lpni->lpni_net != NULL) {
                lpni->lpni_txcredits    =
-               lpni->lpni_mintxcredits = lpni->lpni_net->net_peertxcredits;
+               lpni->lpni_mintxcredits =
+                       lpni->lpni_net->net_tunables.lct_peer_tx_credits;
                lpni->lpni_rtrcredits =
                lpni->lpni_minrtrcredits = lnet_peer_buffer_credits(lpni->lpni_net);
        } else {
                lpni->lpni_rtrcredits =
                lpni->lpni_minrtrcredits = lnet_peer_buffer_credits(lpni->lpni_net);
        } else {
@@ -944,7 +967,7 @@ int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid,
 
        peer_ni_info->cr_refcount = atomic_read(&lpni->lpni_refcount);
        peer_ni_info->cr_ni_peer_tx_credits = (lpni->lpni_net != NULL) ?
 
        peer_ni_info->cr_refcount = atomic_read(&lpni->lpni_refcount);
        peer_ni_info->cr_ni_peer_tx_credits = (lpni->lpni_net != NULL) ?
-               lpni->lpni_net->net_peertxcredits : 0;
+               lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0;
        peer_ni_info->cr_peer_tx_credits = lpni->lpni_txcredits;
        peer_ni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits;
        peer_ni_info->cr_peer_min_rtr_credits = lpni->lpni_mintxcredits;
        peer_ni_info->cr_peer_tx_credits = lpni->lpni_txcredits;
        peer_ni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits;
        peer_ni_info->cr_peer_min_rtr_credits = lpni->lpni_mintxcredits;
index 2a6f58f..a713566 100644 (file)
@@ -160,6 +160,32 @@ static yaml_token_handler dispatch_tbl[] = {
        [YAML_SCALAR_TOKEN] = yaml_scalar,
 };
 
        [YAML_SCALAR_TOKEN] = yaml_scalar,
 };
 
+/* dispatch table */
+static char *token_type_string[] = {
+       [YAML_NO_TOKEN] = "YAML_NO_TOKEN",
+       [YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
+       [YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
+       [YAML_VERSION_DIRECTIVE_TOKEN] = "YAML_VERSION_DIRECTIVE_TOKEN",
+       [YAML_TAG_DIRECTIVE_TOKEN] = "YAML_TAG_DIRECTIVE_TOKEN",
+       [YAML_DOCUMENT_START_TOKEN] = "YAML_DOCUMENT_START_TOKEN",
+       [YAML_DOCUMENT_END_TOKEN] = "YAML_DOCUMENT_END_TOKEN",
+       [YAML_BLOCK_SEQUENCE_START_TOKEN] = "YAML_BLOCK_SEQUENCE_START_TOKEN",
+       [YAML_BLOCK_MAPPING_START_TOKEN] = "YAML_BLOCK_MAPPING_START_TOKEN",
+       [YAML_BLOCK_END_TOKEN] = "YAML_BLOCK_END_TOKEN",
+       [YAML_FLOW_SEQUENCE_START_TOKEN] = "YAML_FLOW_SEQUENCE_START_TOKEN",
+       [YAML_FLOW_SEQUENCE_END_TOKEN] = "YAML_FLOW_SEQUENCE_END_TOKEN",
+       [YAML_FLOW_MAPPING_START_TOKEN] = "YAML_FLOW_MAPPING_START_TOKEN",
+       [YAML_FLOW_MAPPING_END_TOKEN] = "YAML_FLOW_MAPPING_END_TOKEN",
+       [YAML_BLOCK_ENTRY_TOKEN] = "YAML_BLOCK_ENTRY_TOKEN",
+       [YAML_FLOW_ENTRY_TOKEN] = "YAML_FLOW_ENTRY_TOKEN",
+       [YAML_KEY_TOKEN] = "YAML_KEY_TOKEN",
+       [YAML_VALUE_TOKEN] = "YAML_VALUE_TOKEN",
+       [YAML_ALIAS_TOKEN] = "YAML_ALIAS_TOKEN",
+       [YAML_ANCHOR_TOKEN] = "YAML_ANCHOR_TOKEN",
+       [YAML_TAG_TOKEN] = "YAML_TAG_TOKEN",
+       [YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
+};
+
 static void cYAML_ll_free(struct list_head *ll)
 {
        struct cYAML_ll *node, *tmp;
 static void cYAML_ll_free(struct list_head *ll)
 {
        struct cYAML_ll *node, *tmp;
@@ -1097,7 +1123,8 @@ failed:
 struct cYAML *cYAML_build_tree(char *yaml_file,
                               const char *yaml_blk,
                               size_t yaml_blk_size,
 struct cYAML *cYAML_build_tree(char *yaml_file,
                               const char *yaml_blk,
                               size_t yaml_blk_size,
-                              struct cYAML **err_rc)
+                              struct cYAML **err_rc,
+                              bool debug)
 {
        yaml_parser_t parser;
        yaml_token_t token;
 {
        yaml_parser_t parser;
        yaml_token_t token;
@@ -1145,6 +1172,11 @@ struct cYAML *cYAML_build_tree(char *yaml_file,
                */
                yaml_parser_scan(&parser, &token);
 
                */
                yaml_parser_scan(&parser, &token);
 
+               if (debug)
+                       fprintf(stderr, "token.type = %s: %s\n",
+                               token_type_string[token.type],
+                               (token.type == YAML_SCALAR_TOKEN) ?
+                               (char*)token.data.scalar.value : "");
                rc = dispatch_tbl[token.type](&token, &tree);
                if (rc != CYAML_ERROR_NONE) {
                        snprintf(err_str, sizeof(err_str),
                rc = dispatch_tbl[token.type](&token, &tree);
                if (rc != CYAML_ERROR_NONE) {
                        snprintf(err_str, sizeof(err_str),
index 98f7a27..c9c21c7 100644 (file)
@@ -86,7 +86,7 @@ typedef bool (*cYAML_walk_cb)(struct cYAML *, void *, void**);
  */
 struct cYAML *cYAML_build_tree(char *yaml_file, const char *yaml_blk,
                                size_t yaml_blk_size,
  */
 struct cYAML *cYAML_build_tree(char *yaml_file, const char *yaml_blk,
                                size_t yaml_blk_size,
-                               struct cYAML **err_str);
+                               struct cYAML **err_str, bool debug);
 
 /*
  * cYAML_print_tree
 
 /*
  * cYAML_print_tree
index 58ab064..54e9a26 100644 (file)
@@ -34,6 +34,6 @@ liblnetconfig_la_SOURCES  = liblnetconfig.c liblnetconfig.h \
                            liblnetconfig_lnd.c liblnd.h $(CYAML)
 liblnetconfig_la_CPPFLAGS = -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 \
                            -DLUSTRE_UTILS=1 -I$(top_builddir)/lnet/utils/cyaml
                            liblnetconfig_lnd.c liblnd.h $(CYAML)
 liblnetconfig_la_CPPFLAGS = -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64 \
                            -DLUSTRE_UTILS=1 -I$(top_builddir)/lnet/utils/cyaml
-liblnetconfig_la_LDFLAGS = -L$(top_builddir)/libcfs/libcfs -version-info 1:1:0
+liblnetconfig_la_LDFLAGS = -L$(top_builddir)/libcfs/libcfs -version-info 2:0:0
 
 EXTRA_DIST =
 
 EXTRA_DIST =
index 0de9fba..45f7893 100644 (file)
 #include "cyaml.h"
 
 int
 #include "cyaml.h"
 
 int
-lustre_interface_show_net(struct cYAML *interfaces, unsigned int index,
-                         bool detail, struct lnet_ioctl_config_data *data,
-                         struct lnet_ioctl_net_config *net_config);
+lustre_net_show_tunables(struct cYAML *tunables,
+                        struct lnet_ioctl_config_lnd_cmn_tunables *cmn);
+
+int
+lustre_ni_show_tunables(struct cYAML *lnd_tunables,
+                       __u32 net_type,
+                       struct lnet_lnd_tunables *lnd);
 
 void
 
 void
-lustre_interface_parse(struct cYAML *lndparams, const char *dev_name,
-                      struct lnet_ioctl_config_lnd_tunables *lnd_cfg);
+lustre_yaml_extract_lnd_tunables(struct cYAML *tree,
+                                __u32 net_type,
+                                struct lnet_lnd_tunables *tun);
 
 #endif /* LIB_LND_CONFIG_API_H */
 
 #endif /* LIB_LND_CONFIG_API_H */
index edfd5d5..0e960f4 100644 (file)
 
 #include <errno.h>
 #include <limits.h>
 
 #include <errno.h>
 #include <limits.h>
+#include <byteswap.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <net/if.h>
 #include <libcfs/util/ioctl.h>
 #include <lnet/lnetctl.h>
 #include <lnet/socklnd.h>
 #include "liblnd.h"
 #include <libcfs/util/ioctl.h>
 #include <lnet/lnetctl.h>
 #include <lnet/socklnd.h>
 #include "liblnd.h"
+#include <lnet/lnet.h>
+#include <libcfs/libcfs_string.h>
+#include <sys/types.h>
+#include <ifaddrs.h>
 #include "liblnetconfig.h"
 #include "cyaml.h"
 
 #include "liblnetconfig.h"
 #include "cyaml.h"
 
 #define ADD_CMD                        "add"
 #define DEL_CMD                        "del"
 #define SHOW_CMD               "show"
 #define ADD_CMD                        "add"
 #define DEL_CMD                        "del"
 #define SHOW_CMD               "show"
+#define DBG_CMD                        "dbg"
+
+/*
+ * lustre_lnet_ip_range_descr
+ *     Describes an IP range.
+ *     Each octect is an expression
+ */
+struct lustre_lnet_ip_range_descr {
+       struct list_head ipr_entry;
+       struct list_head ipr_expr;
+};
+
+/*
+ * lustre_lnet_ip2nets
+ *     Describes an ip2nets rule. This can be on a list of rules.
+ */
+struct lustre_lnet_ip2nets {
+       struct lnet_dlc_network_descr ip2nets_net;
+       struct list_head ip2nets_ip_ranges;
+};
+
+/*
+ * lustre_lnet_add_ip_range
+ * Formatting:
+ *     given a string of the format:
+ *     <expr.expr.expr.expr> parse each expr into
+ *     a lustre_lnet_ip_range_descr structure and insert on the list.
+ *
+ *     This function is called from
+ *             YAML on each ip-range.
+ *             As a result of lnetctl command
+ *             When building a NID or P2P selection rules
+ */
+int lustre_lnet_add_ip_range(struct list_head *list, char *str_ip_range)
+{
+       struct lustre_lnet_ip_range_descr *ip_range;
+       int rc;
+
+       ip_range = calloc(1, sizeof(*ip_range));
+       if (ip_range == NULL)
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
+
+       INIT_LIST_HEAD(&ip_range->ipr_entry);
+       INIT_LIST_HEAD(&ip_range->ipr_expr);
+
+       rc = cfs_ip_addr_parse(str_ip_range, strlen(str_ip_range),
+                              &ip_range->ipr_expr);
+       if (rc != 0)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       list_add_tail(&ip_range->ipr_entry, list);
+
+       return LUSTRE_CFG_RC_NO_ERR;
+}
+
+int lustre_lnet_add_intf_descr(struct list_head *list, char *intf, int len)
+{
+       char *open_sq_bracket = NULL, *close_sq_bracket = NULL,
+            *intf_name;
+       struct lnet_dlc_intf_descr *intf_descr = NULL;
+       int rc;
+       char intf_string[LNET_MAX_STR_LEN];
+
+       if (len >= LNET_MAX_STR_LEN)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       strncpy(intf_string, intf, len);
+       intf_string[len] = '\0';
+
+       intf_descr = calloc(1, sizeof(*intf_descr));
+       if (intf_descr == NULL)
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
+
+       INIT_LIST_HEAD(&intf_descr->intf_on_network);
+
+       intf_name = intf_string;
+       open_sq_bracket = strchr(intf_string, '[');
+       if (open_sq_bracket != NULL) {
+               close_sq_bracket = strchr(intf_string, ']');
+               if (close_sq_bracket == NULL) {
+                       free(intf_descr);
+                       return LUSTRE_CFG_RC_BAD_PARAM;
+               }
+               rc = cfs_expr_list_parse(open_sq_bracket,
+                                        strlen(open_sq_bracket), 0, UINT_MAX,
+                                        &intf_descr->cpt_expr);
+               if (rc < 0) {
+                       free(intf_descr);
+                       return LUSTRE_CFG_RC_BAD_PARAM;
+               }
+               strncpy(intf_descr->intf_name, intf_name,
+                       open_sq_bracket - intf_name);
+               intf_descr->intf_name[open_sq_bracket - intf_name] = '\0';
+       } else {
+               strcpy(intf_descr->intf_name, intf_name);
+               intf_descr->cpt_expr = NULL;
+       }
+
+       list_add_tail(&intf_descr->intf_on_network, list);
+
+       return LUSTRE_CFG_RC_NO_ERR;
+}
+
+void lustre_lnet_init_nw_descr(struct lnet_dlc_network_descr *nw_descr)
+{
+       if (nw_descr != NULL) {
+               INIT_LIST_HEAD(&nw_descr->network_on_rule);
+               INIT_LIST_HEAD(&nw_descr->nw_intflist);
+       }
+}
+
+/*
+ * format expected:
+ *     <intf>[<expr>], <intf>[<expr>],..
+ */
+int lustre_lnet_parse_interfaces(char *intf_str,
+                                struct lnet_dlc_network_descr *nw_descr)
+{
+       char *open_square;
+       char *close_square;
+       char *comma;
+       char *cur = intf_str, *next = NULL;
+       char *end = intf_str + strlen(intf_str);
+       int rc, len;
+       struct lnet_dlc_intf_descr *intf_descr, *tmp;
+
+       if (nw_descr == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       while (cur < end) {
+               open_square = strchr(cur, '[');
+               if (open_square != NULL) {
+                       close_square = strchr(cur, ']');
+                       if (close_square == NULL) {
+                               rc = LUSTRE_CFG_RC_BAD_PARAM;
+                               goto failed;
+                       }
+
+                       comma = strchr(cur, ',');
+                       if (comma != NULL && comma > close_square) {
+                               next = comma + 1;
+                               len = next - close_square;
+                       } else {
+                               len = strlen(cur);
+                               next = cur + len;
+                       }
+               } else {
+                       comma = strchr(cur, ',');
+                       if (comma != NULL) {
+                               next = comma + 1;
+                               len = comma - cur;
+                       } else {
+                               len = strlen(cur);
+                               next = cur + len;
+                       }
+               }
+
+               rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist, cur, len);
+               if (rc != LUSTRE_CFG_RC_NO_ERR)
+                       goto failed;
+
+               cur = next;
+       }
+
+       return LUSTRE_CFG_RC_NO_ERR;
+
+failed:
+       list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
+                                intf_on_network) {
+               if (intf_descr->cpt_expr != NULL)
+                       cfs_expr_list_free(intf_descr->cpt_expr);
+               free(intf_descr);
+       }
+
+       return rc;
+}
 
 int lustre_lnet_config_lib_init(void)
 {
 
 int lustre_lnet_config_lib_init(void)
 {
@@ -59,6 +241,11 @@ int lustre_lnet_config_lib_init(void)
                                LNET_DEV_MAJOR, LNET_DEV_MINOR);
 }
 
                                LNET_DEV_MAJOR, LNET_DEV_MINOR);
 }
 
+void lustre_lnet_config_lib_uninit(void)
+{
+       unregister_ioc_dev(LNET_DEV_ID);
+}
+
 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
                                 int seq_no, struct cYAML **err_rc)
 {
 int lustre_lnet_config_ni_system(bool up, bool load_ni_from_mod,
                                 int seq_no, struct cYAML **err_rc)
 {
@@ -619,42 +806,399 @@ out:
        return rc;
 }
 
        return rc;
 }
 
-int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
-                          int peer_to, int peer_cr, int peer_buf_cr,
-                          int credits, char *smp, int seq_no,
-                          struct lnet_ioctl_config_lnd_tunables *lnd_tunables,
-                          struct cYAML **err_rc)
+static int socket_intf_query(int request, char *intf,
+                            struct ifreq *ifr)
 {
 {
-       struct lnet_ioctl_config_lnd_tunables *lnd = NULL;
-       struct lnet_ioctl_config_data *data;
-       size_t ioctl_size = sizeof(*data);
-       char buf[LNET_MAX_STR_LEN];
+       int rc;
+       int sockfd;
+
+       if (strlen(intf) >= IFNAMSIZ || ifr == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sockfd < 0)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       strcpy(ifr->ifr_name, intf);
+       rc = ioctl(sockfd, request, ifr);
+       if (rc != 0)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       return 0;
+}
+
+/*
+ * for each interface in the array of interfaces find the IP address of
+ * that interface, create its nid and add it to an array of NIDs.
+ * Stop if any of the interfaces is down
+ */
+static int lustre_lnet_intf2nids(struct lnet_dlc_network_descr *nw,
+                                lnet_nid_t **nids, __u32 *nnids)
+{
+       int i = 0, count = 0, rc;
+       struct ifreq ifr;
+       __u32 ip;
+       struct lnet_dlc_intf_descr *intf;
+
+       if (nw == NULL || nids == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       list_for_each_entry(intf, &nw->nw_intflist, intf_on_network)
+               count++;
+
+       *nids = calloc(count, sizeof(lnet_nid_t));
+       if (*nids == NULL)
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
+
+       list_for_each_entry(intf, &nw->nw_intflist, intf_on_network) {
+               memset(&ifr, 0, sizeof(ifr));
+               rc = socket_intf_query(SIOCGIFFLAGS, intf->intf_name, &ifr);
+               if (rc != 0)
+                       goto failed;
+
+               if ((ifr.ifr_flags & IFF_UP) == 0) {
+                       rc = LUSTRE_CFG_RC_BAD_PARAM;
+                       goto failed;
+               }
+
+               memset(&ifr, 0, sizeof(ifr));
+               rc = socket_intf_query(SIOCGIFADDR, intf->intf_name, &ifr);
+               if (rc != 0)
+                       goto failed;
+
+               ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+               ip = bswap_32(ip);
+               (*nids)[i] = LNET_MKNID(nw->nw_id, ip);
+               i++;
+       }
+
+       *nnids = count;
+
+       return 0;
+
+failed:
+       free(*nids);
+       *nids = NULL;
+       return rc;
+}
+
+/*
+ * called repeatedly until a match or no more ip range
+ * What do you have?
+ *     ip_range expression
+ *     interface list with all the interface names.
+ *     all the interfaces in the system.
+ *
+ *     try to match the ip_range expr to one of the interfaces' IPs in
+ *     the system. If we hit a patch for an interface. Check if that
+ *     interface name is in the list.
+ *
+ *     If there are more than one interface in the list, then make sure
+ *     that the IPs for all of these interfaces match the ip ranges
+ *     given.
+ *
+ *     for each interface in intf_list
+ *             look up the intf name in ifa
+ *             if not there then no match
+ *             check ip obtained from ifa against a match to any of the
+ *             ip_ranges given.
+ *             If no match, then fail
+ *
+ *     The result is that all the interfaces have to match.
+ */
+int lustre_lnet_match_ip_to_intf(struct ifaddrs *ifa,
+                                struct list_head *intf_list,
+                                struct list_head *ip_ranges)
+{
+       int rc;
+       __u32 ip;
+       struct lnet_dlc_intf_descr *intf_descr;
+       struct ifaddrs *ifaddr = ifa;
+       struct lustre_lnet_ip_range_descr *ip_range;
+       int family;
+
+       /*
+        * if there are no explicit interfaces, and no ip ranges, then
+        * configure the first tcp interface we encounter.
+        */
+       if (list_empty(intf_list) && list_empty(ip_ranges)) {
+               for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+                       if (ifaddr->ifa_addr == NULL)
+                               continue;
+
+                       if ((ifaddr->ifa_flags & IFF_UP) == 0)
+                               continue;
+
+                       family = ifaddr->ifa_addr->sa_family;
+                       if (family == AF_INET) {
+                               rc = lustre_lnet_add_intf_descr
+                                       (intf_list, ifaddr->ifa_name,
+                                       strlen(ifaddr->ifa_name));
+
+                               if (rc != LUSTRE_CFG_RC_NO_ERR)
+                                       return rc;
+
+                               return LUSTRE_CFG_RC_MATCH;
+                       }
+               }
+               return LUSTRE_CFG_RC_NO_MATCH;
+       }
+
+       /*
+        * First interface which matches an IP pattern will be used
+        */
+       if (list_empty(intf_list)) {
+               /*
+                * no interfaces provided in the rule, but an ip range is
+                * provided, so try and match an interface to the ip
+                * range.
+                */
+               for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+                       if (ifaddr->ifa_addr == NULL)
+                               continue;
+
+                       if ((ifaddr->ifa_flags & IFF_UP) == 0)
+                               continue;
+
+                       family = ifaddr->ifa_addr->sa_family;
+                       if (family == AF_INET) {
+                               ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->
+                                       sin_addr.s_addr;
+
+                               list_for_each_entry(ip_range, ip_ranges,
+                                                   ipr_entry) {
+                                       rc = cfs_ip_addr_match(bswap_32(ip),
+                                                       &ip_range->ipr_expr);
+                                       if (!rc)
+                                               continue;
+
+                                       rc = lustre_lnet_add_intf_descr
+                                         (intf_list, ifaddr->ifa_name,
+                                          strlen(ifaddr->ifa_name));
+
+                                       if (rc != LUSTRE_CFG_RC_NO_ERR)
+                                               return rc;
+
+                                       return LUSTRE_CFG_RC_MATCH;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * If an interface is explicitly specified the ip-range might or
+        * might not be specified. if specified the interface needs to match the
+        * ip-range. If no ip-range then the interfaces are
+        * automatically matched if they are all up.
+        * If > 1 interfaces all the interfaces must match for the NI to
+        * be configured.
+        */
+       list_for_each_entry(intf_descr, intf_list, intf_on_network) {
+               for (ifaddr = ifa; ifaddr != NULL; ifaddr = ifaddr->ifa_next) {
+                       if (ifaddr->ifa_addr == NULL)
+                               continue;
+
+                       family = ifaddr->ifa_addr->sa_family;
+                       if (family == AF_INET &&
+                           strcmp(intf_descr->intf_name,
+                                  ifaddr->ifa_name) == 0)
+                               break;
+               }
+
+               if (ifaddr == NULL)
+                       return LUSTRE_CFG_RC_NO_MATCH;
+
+               if ((ifaddr->ifa_flags & IFF_UP) == 0)
+                       return LUSTRE_CFG_RC_NO_MATCH;
+
+               ip = ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr;
+
+               list_for_each_entry(ip_range, ip_ranges, ipr_entry) {
+                       rc = cfs_ip_addr_match(bswap_32(ip), &ip_range->ipr_expr);
+                       if (rc)
+                               break;
+                       else
+                               return LUSTRE_CFG_RC_NO_MATCH;
+               }
+       }
+
+       return LUSTRE_CFG_RC_MATCH;
+}
+
+int lustre_lnet_resolve_ip2nets_rule(struct lustre_lnet_ip2nets *ip2nets,
+                                    lnet_nid_t **nids, __u32 *nnids)
+{
+       struct ifaddrs *ifa;
        int rc = LUSTRE_CFG_RC_NO_ERR;
        int rc = LUSTRE_CFG_RC_NO_ERR;
+
+       rc = getifaddrs(&ifa);
+       if (rc < 0)
+               return -errno;
+
+       rc = lustre_lnet_match_ip_to_intf(ifa,
+                                         &ip2nets->ip2nets_net.nw_intflist,
+                                         &ip2nets->ip2nets_ip_ranges);
+       if (rc != LUSTRE_CFG_RC_MATCH) {
+               freeifaddrs(ifa);
+               return rc;
+       }
+
+       rc = lustre_lnet_intf2nids(&ip2nets->ip2nets_net, nids, nnids);
+       if (rc != LUSTRE_CFG_RC_NO_ERR) {
+               *nids = NULL;
+               *nnids = 0;
+       }
+
+       freeifaddrs(ifa);
+
+       return rc;
+}
+
+static int
+lustre_lnet_ioctl_config_ni(struct list_head *intf_list,
+                           struct lnet_ioctl_config_lnd_tunables *tunables,
+                           struct cfs_expr_list *global_cpts,
+                           lnet_nid_t *nids, char *err_str)
+{
+       char *data;
+       struct lnet_ioctl_config_ni *conf;
+       struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+       int rc = LUSTRE_CFG_RC_NO_ERR, i = 0;
+       size_t len;
+       int count;
+       struct lnet_dlc_intf_descr *intf_descr;
+       __u32 *cpt_array;
+       struct cfs_expr_list *cpt_expr;
+
+       list_for_each_entry(intf_descr, intf_list,
+                           intf_on_network) {
+               if (i == 0 && tunables != NULL)
+                       len = sizeof(struct lnet_ioctl_config_ni) +
+                             sizeof(struct lnet_ioctl_config_lnd_tunables);
+               else
+                       len = sizeof(struct lnet_ioctl_config_ni);
+
+               data = calloc(1, len);
+               conf = (struct lnet_ioctl_config_ni*) data;
+               if (i == 0 && tunables != NULL)
+                       tun = (struct lnet_ioctl_config_lnd_tunables*)
+                               (data + sizeof(*conf));
+
+               LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
+               conf->lic_cfg_hdr.ioc_len = len;
+               conf->lic_nid = nids[i];
+               strncpy(conf->lic_ni_intf[0], intf_descr->intf_name,
+                       LNET_MAX_STR_LEN);
+
+               if (intf_descr->cpt_expr != NULL)
+                       cpt_expr = intf_descr->cpt_expr;
+               else if (global_cpts != NULL)
+                       cpt_expr = global_cpts;
+               else
+                       cpt_expr = NULL;
+
+               if (cpt_expr != NULL) {
+                       count = cfs_expr_list_values(cpt_expr,
+                                                    LNET_MAX_SHOW_NUM_CPT,
+                                                    &cpt_array);
+                       if (count > 0) {
+                               memcpy(conf->lic_cpts, cpt_array,
+                                      sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
+                               free(cpt_array);
+                       } else {
+                               count = 0;
+                       }
+               } else {
+                       count = 0;
+               }
+
+               conf->lic_ncpts = count;
+
+               if (i == 0 && tunables != NULL)
+                       /* TODO put in the LND tunables */
+                       memcpy(tun, tunables, sizeof(*tunables));
+
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
+               if (rc < 0) {
+                       rc = -errno;
+                       snprintf(err_str,
+                                LNET_MAX_STR_LEN,
+                                "\"cannot add network: %s\"", strerror(errno));
+                       return rc;
+               }
+               i++;
+       }
+
+       return LUSTRE_CFG_RC_NO_ERR;
+}
+
+int
+lustre_lnet_config_ip2nets(struct lustre_lnet_ip2nets *ip2nets,
+                          struct lnet_ioctl_config_lnd_tunables *tunables,
+                          struct cfs_expr_list *global_cpts,
+                          int seq_no, struct cYAML **err_rc)
+{
+       lnet_nid_t *nids = NULL;
+       __u32 nnids = 0;
+       int rc;
        char err_str[LNET_MAX_STR_LEN];
 
        snprintf(err_str, sizeof(err_str), "\"success\"");
 
        char err_str[LNET_MAX_STR_LEN];
 
        snprintf(err_str, sizeof(err_str), "\"success\"");
 
-       /* No need to register lo */
-       if (net != NULL && !strcmp(net, "lo"))
-               return 0;
+       if (ip2nets == NULL ||
+           list_empty(&ip2nets->ip2nets_net.nw_intflist)) {
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"incomplete ip2nets information\"");
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
 
 
-       if (ip2net == NULL && (intf == NULL || net == NULL)) {
+       rc = lustre_lnet_resolve_ip2nets_rule(ip2nets, &nids, &nnids);
+       if (rc != LUSTRE_CFG_RC_NO_ERR && rc != LUSTRE_CFG_RC_MATCH) {
                snprintf(err_str,
                         sizeof(err_str),
                snprintf(err_str,
                         sizeof(err_str),
-                        "\"mandatory parameter '%s' not specified."
-                        " Optionally specify ip2net parameter\"",
-                        (intf == NULL && net == NULL) ? "net, if" :
-                        (intf == NULL) ? "if" : "net");
-               rc = LUSTRE_CFG_RC_MISSING_PARAM;
+                        "\"cannot resolve ip2nets rule\"");
                goto out;
        }
 
                goto out;
        }
 
-       if (peer_to != -1 && peer_to <= 0) {
+       rc = lustre_lnet_ioctl_config_ni(&ip2nets->ip2nets_net.nw_intflist,
+                                        tunables, global_cpts, nids,
+                                        err_str);
+       if (rc != LUSTRE_CFG_RC_NO_ERR)
+               free(nids);
+
+out:
+       cYAML_build_error(rc, seq_no, ADD_CMD, "ip2nets", err_str, err_rc);
+       return rc;
+}
+
+int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
+                         struct cfs_expr_list *global_cpts,
+                         char *ip2net,
+                         struct lnet_ioctl_config_lnd_tunables *tunables,
+                         int seq_no, struct cYAML **err_rc)
+{
+       char *data = NULL;
+       struct lnet_ioctl_config_ni *conf;
+       struct lnet_ioctl_config_lnd_tunables *tun = NULL;
+       char buf[LNET_MAX_STR_LEN];
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       char err_str[LNET_MAX_STR_LEN];
+       lnet_nid_t *nids = NULL;
+       __u32 nnids = 0;
+       size_t len;
+       int count;
+       struct lnet_dlc_intf_descr *intf_descr, *tmp;
+       __u32 *cpt_array;
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       if (ip2net == NULL && nw_descr == NULL) {
                snprintf(err_str,
                         sizeof(err_str),
                snprintf(err_str,
                         sizeof(err_str),
-                        "\"peer timeout %d, must be greater than 0\"",
-                        peer_to);
-               rc = LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM;
+                        "\"mandatory parameters not specified.\"");
+               rc = LUSTRE_CFG_RC_MISSING_PARAM;
                goto out;
        }
 
                goto out;
        }
 
@@ -667,58 +1211,125 @@ int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
                goto out;
        }
 
                goto out;
        }
 
-       if (lnd_tunables != NULL)
-               ioctl_size += sizeof(*lnd_tunables);
+       if (ip2net != NULL) {
+               if (tunables != NULL)
+                       len = sizeof(struct lnet_ioctl_config_ni) +
+                             sizeof(struct lnet_ioctl_config_lnd_tunables);
+               else
+                       len = sizeof(struct lnet_ioctl_config_ni);
+               data = calloc(1, len);
+               conf = (struct lnet_ioctl_config_ni*) data;
+               if (tunables != NULL)
+                       tun = (struct lnet_ioctl_config_lnd_tunables*)
+                               (data + sizeof(*conf));
+
+               LIBCFS_IOC_INIT_V2(*conf, lic_cfg_hdr);
+               conf->lic_cfg_hdr.ioc_len = len;
+               strncpy(conf->lic_legacy_ip2nets, ip2net,
+                       LNET_MAX_STR_LEN);
+
+               if (global_cpts != NULL) {
+                       count = cfs_expr_list_values(global_cpts,
+                                                    LNET_MAX_SHOW_NUM_CPT,
+                                                    &cpt_array);
+                       if (count > 0) {
+                               memcpy(conf->lic_cpts, cpt_array,
+                                      sizeof(cpt_array[0]) * LNET_MAX_STR_LEN);
+                               free(cpt_array);
+                       } else {
+                               count = 0;
+                       }
+               } else {
+                       count = 0;
+               }
 
 
-       data = calloc(1, ioctl_size);
-       if (data == NULL)
-               goto out;
+               conf->lic_ncpts = count;
 
 
-       if (ip2net == NULL)
-               snprintf(buf, sizeof(buf) - 1, "%s(%s)%s",
-                       net, intf,
-                       (smp) ? smp : "");
+               if (tunables != NULL)
+                       memcpy(tun, tunables, sizeof(*tunables));
 
 
-       LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
-       strncpy(data->cfg_config_u.cfg_net.net_intf,
-               (ip2net != NULL) ? ip2net : buf, sizeof(buf));
-       data->cfg_config_u.cfg_net.net_peer_timeout = peer_to;
-       data->cfg_config_u.cfg_net.net_peer_tx_credits = peer_cr;
-       data->cfg_config_u.cfg_net.net_peer_rtr_credits = peer_buf_cr;
-       data->cfg_config_u.cfg_net.net_max_tx_credits = credits;
-       /* Add in tunable settings if available */
-       if (lnd_tunables != NULL) {
-               lnd = (struct lnet_ioctl_config_lnd_tunables *)data->cfg_bulk;
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_LOCAL_NI, data);
+               if (rc < 0) {
+                       rc = -errno;
+                       snprintf(err_str,
+                               sizeof(err_str),
+                               "\"cannot add network: %s\"", strerror(errno));
+                       goto out;
+               }
 
 
-               data->cfg_hdr.ioc_len = ioctl_size;
-               memcpy(lnd, lnd_tunables, sizeof(*lnd_tunables));
+               goto out;
        }
 
        }
 
-       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_ADD_NET, data);
-       if (rc < 0) {
-               rc = -errno;
+       if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
+               return LUSTRE_CFG_RC_NO_ERR;
+
+       if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
                snprintf(err_str,
                snprintf(err_str,
-                        sizeof(err_str),
-                        "\"cannot add network: %s\"", strerror(errno));
+                       sizeof(err_str),
+                       "\"cannot parse net '%s'\"",
+                       libcfs_net2str(nw_descr->nw_id));
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
        }
        }
-       free(data);
+
+       if (list_empty(&nw_descr->nw_intflist)) {
+               snprintf(err_str,
+                       sizeof(err_str),
+                       "\"no interface name provided\"");
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
+       if (rc != 0) {
+               snprintf(err_str, sizeof(err_str),
+                        "\"bad parameter\"");
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
+               goto out;
+       }
+
+       rc = lustre_lnet_ioctl_config_ni(&nw_descr->nw_intflist,
+                                        tunables, global_cpts, nids,
+                                        err_str);
 
 out:
 
 out:
+       if (nw_descr != NULL) {
+               list_for_each_entry_safe(intf_descr, tmp,
+                                        &nw_descr->nw_intflist,
+                                        intf_on_network) {
+                       if (intf_descr->cpt_expr != NULL)
+                               cfs_expr_list_free(intf_descr->cpt_expr);
+                       free(intf_descr);
+               }
+       }
+
        cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
 
        cYAML_build_error(rc, seq_no, ADD_CMD, "net", err_str, err_rc);
 
+       if (nids)
+               free(nids);
+
+       if (data)
+               free(data);
+
        return rc;
 }
 
        return rc;
 }
 
-int lustre_lnet_del_net(char *nw, int seq_no, struct cYAML **err_rc)
+int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw_descr,
+                      int seq_no, struct cYAML **err_rc)
 {
 {
-       struct lnet_ioctl_config_data data;
-       __u32 net = LNET_NIDNET(LNET_NID_ANY);
-       int rc = LUSTRE_CFG_RC_NO_ERR;
+       struct lnet_ioctl_config_ni data;
+       int rc = LUSTRE_CFG_RC_NO_ERR, i;
        char err_str[LNET_MAX_STR_LEN];
        char err_str[LNET_MAX_STR_LEN];
+       lnet_nid_t *nids = NULL;
+       __u32 nnids = 0;
+       struct lnet_dlc_intf_descr *intf_descr, *tmp;
+
+       if (LNET_NETTYP(nw_descr->nw_id) == LOLND)
+               return LUSTRE_CFG_RC_NO_ERR;
 
        snprintf(err_str, sizeof(err_str), "\"success\"");
 
 
        snprintf(err_str, sizeof(err_str), "\"success\"");
 
-       if (nw == NULL) {
+       if (nw_descr == NULL) {
                snprintf(err_str,
                         sizeof(err_str),
                         "\"missing mandatory parameter\"");
                snprintf(err_str,
                         sizeof(err_str),
                         "\"missing mandatory parameter\"");
@@ -726,30 +1337,64 @@ int lustre_lnet_del_net(char *nw, int seq_no, struct cYAML **err_rc)
                goto out;
        }
 
                goto out;
        }
 
-       net = libcfs_str2net(nw);
-       if (net == LNET_NIDNET(LNET_NID_ANY)) {
+       if (nw_descr->nw_id == LNET_NIDNET(LNET_NID_ANY)) {
                snprintf(err_str,
                         sizeof(err_str),
                snprintf(err_str,
                         sizeof(err_str),
-                        "\"cannot parse net '%s'\"", nw);
+                        "\"cannot parse net '%s'\"",
+                        libcfs_net2str(nw_descr->nw_id));
                rc = LUSTRE_CFG_RC_BAD_PARAM;
                goto out;
        }
 
                rc = LUSTRE_CFG_RC_BAD_PARAM;
                goto out;
        }
 
-       LIBCFS_IOC_INIT_V2(data, cfg_hdr);
-       data.cfg_net = net;
-
-       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_NET, &data);
+       rc = lustre_lnet_intf2nids(nw_descr, &nids, &nnids);
        if (rc != 0) {
        if (rc != 0) {
-               rc = -errno;
-               snprintf(err_str,
-                        sizeof(err_str),
-                        "\"cannot delete network: %s\"", strerror(errno));
+               snprintf(err_str, sizeof(err_str),
+                        "\"bad parameter\"");
+               rc = LUSTRE_CFG_RC_BAD_PARAM;
                goto out;
        }
 
                goto out;
        }
 
+       /*
+        * no interfaces just the nw_id is specified
+        */
+       if (nnids == 0) {
+               nids = calloc(1, sizeof(*nids));
+               if (nids == NULL) {
+                       snprintf(err_str, sizeof(err_str),
+                               "\"out of memory\"");
+                       rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+                       goto out;
+               }
+               nids[0] = LNET_MKNID(nw_descr->nw_id, 0);
+               nnids = 1;
+       }
+
+       for (i = 0; i < nnids; i++) {
+               LIBCFS_IOC_INIT_V2(data, lic_cfg_hdr);
+               data.lic_nid = nids[i];
+
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DEL_LOCAL_NI, &data);
+               if (rc < 0) {
+                       rc = -errno;
+                       snprintf(err_str,
+                               sizeof(err_str),
+                               "\"cannot del network: %s\"", strerror(errno));
+               }
+       }
+
+       list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
+                                intf_on_network) {
+               if (intf_descr->cpt_expr != NULL)
+                       cfs_expr_list_free(intf_descr->cpt_expr);
+               free(intf_descr);
+       }
+
 out:
        cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
 
 out:
        cYAML_build_error(rc, seq_no, DEL_CMD, "net", err_str, err_rc);
 
+       if (nids != NULL)
+               free(nids);
+
        return rc;
 }
 
        return rc;
 }
 
@@ -757,29 +1402,31 @@ int lustre_lnet_show_net(char *nw, int detail, int seq_no,
                         struct cYAML **show_rc, struct cYAML **err_rc)
 {
        char *buf;
                         struct cYAML **show_rc, struct cYAML **err_rc)
 {
        char *buf;
-       struct lnet_ioctl_config_lnd_tunables *lnd_cfg;
-       struct lnet_ioctl_config_data *data;
-       struct lnet_ioctl_net_config *net_config;
+       struct lnet_ioctl_config_ni *ni_data;
+       struct lnet_ioctl_config_lnd_tunables *lnd;
        __u32 net = LNET_NIDNET(LNET_NID_ANY);
        __u32 net = LNET_NIDNET(LNET_NID_ANY);
+       __u32 prev_net = LNET_NIDNET(LNET_NID_ANY);
        int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
        int l_errno = 0;
        int rc = LUSTRE_CFG_RC_OUT_OF_MEM, i, j;
        int l_errno = 0;
-       struct cYAML *root = NULL, *tunables = NULL, *net_node = NULL,
-               *interfaces = NULL, *item = NULL, *first_seq = NULL;
+       struct cYAML *root = NULL, *tunables = NULL,
+               *net_node = NULL, *interfaces = NULL,
+               *item = NULL, *first_seq = NULL,
+               *tmp = NULL;
        int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
        char str_buf[str_buf_len];
        char *pos;
        char err_str[LNET_MAX_STR_LEN];
        int str_buf_len = LNET_MAX_SHOW_NUM_CPT * 2;
        char str_buf[str_buf_len];
        char *pos;
        char err_str[LNET_MAX_STR_LEN];
-       bool exist = false;
-       size_t buf_len;
+       bool exist = false, new_net = true;
+       int net_num = 0;
+       size_t buf_size = sizeof(*ni_data) + sizeof(*lnd);
 
        snprintf(err_str, sizeof(err_str), "\"out of memory\"");
 
 
        snprintf(err_str, sizeof(err_str), "\"out of memory\"");
 
-       buf_len = sizeof(*data) + sizeof(*net_config) + sizeof(*lnd_cfg);
-       buf = calloc(1, buf_len);
+       buf = calloc(1, buf_size);
        if (buf == NULL)
                goto out;
 
        if (buf == NULL)
                goto out;
 
-       data = (struct lnet_ioctl_config_data *)buf;
+       ni_data = (struct lnet_ioctl_config_ni *)buf;
 
        if (nw != NULL) {
                net = libcfs_str2net(nw);
 
        if (nw != NULL) {
                net = libcfs_str2net(nw);
@@ -802,70 +1449,90 @@ int lustre_lnet_show_net(char *nw, int detail, int seq_no,
 
        for (i = 0;; i++) {
                pos = str_buf;
 
        for (i = 0;; i++) {
                pos = str_buf;
+               __u32 rc_net;
 
 
-               memset(buf, 0, buf_len);
+               memset(buf, 0, buf_size);
 
 
-               LIBCFS_IOC_INIT_V2(*data, cfg_hdr);
+               LIBCFS_IOC_INIT_V2(*ni_data, lic_cfg_hdr);
                /*
                 * set the ioc_len to the proper value since INIT assumes
                 * size of data
                 */
                /*
                 * set the ioc_len to the proper value since INIT assumes
                 * size of data
                 */
-               data->cfg_hdr.ioc_len = buf_len;
-               data->cfg_count = i;
+               ni_data->lic_cfg_hdr.ioc_len = buf_size;
+               ni_data->lic_idx = i;
 
 
-               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_NET, data);
+               rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_GET_LOCAL_NI, ni_data);
                if (rc != 0) {
                        l_errno = errno;
                        break;
                }
 
                if (rc != 0) {
                        l_errno = errno;
                        break;
                }
 
+               rc_net = LNET_NIDNET(ni_data->lic_nid);
+
                /* filter on provided data */
                if (net != LNET_NIDNET(LNET_NID_ANY) &&
                /* filter on provided data */
                if (net != LNET_NIDNET(LNET_NID_ANY) &&
-                   net != LNET_NIDNET(data->cfg_nid))
+                   net != rc_net)
                        continue;
 
                /* default rc to -1 in case we hit the goto */
                rc = -1;
                exist = true;
 
                        continue;
 
                /* default rc to -1 in case we hit the goto */
                rc = -1;
                exist = true;
 
-               net_config = (struct lnet_ioctl_net_config *)data->cfg_bulk;
+               lnd = (struct lnet_ioctl_config_lnd_tunables *)ni_data->lic_bulk;
+
+               if (rc_net != prev_net) {
+                       prev_net = rc_net;
+                       new_net = true;
+                       net_num++;
+               }
+
+               if (new_net) {
+                       if (!cYAML_create_string(net_node, "net type",
+                                                libcfs_net2str(rc_net)))
+                               goto out;
+
+                       tmp = cYAML_create_seq(net_node, "local NI(s)");
+                       if (tmp == NULL)
+                               goto out;
+                       new_net = false;
+               }
 
                /* create the tree to be printed. */
 
                /* create the tree to be printed. */
-               item = cYAML_create_seq_item(net_node);
+               item = cYAML_create_seq_item(tmp);
                if (item == NULL)
                        goto out;
 
                if (first_seq == NULL)
                        first_seq = item;
 
                if (item == NULL)
                        goto out;
 
                if (first_seq == NULL)
                        first_seq = item;
 
-               if (cYAML_create_string(item, "net",
-                                       libcfs_net2str(
-                                               LNET_NIDNET(data->cfg_nid)))
-                   == NULL)
-                       goto out;
-
                if (cYAML_create_string(item, "nid",
                if (cYAML_create_string(item, "nid",
-                                       libcfs_nid2str(data->cfg_nid)) == NULL)
+                                       libcfs_nid2str(ni_data->lic_nid)) == NULL)
                        goto out;
 
                        goto out;
 
-               if (cYAML_create_string(item, "status",
-                                       (net_config->ni_status ==
+               if (cYAML_create_string(item,
+                                       "status",
+                                       (ni_data->lic_status ==
                                          LNET_NI_STATUS_UP) ?
                                            "up" : "down") == NULL)
                        goto out;
 
                /* don't add interfaces unless there is at least one
                 * interface */
                                          LNET_NI_STATUS_UP) ?
                                            "up" : "down") == NULL)
                        goto out;
 
                /* don't add interfaces unless there is at least one
                 * interface */
-               if (strlen(net_config->ni_interfaces[0]) > 0) {
+               if (strlen(ni_data->lic_ni_intf[0]) > 0) {
                        interfaces = cYAML_create_object(item, "interfaces");
                        if (interfaces == NULL)
                                goto out;
 
                        for (j = 0; j < LNET_MAX_INTERFACES; j++) {
                        interfaces = cYAML_create_object(item, "interfaces");
                        if (interfaces == NULL)
                                goto out;
 
                        for (j = 0; j < LNET_MAX_INTERFACES; j++) {
-                               if (lustre_interface_show_net(interfaces, j,
-                                                             detail, data,
-                                                             net_config) < 0)
-                                       goto out;
+                               if (strlen(ni_data->lic_ni_intf[j]) > 0) {
+                                       snprintf(str_buf,
+                                                sizeof(str_buf), "%d", j);
+                                       if (cYAML_create_string(interfaces,
+                                               str_buf,
+                                               ni_data->lic_ni_intf[j]) ==
+                                                       NULL)
+                                               goto out;
+                               }
                        }
                }
 
                        }
                }
 
@@ -873,45 +1540,42 @@ int lustre_lnet_show_net(char *nw, int detail, int seq_no,
                        char *limit;
 
                        tunables = cYAML_create_object(item, "tunables");
                        char *limit;
 
                        tunables = cYAML_create_object(item, "tunables");
-                       if (tunables == NULL)
+                       if (!tunables)
                                goto out;
 
                                goto out;
 
-                       if (cYAML_create_number(tunables, "peer_timeout",
-                                               data->cfg_config_u.cfg_net.
-                                               net_peer_timeout) == NULL)
+                       rc = lustre_net_show_tunables(tunables, &lnd->lt_cmn);
+                       if (rc != LUSTRE_CFG_RC_NO_ERR)
                                goto out;
 
                                goto out;
 
-                       if (cYAML_create_number(tunables, "peer_credits",
-                                               data->cfg_config_u.cfg_net.
-                                               net_peer_tx_credits) == NULL)
+                       tunables = cYAML_create_object(item, "lnd tunables");
+                       if (tunables == NULL)
                                goto out;
 
                                goto out;
 
-                       if (cYAML_create_number(tunables,
-                                               "peer_buffer_credits",
-                                               data->cfg_config_u.cfg_net.
-                                               net_peer_rtr_credits) == NULL)
+                       rc = lustre_ni_show_tunables(tunables, LNET_NETTYP(rc_net),
+                                                    &lnd->lt_tun);
+                       if (rc != LUSTRE_CFG_RC_NO_ERR)
                                goto out;
 
                                goto out;
 
-                       if (cYAML_create_number(tunables, "credits",
-                                               data->cfg_config_u.cfg_net.
-                                               net_max_tx_credits) == NULL)
+                       if (cYAML_create_number(item, "tcp bonding",
+                                               ni_data->lic_tcp_bonding)
+                                                       == NULL)
                                goto out;
 
                        /* out put the CPTs in the format: "[x,x,x,...]" */
                        limit = str_buf + str_buf_len - 3;
                        pos += snprintf(pos, limit - pos, "\"[");
                                goto out;
 
                        /* out put the CPTs in the format: "[x,x,x,...]" */
                        limit = str_buf + str_buf_len - 3;
                        pos += snprintf(pos, limit - pos, "\"[");
-                       for (j = 0 ; data->cfg_ncpts > 1 &&
-                               j < data->cfg_ncpts &&
+                       for (j = 0 ; ni_data->lic_ncpts >= 1 &&
+                               j < ni_data->lic_ncpts &&
                                pos < limit; j++) {
                                pos += snprintf(pos, limit - pos,
                                pos < limit; j++) {
                                pos += snprintf(pos, limit - pos,
-                                               "%d", net_config->ni_cpts[j]);
-                               if ((j + 1) < data->cfg_ncpts)
+                                               "%d", ni_data->lic_cpts[j]);
+                               if ((j + 1) < ni_data->lic_ncpts)
                                        pos += snprintf(pos, limit - pos, ",");
                        }
                        pos += snprintf(pos, 3, "]\"");
 
                                        pos += snprintf(pos, limit - pos, ",");
                        }
                        pos += snprintf(pos, 3, "]\"");
 
-                       if (data->cfg_ncpts > 1 &&
-                           cYAML_create_string(tunables, "CPT",
+                       if (ni_data->lic_ncpts >= 1 &&
+                           cYAML_create_string(item, "CPT",
                                                str_buf) == NULL)
                                goto out;
                }
                                                str_buf) == NULL)
                                goto out;
                }
@@ -1474,88 +2138,371 @@ static int handle_yaml_config_route(struct cYAML *tree, struct cYAML **show_rc,
                                        err_rc);
 }
 
                                        err_rc);
 }
 
-static int handle_yaml_config_net(struct cYAML *tree, struct cYAML **show_rc,
-                                 struct cYAML **err_rc)
+static void yaml_free_string_array(char **array, int num)
+{
+       int i;
+       char **sub_array = array;
+
+       for (i = 0; i < num; i++) {
+               if (*sub_array != NULL)
+                       free(sub_array);
+               sub_array++;
+       }
+       free(array);
+}
+
+/*
+ *    interfaces:
+ *        0: <intf_name>['['<expr>']']
+ *        1: <intf_name>['['<expr>']']
+ */
+static int yaml_copy_intf_info(struct cYAML *intf_tree,
+                              struct lnet_dlc_network_descr *nw_descr)
+{
+       struct cYAML *child = NULL;
+       int intf_num = 0, rc = LUSTRE_CFG_RC_NO_ERR;
+       struct lnet_dlc_intf_descr *intf_descr, *tmp;
+
+       if (intf_tree == NULL || nw_descr == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       /* now grab all the interfaces and their cpts */
+       child = intf_tree->cy_child;
+       while (child != NULL) {
+               if (child->cy_valuestring == NULL) {
+                       child = child->cy_next;
+                       continue;
+               }
+
+               if (strlen(child->cy_valuestring) >= LNET_MAX_STR_LEN)
+                       goto failed;
+
+               rc = lustre_lnet_add_intf_descr(&nw_descr->nw_intflist,
+                                               child->cy_valuestring,
+                                               strlen(child->cy_valuestring));
+               if (rc != LUSTRE_CFG_RC_NO_ERR)
+                       goto failed;
+
+               intf_num++;
+               child = child->cy_next;
+       }
+
+       if (intf_num == 0)
+               return LUSTRE_CFG_RC_MISSING_PARAM;
+
+       return intf_num;
+
+failed:
+       list_for_each_entry_safe(intf_descr, tmp, &nw_descr->nw_intflist,
+                                intf_on_network) {
+               if (intf_descr->cpt_expr != NULL)
+                       cfs_expr_list_free(intf_descr->cpt_expr);
+               free(intf_descr);
+       }
+
+       return rc;
+}
+
+static bool
+yaml_extract_cmn_tunables(struct cYAML *tree,
+                         struct lnet_ioctl_config_lnd_cmn_tunables *tunables,
+                         int *num_global_cpts,
+                         struct cfs_expr_list **global_cpts)
+{
+       struct cYAML *tun, *item, *smp;
+
+       tun = cYAML_get_object_item(tree, "tunables");
+       if (tun != NULL) {
+               item = cYAML_get_object_item(tun, "peer_timeout");
+               if (item != NULL)
+                       tunables->lct_peer_timeout = item->cy_valueint;
+               item = cYAML_get_object_item(tun, "peer_credits");
+               if (item != NULL)
+                       tunables->lct_peer_tx_credits = item->cy_valueint;
+               item = cYAML_get_object_item(tun, "peer_buffer_credits");
+               if (item != NULL)
+                       tunables->lct_peer_rtr_credits = item->cy_valueint;
+               item = cYAML_get_object_item(tun, "credits");
+               if (item != NULL)
+                       tunables->lct_max_tx_credits = item->cy_valueint;
+               smp = cYAML_get_object_item(tun, "CPT");
+               if (smp != NULL) {
+                       *num_global_cpts =
+                               cfs_expr_list_parse(smp->cy_valuestring,
+                                                strlen(smp->cy_valuestring),
+                                                0, UINT_MAX, global_cpts);
+               }
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool
+yaml_extract_tunables(struct cYAML *tree,
+                     struct lnet_ioctl_config_lnd_tunables *tunables,
+                     int *num_global_cpts,
+                     struct cfs_expr_list **global_cpts,
+                     __u32 net_type)
+{
+       bool rc;
+
+       rc = yaml_extract_cmn_tunables(tree, &tunables->lt_cmn,
+                                      num_global_cpts, global_cpts);
+
+       if (!rc)
+               return rc;
+
+       lustre_yaml_extract_lnd_tunables(tree, net_type,
+                                        &tunables->lt_tun);
+
+       return rc;
+}
+
+/*
+ * net:
+ *    - net type: <net>[<NUM>]
+  *      local NI(s):
+ *        - nid: <ip>@<net>[<NUM>]
+ *          status: up
+ *          interfaces:
+ *               0: <intf_name>['['<expr>']']
+ *               1: <intf_name>['['<expr>']']
+ *        tunables:
+ *               peer_timeout: <NUM>
+ *               peer_credits: <NUM>
+ *               peer_buffer_credits: <NUM>
+ *               credits: <NUM>
+*         lnd tunables:
+ *               peercredits_hiw: <NUM>
+ *               map_on_demand: <NUM>
+ *               concurrent_sends: <NUM>
+ *               fmr_pool_size: <NUM>
+ *               fmr_flush_trigger: <NUM>
+ *               fmr_cache: <NUM>
+ *
+ * At least one interface is required. If no interfaces are provided the
+ * network interface can not be configured.
+ */
+static int handle_yaml_config_ni(struct cYAML *tree, struct cYAML **show_rc,
+                                struct cYAML **err_rc)
 {
 {
-       struct cYAML *net, *intf, *tunables, *seq_no,
-             *peer_to = NULL, *peer_buf_cr = NULL, *peer_cr = NULL,
-             *credits = NULL, *ip2net = NULL, *smp = NULL, *child;
-       struct lnet_ioctl_config_lnd_tunables *lnd_tunables_p = NULL;
-       struct lnet_ioctl_config_lnd_tunables lnd_tunables;
-       char devs[LNET_MAX_STR_LEN];
-       char *loc = devs;
-       int size = LNET_MAX_STR_LEN;
-       int num;
-       bool intf_found = false;
+       struct cYAML *net, *intf, *seq_no, *ip2net = NULL, *local_nis = NULL,
+                    *item = NULL;
+       int num_entries = 0, num_global_cpts = 0, rc;
+       struct lnet_dlc_network_descr nw_descr;
+       struct cfs_expr_list *global_cpts = NULL;
+       struct lnet_ioctl_config_lnd_tunables tunables;
+       bool found = false;
+
+       memset(&tunables, 0, sizeof(tunables));
+
+       INIT_LIST_HEAD(&nw_descr.network_on_rule);
+       INIT_LIST_HEAD(&nw_descr.nw_intflist);
 
        ip2net = cYAML_get_object_item(tree, "ip2net");
 
        ip2net = cYAML_get_object_item(tree, "ip2net");
-       net = cYAML_get_object_item(tree, "net");
+       net = cYAML_get_object_item(tree, "net type");
+       if (net)
+               nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
+
+       /*
+        * if neither net nor ip2nets are present, then we can not
+        * configure the network.
+        */
+       if (!net && !ip2net)
+               return LUSTRE_CFG_RC_MISSING_PARAM;
+
+       local_nis = cYAML_get_object_item(tree, "local NI(s)");
+       if (local_nis == NULL)
+               return LUSTRE_CFG_RC_MISSING_PARAM;
+
+       if (!cYAML_is_sequence(local_nis))
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
+               intf = cYAML_get_object_item(item, "interfaces");
+               if (intf == NULL)
+                       continue;
+               num_entries = yaml_copy_intf_info(intf, &nw_descr);
+               if (num_entries <= 0) {
+                       cYAML_build_error(num_entries, -1, "ni", "add",
+                                       "bad interface list",
+                                       err_rc);
+                       return LUSTRE_CFG_RC_BAD_PARAM;
+               }
+       }
+
+       found = yaml_extract_tunables(tree, &tunables, &num_global_cpts,
+                                     &global_cpts,
+                                     LNET_NETTYP(nw_descr.nw_id));
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       rc = lustre_lnet_config_ni(&nw_descr,
+                                  (num_global_cpts > 0) ? global_cpts: NULL,
+                                  (ip2net) ? ip2net->cy_valuestring : NULL,
+                                  (found) ? &tunables: NULL,
+                                  (seq_no) ? seq_no->cy_valueint : -1,
+                                  err_rc);
+
+       if (global_cpts != NULL)
+               cfs_expr_list_free(global_cpts);
+
+       return rc;
+}
+
+/*
+ * ip2nets:
+ *  - net-spec: <tcp|o2ib|gni>[NUM]
+ *    interfaces:
+ *        0: <intf name>['['<expr>']']
+ *        1: <intf name>['['<expr>']']
+ *    ip-range:
+ *        0: <expr.expr.expr.expr>
+ *        1: <expr.expr.expr.expr>
+ */
+static int handle_yaml_config_ip2nets(struct cYAML *tree,
+                                     struct cYAML **show_rc,
+                                     struct cYAML **err_rc)
+{
+       struct cYAML *net, *ip_range, *item = NULL, *intf = NULL,
+                    *seq_no = NULL;
+       struct lustre_lnet_ip2nets ip2nets;
+       struct lustre_lnet_ip_range_descr *ip_range_descr = NULL,
+                                         *tmp = NULL;
+       int rc = LUSTRE_CFG_RC_NO_ERR, num_global_cpts = 0;
+       struct cfs_expr_list *global_cpts = NULL;
+       struct cfs_expr_list *el, *el_tmp;
+       struct lnet_ioctl_config_lnd_tunables tunables;
+       struct lnet_dlc_intf_descr *intf_descr, *intf_tmp;
+       bool found = false;
+
+       memset(&tunables, 0, sizeof(tunables));
+
+       /* initialize all lists */
+       INIT_LIST_HEAD(&ip2nets.ip2nets_ip_ranges);
+       INIT_LIST_HEAD(&ip2nets.ip2nets_net.network_on_rule);
+       INIT_LIST_HEAD(&ip2nets.ip2nets_net.nw_intflist);
+
+       net = cYAML_get_object_item(tree, "net-spec");
+       if (net == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       if (net != NULL && net->cy_valuestring == NULL)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       /* assign the network id */
+       ip2nets.ip2nets_net.nw_id = libcfs_str2net(net->cy_valuestring);
+       if (ip2nets.ip2nets_net.nw_id == LNET_NID_ANY)
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
        intf = cYAML_get_object_item(tree, "interfaces");
        if (intf != NULL) {
        intf = cYAML_get_object_item(tree, "interfaces");
        if (intf != NULL) {
-               /* grab all the interfaces */
-               child = intf->cy_child;
-               while (child != NULL && size > 0) {
-                       struct cYAML *lnd_params;
-
-                       if (child->cy_valuestring == NULL)
-                               goto ignore_child;
+               rc = yaml_copy_intf_info(intf, &ip2nets.ip2nets_net);
+               if (rc <= 0)
+                       return LUSTRE_CFG_RC_BAD_PARAM;
+       }
 
 
-                       if (loc > devs)
-                               num  = snprintf(loc, size, ",%s",
-                                               child->cy_valuestring);
-                       else
-                               num = snprintf(loc, size, "%s",
-                                              child->cy_valuestring);
-                       size -= num;
-                       loc += num;
-                       intf_found = true;
-
-                       lnd_params = cYAML_get_object_item(intf,
-                                                          "lnd tunables");
-                       if (lnd_params != NULL) {
-                               const char *dev_name = child->cy_valuestring;
-                               lnd_tunables_p = &lnd_tunables;
-
-                               lustre_interface_parse(lnd_params, dev_name,
-                                                      lnd_tunables_p);
+       ip_range = cYAML_get_object_item(tree, "ip-range");
+       if (ip_range != NULL) {
+               item = ip_range->cy_child;
+               while (item != NULL) {
+                       if (item->cy_valuestring == NULL) {
+                               item = item->cy_next;
+                               continue;
                        }
                        }
-ignore_child:
-                       child = child->cy_next;
+
+                       rc = lustre_lnet_add_ip_range(&ip2nets.ip2nets_ip_ranges,
+                                                     item->cy_valuestring);
+
+                       if (rc != LUSTRE_CFG_RC_NO_ERR)
+                               goto out;
+
+                       item = item->cy_next;
                }
        }
 
                }
        }
 
-       tunables = cYAML_get_object_item(tree, "tunables");
-       if (tunables != NULL) {
-               peer_to = cYAML_get_object_item(tunables, "peer_timeout");
-               peer_cr = cYAML_get_object_item(tunables, "peer_credits");
-               peer_buf_cr = cYAML_get_object_item(tunables,
-                                                   "peer_buffer_credits");
-               credits = cYAML_get_object_item(tunables, "credits");
-               smp = cYAML_get_object_item(tunables, "CPT");
+       found = yaml_extract_tunables(tree, &tunables, &num_global_cpts,
+                                     &global_cpts,
+                                     LNET_NETTYP(ip2nets.ip2nets_net.nw_id));
+
+       rc = lustre_lnet_config_ip2nets(&ip2nets,
+                       (found) ? &tunables : NULL,
+                       (num_global_cpts > 0) ? global_cpts : NULL,
+                       (seq_no) ? seq_no->cy_valueint : -1,
+                       err_rc);
+
+       /*
+        * don't stop because there was no match. Continue processing the
+        * rest of the rules. If non-match then nothing is configured
+        */
+       if (rc == LUSTRE_CFG_RC_NO_MATCH)
+               rc = LUSTRE_CFG_RC_NO_ERR;
+out:
+       list_for_each_entry_safe(intf_descr, intf_tmp,
+                                &ip2nets.ip2nets_net.nw_intflist,
+                                intf_on_network) {
+               if (intf_descr->cpt_expr != NULL)
+                       cfs_expr_list_free(intf_descr->cpt_expr);
+               free(intf_descr);
        }
        }
-       seq_no = cYAML_get_object_item(tree, "seq_no");
 
 
-       return lustre_lnet_config_net((net) ? net->cy_valuestring : NULL,
-                                     (intf_found) ? devs : NULL,
-                                     (ip2net) ? ip2net->cy_valuestring : NULL,
-                                     (peer_to) ? peer_to->cy_valueint : -1,
-                                     (peer_cr) ? peer_cr->cy_valueint : -1,
-                                     (peer_buf_cr) ?
-                                       peer_buf_cr->cy_valueint : -1,
-                                     (credits) ? credits->cy_valueint : -1,
-                                     (smp) ? smp->cy_valuestring : NULL,
-                                     (seq_no) ? seq_no->cy_valueint : -1,
-                                     lnd_tunables_p,
-                                     err_rc);
+       list_for_each_entry_safe(ip_range_descr, tmp,
+                                &ip2nets.ip2nets_ip_ranges,
+                                ipr_entry) {
+               list_for_each_entry_safe(el, el_tmp, &ip_range_descr->ipr_expr,
+                                        el_link)
+                       cfs_expr_list_free(el);
+               free(ip_range_descr);
+       }
+
+       return rc;
 }
 
 }
 
-static void yaml_free_string_array(char **str_array, int num)
+static int handle_yaml_del_ni(struct cYAML *tree, struct cYAML **show_rc,
+                             struct cYAML **err_rc)
 {
 {
-       int i;
+       struct cYAML *net = NULL, *intf = NULL, *seq_no = NULL, *item = NULL,
+                    *local_nis = NULL;
+       int num_entries, rc;
+       struct lnet_dlc_network_descr nw_descr;
+
+       INIT_LIST_HEAD(&nw_descr.network_on_rule);
+       INIT_LIST_HEAD(&nw_descr.nw_intflist);
+
+       net = cYAML_get_object_item(tree, "net type");
+       if (net != NULL)
+               nw_descr.nw_id = libcfs_str2net(net->cy_valuestring);
+
+       local_nis = cYAML_get_object_item(tree, "local NI(s)");
+       if (local_nis == NULL)
+               return LUSTRE_CFG_RC_MISSING_PARAM;
+
+       if (!cYAML_is_sequence(local_nis))
+               return LUSTRE_CFG_RC_BAD_PARAM;
+
+       while (cYAML_get_next_seq_item(local_nis, &item) != NULL) {
+               intf = cYAML_get_object_item(item, "interfaces");
+               if (intf == NULL)
+                       continue;
+               num_entries = yaml_copy_intf_info(intf, &nw_descr);
+               if (num_entries <= 0) {
+                       cYAML_build_error(num_entries, -1, "ni", "add",
+                                       "bad interface list",
+                                       err_rc);
+                       return LUSTRE_CFG_RC_BAD_PARAM;
+               }
+       }
 
 
-       for (i = 0; i < num; i++)
-               free(str_array[num]);
-       free(str_array);
+       seq_no = cYAML_get_object_item(tree, "seq_no");
+
+       rc = lustre_lnet_del_ni((net) ? &nw_descr : NULL,
+                               (seq_no) ? seq_no->cy_valueint : -1,
+                               err_rc);
+
+       return rc;
 }
 
 static int yaml_copy_peer_nids(struct cYAML *tree, char ***nidsppp)
 }
 
 static int yaml_copy_peer_nids(struct cYAML *tree, char ***nidsppp)
@@ -1715,19 +2662,6 @@ static int handle_yaml_del_route(struct cYAML *tree, struct cYAML **show_rc,
                                     err_rc);
 }
 
                                     err_rc);
 }
 
-static int handle_yaml_del_net(struct cYAML *tree, struct cYAML **show_rc,
-                              struct cYAML **err_rc)
-{
-       struct cYAML *net, *seq_no;
-
-       net = cYAML_get_object_item(tree, "net");
-       seq_no = cYAML_get_object_item(tree, "seq_no");
-
-       return lustre_lnet_del_net((net) ? net->cy_valuestring : NULL,
-                                  (seq_no) ? seq_no->cy_valueint : -1,
-                                  err_rc);
-}
-
 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
                                   struct cYAML **err_rc)
 {
 static int handle_yaml_del_routing(struct cYAML *tree, struct cYAML **show_rc,
                                   struct cYAML **err_rc)
 {
@@ -1825,7 +2759,8 @@ struct lookup_cmd_hdlr_tbl {
 
 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
        {"route", handle_yaml_config_route},
 
 static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
        {"route", handle_yaml_config_route},
-       {"net", handle_yaml_config_net},
+       {"net", handle_yaml_config_ni},
+       {"ip2nets", handle_yaml_config_ip2nets},
        {"peer", handle_yaml_config_peer},
        {"routing", handle_yaml_config_routing},
        {"buffers", handle_yaml_config_buffers},
        {"peer", handle_yaml_config_peer},
        {"routing", handle_yaml_config_routing},
        {"buffers", handle_yaml_config_buffers},
@@ -1834,7 +2769,7 @@ static struct lookup_cmd_hdlr_tbl lookup_config_tbl[] = {
 
 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
        {"route", handle_yaml_del_route},
 
 static struct lookup_cmd_hdlr_tbl lookup_del_tbl[] = {
        {"route", handle_yaml_del_route},
-       {"net", handle_yaml_del_net},
+       {"net", handle_yaml_del_ni},
        {"peer", handle_yaml_del_peer},
        {"routing", handle_yaml_del_routing},
        {NULL, NULL}
        {"peer", handle_yaml_del_peer},
        {"routing", handle_yaml_del_routing},
        {NULL, NULL}
@@ -1873,7 +2808,7 @@ static int lustre_yaml_cb_helper(char *f, struct lookup_cmd_hdlr_tbl *table,
        char err_str[LNET_MAX_STR_LEN];
        int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
 
        char err_str[LNET_MAX_STR_LEN];
        int rc = LUSTRE_CFG_RC_NO_ERR, return_rc = LUSTRE_CFG_RC_NO_ERR;
 
-       tree = cYAML_build_tree(f, NULL, 0, err_rc);
+       tree = cYAML_build_tree(f, NULL, 0, err_rc, false);
        if (tree == NULL)
                return LUSTRE_CFG_RC_BAD_PARAM;
 
        if (tree == NULL)
                return LUSTRE_CFG_RC_BAD_PARAM;
 
@@ -1928,3 +2863,47 @@ int lustre_yaml_show(char *f, struct cYAML **show_rc, struct cYAML **err_rc)
        return lustre_yaml_cb_helper(f, lookup_show_tbl,
                                     show_rc, err_rc);
 }
        return lustre_yaml_cb_helper(f, lookup_show_tbl,
                                     show_rc, err_rc);
 }
+
+int lustre_lnet_send_dbg_task(enum lnet_dbg_task dbg_task,
+                             struct lnet_dbg_task_info *dbg_info,
+                             struct cYAML **show_rc,
+                             struct cYAML **err_rc)
+{
+       struct lnet_ioctl_dbg *dbg;
+       struct lnet_dbg_task_info *info;
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+       char err_str[LNET_MAX_STR_LEN];
+
+       snprintf(err_str, sizeof(err_str), "\"success\"");
+
+       dbg = calloc(1, sizeof(*dbg) + sizeof(*info));
+       if (!dbg) {
+               snprintf(err_str, sizeof(err_str), "\"out of memory\"");
+               rc = LUSTRE_CFG_RC_OUT_OF_MEM;
+               goto out;
+       }
+
+       info = (struct lnet_dbg_task_info *)dbg->dbg_bulk;
+
+       LIBCFS_IOC_INIT_V2(*dbg, dbg_hdr);
+
+       dbg->dbg_task = dbg_task;
+       if (dbg_info)
+               memcpy(info, dbg_info, sizeof(*info));
+
+       rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_DBG, dbg);
+       if (rc != 0) {
+               rc = -errno;
+               snprintf(err_str,
+                        sizeof(err_str),
+                        "\"debug task failed %s\"", strerror(errno));
+               goto out;
+       }
+
+out:
+       cYAML_build_error(rc, -1, DBG_CMD,
+                        "debug", err_str, err_rc);
+
+       return rc;
+}
+
index 38dce8c..8eebfc2 100644 (file)
 #define LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM       -3
 #define LUSTRE_CFG_RC_OUT_OF_MEM               -4
 #define LUSTRE_CFG_RC_GENERIC_ERR              -5
 #define LUSTRE_CFG_RC_OUT_OF_RANGE_PARAM       -3
 #define LUSTRE_CFG_RC_OUT_OF_MEM               -4
 #define LUSTRE_CFG_RC_GENERIC_ERR              -5
+#define LUSTRE_CFG_RC_NO_MATCH                 -6
+#define LUSTRE_CFG_RC_MATCH                    -7
+
+#include <lnet/lnet.h>
+#include <libcfs/libcfs_string.h>
+
+struct lnet_dlc_network_descr {
+       struct list_head network_on_rule;
+       __u32 nw_id;
+       struct list_head nw_intflist;
+};
+
+struct lnet_dlc_intf_descr {
+       struct list_head intf_on_network;
+       char intf_name[LNET_MAX_STR_LEN];
+       struct cfs_expr_list *cpt_expr;
+};
 
 /* forward declaration of the cYAML structure. */
 struct cYAML;
 
 /* forward declaration of the cYAML structure. */
 struct cYAML;
@@ -47,6 +64,12 @@ struct cYAML;
 int lustre_lnet_config_lib_init();
 
 /*
 int lustre_lnet_config_lib_init();
 
 /*
+ * lustre_lnet_config_lib_uninit
+ *     Uninitialize the DLC Library
+ */
+void lustre_lnet_config_lib_uninit();
+
+/*
  * lustre_lnet_config_ni_system
  *   Initialize/Uninitialize the lnet NI system.
  *
  * lustre_lnet_config_ni_system
  *   Initialize/Uninitialize the lnet NI system.
  *
@@ -108,39 +131,36 @@ int lustre_lnet_show_route(char *nw, char *gw,
                           struct cYAML **err_rc);
 
 /*
                           struct cYAML **err_rc);
 
 /*
- * lustre_lnet_config_net
- *   Send down an IOCTL to configure a network.
+ * lustre_lnet_config_ni
+ *   Send down an IOCTL to configure a network interface. It implicitly
+ *   creates a network if one doesn't exist..
  *
  *
- *   net - the network name
- *   intf - the interface of the network of the form net_name(intf)
+ *   nw_descr - network and interface descriptor
+ *   global_cpts - globally defined CPTs
  *   ip2net - this parameter allows configuring multiple networks.
  *     it takes precedence over the net and intf parameters
  *   ip2net - this parameter allows configuring multiple networks.
  *     it takes precedence over the net and intf parameters
- *   peer_to - peer timeout
- *   peer_cr - peer credit
- *   peer_buf_cr - peer buffer credits
- *       - the above are LND tunable parameters and are optional
- *   credits - network interface credits
- *   smp - cpu affinity
+ *   tunables - LND tunables
  *   seq_no - sequence number of the request
  *   lnd_tunables - lnet specific tunable parameters
  *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
  */
  *   seq_no - sequence number of the request
  *   lnd_tunables - lnet specific tunable parameters
  *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
  */
-int lustre_lnet_config_net(char *net, char *intf, char *ip2net,
-                          int peer_to, int peer_cr, int peer_buf_cr,
-                          int credits, char *smp, int seq_no,
-                          struct lnet_ioctl_config_lnd_tunables *lnd_tunables,
-                          struct cYAML **err_rc);
+int lustre_lnet_config_ni(struct lnet_dlc_network_descr *nw_descr,
+                         struct cfs_expr_list *global_cpts,
+                         char *ip2net,
+                         struct lnet_ioctl_config_lnd_tunables *tunables,
+                         int seq_no, struct cYAML **err_rc);
 
 /*
 
 /*
- * lustre_lnet_del_net
- *   Send down an IOCTL to delete a network.
+ * lustre_lnet_del_ni
+ *   Send down an IOCTL to delete a network interface. It implicitly
+ *   deletes a network if it becomes empty of nis
  *
  *
- *   nw - network to delete.
+ *   nw  - network and interface list
  *   seq_no - sequence number of the request
  *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
  */
  *   seq_no - sequence number of the request
  *   err_rc - [OUT] struct cYAML tree describing the error. Freed by caller
  */
-int lustre_lnet_del_net(char *nw, int seq_no,
-                       struct cYAML **err_rc);
+int lustre_lnet_del_ni(struct lnet_dlc_network_descr *nw,
+                      int seq_no, struct cYAML **err_rc);
 
 /*
  * lustre_lnet_show_net
 
 /*
  * lustre_lnet_show_net
@@ -289,4 +309,34 @@ int lustre_yaml_del(char *f, struct cYAML **err_rc);
 int lustre_yaml_show(char *f, struct cYAML **show_rc,
                     struct cYAML **err_rc);
 
 int lustre_yaml_show(char *f, struct cYAML **show_rc,
                     struct cYAML **err_rc);
 
+/*
+ * lustre_lnet_init_nw_descr
+ *     initialize the network descriptor structure for use
+ */
+void lustre_lnet_init_nw_descr(struct lnet_dlc_network_descr *nw_descr);
+
+/*
+ * lustre_lnet_parse_interfaces
+ *     prase an interface string and populate descriptor structures
+ *             intf_str - interface string of the format
+ *                     <intf>[<expr>], <intf>[<expr>],..
+ *             nw_descr - network descriptor to populate
+ *             init - True to initialize nw_descr
+ */
+int lustre_lnet_parse_interfaces(char *intf_str,
+                                struct lnet_dlc_network_descr *nw_descr);
+
+/*
+ * lustre_lnet_send_dbg_task
+ *     send a debug task to be carried out in the kernel. This API will
+ *     not be exposed to the user through lnetctl utility. It can only be
+ *     executed by being called directly.
+ *             dbg_task: The task to be carried out
+ *             dbg_info: task specific information
+ */
+int lustre_lnet_send_dbg_task(enum lnet_dbg_task dbg_task,
+                             struct lnet_dbg_task_info *dbg_info,
+                             struct cYAML **show_rc,
+                             struct cYAML **err_rc);
+
 #endif /* LIB_LNET_CONFIG_API_H */
 #endif /* LIB_LNET_CONFIG_API_H */
index 5f68b47..688cb98 100644 (file)
@@ -25,6 +25,8 @@
  * Author:
  *   James Simmons <jsimmons@infradead.org>
  */
  * Author:
  *   James Simmons <jsimmons@infradead.org>
  */
+
+#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <libcfs/util/ioctl.h>
 #include <stdio.h>
 #include <string.h>
 #include <libcfs/util/ioctl.h>
 #include "cyaml.h"
 
 static int
 #include "cyaml.h"
 
 static int
-lustre_ko2iblnd_show_net(struct cYAML *lndparams,
-                        struct lnet_ioctl_config_lnd_tunables *tunables)
+lustre_o2iblnd_show_tun(struct cYAML *lndparams,
+                       struct lnet_ioctl_config_o2iblnd_tunables *lnd_cfg)
 {
 {
-       struct lnet_ioctl_config_o2iblnd_tunables *lnd_cfg;
-
-       lnd_cfg = &tunables->lt_tun_u.lt_o2ib;
-
        if (cYAML_create_number(lndparams, "peercredits_hiw",
                                lnd_cfg->lnd_peercredits_hiw) == NULL)
        if (cYAML_create_number(lndparams, "peercredits_hiw",
                                lnd_cfg->lnd_peercredits_hiw) == NULL)
-               return -1;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
 
        if (cYAML_create_number(lndparams, "map_on_demand",
                                lnd_cfg->lnd_map_on_demand) == NULL)
 
        if (cYAML_create_number(lndparams, "map_on_demand",
                                lnd_cfg->lnd_map_on_demand) == NULL)
-               return -1;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
 
        if (cYAML_create_number(lndparams, "concurrent_sends",
                                lnd_cfg->lnd_concurrent_sends) == NULL)
 
        if (cYAML_create_number(lndparams, "concurrent_sends",
                                lnd_cfg->lnd_concurrent_sends) == NULL)
-               return -1;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
 
        if (cYAML_create_number(lndparams, "fmr_pool_size",
                                lnd_cfg->lnd_fmr_pool_size) == NULL)
 
        if (cYAML_create_number(lndparams, "fmr_pool_size",
                                lnd_cfg->lnd_fmr_pool_size) == NULL)
-               return -1;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
 
        if (cYAML_create_number(lndparams, "fmr_flush_trigger",
                                lnd_cfg->lnd_fmr_flush_trigger) == NULL)
 
        if (cYAML_create_number(lndparams, "fmr_flush_trigger",
                                lnd_cfg->lnd_fmr_flush_trigger) == NULL)
-               return -1;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
 
        if (cYAML_create_number(lndparams, "fmr_cache",
                                lnd_cfg->lnd_fmr_cache) == NULL)
 
        if (cYAML_create_number(lndparams, "fmr_cache",
                                lnd_cfg->lnd_fmr_cache) == NULL)
-               return -1;
-       return 0;
+               return LUSTRE_CFG_RC_OUT_OF_MEM;
+
+       return LUSTRE_CFG_RC_NO_ERR;
 }
 
 int
 }
 
 int
-lustre_interface_show_net(struct cYAML *interfaces, unsigned int index,
-                         bool detail, struct lnet_ioctl_config_data *data,
-                         struct lnet_ioctl_net_config *net_config)
+lustre_net_show_tunables(struct cYAML *tunables,
+                        struct lnet_ioctl_config_lnd_cmn_tunables *cmn)
 {
 {
-       char ni_index[2]; /* LNET_MAX_INTERFACES is only 16 */
-
-       if (strlen(net_config->ni_interfaces[index]) == 0)
-               return 0;
-
-       snprintf(ni_index, sizeof(ni_index), "%d", index);
-       if (cYAML_create_string(interfaces, ni_index,
-                               net_config->ni_interfaces[index]) == NULL)
-               return -1;
-
-       if (detail) {
-               __u32 net = LNET_NETTYP(LNET_NIDNET(data->cfg_nid));
-               struct lnet_ioctl_config_lnd_tunables *lnd_cfg;
-               struct cYAML *lndparams;
-
-               if (data->cfg_config_u.cfg_net.net_interface_count == 0 ||
-                   net != O2IBLND)
-                       return 0;
-
-               lndparams = cYAML_create_object(interfaces, "lnd tunables");
-               if (lndparams == NULL)
-                       return -1;
-
-               lnd_cfg = (struct lnet_ioctl_config_lnd_tunables *)net_config->cfg_bulk;
-               if (lustre_ko2iblnd_show_net(lndparams, lnd_cfg) < 0)
-                       return -1;
-       }
-       return 0;
+
+
+       if (cYAML_create_number(tunables, "peer_timeout",
+                               cmn->lct_peer_timeout)
+                                       == NULL)
+               goto out;
+
+       if (cYAML_create_number(tunables, "peer_credits",
+                               cmn->lct_peer_tx_credits)
+                                       == NULL)
+               goto out;
+
+       if (cYAML_create_number(tunables,
+                               "peer_buffer_credits",
+                               cmn->lct_peer_rtr_credits)
+                                       == NULL)
+               goto out;
+
+       if (cYAML_create_number(tunables, "credits",
+                               cmn->lct_max_tx_credits)
+                                       == NULL)
+               goto out;
+
+       return LUSTRE_CFG_RC_NO_ERR;
+
+out:
+       return LUSTRE_CFG_RC_OUT_OF_MEM;
+}
+
+int
+lustre_ni_show_tunables(struct cYAML *lnd_tunables,
+                       __u32 net_type,
+                       struct lnet_lnd_tunables *lnd)
+{
+       int rc = LUSTRE_CFG_RC_NO_ERR;
+
+       if (net_type == O2IBLND)
+               rc = lustre_o2iblnd_show_tun(lnd_tunables,
+                                            &lnd->lnd_tun_u.lnd_o2ib);
+
+       return rc;
 }
 
 static void
 }
 
 static void
-lustre_ko2iblnd_parse_net(struct cYAML *lndparams,
-                         struct lnet_ioctl_config_lnd_tunables *lnd_cfg)
+yaml_extract_o2ib_tun(struct cYAML *tree,
+                     struct lnet_ioctl_config_o2iblnd_tunables *lnd_cfg)
 {
        struct cYAML *map_on_demand = NULL, *concurrent_sends = NULL;
        struct cYAML *fmr_pool_size = NULL, *fmr_cache = NULL;
 {
        struct cYAML *map_on_demand = NULL, *concurrent_sends = NULL;
        struct cYAML *fmr_pool_size = NULL, *fmr_cache = NULL;
-       struct cYAML *fmr_flush_trigger = NULL;
+       struct cYAML *fmr_flush_trigger = NULL, *lndparams = NULL;
+
+       lndparams = cYAML_get_object_item(tree, "lnd tunables");
+       if (!lndparams)
+               return;
 
        map_on_demand = cYAML_get_object_item(lndparams, "map_on_demand");
 
        map_on_demand = cYAML_get_object_item(lndparams, "map_on_demand");
-       lnd_cfg->lt_tun_u.lt_o2ib.lnd_map_on_demand =
+       lnd_cfg->lnd_map_on_demand =
                (map_on_demand) ? map_on_demand->cy_valueint : 0;
 
        concurrent_sends = cYAML_get_object_item(lndparams, "concurrent_sends");
                (map_on_demand) ? map_on_demand->cy_valueint : 0;
 
        concurrent_sends = cYAML_get_object_item(lndparams, "concurrent_sends");
-       lnd_cfg->lt_tun_u.lt_o2ib.lnd_concurrent_sends =
+       lnd_cfg->lnd_concurrent_sends =
                (concurrent_sends) ? concurrent_sends->cy_valueint : 0;
 
        fmr_pool_size = cYAML_get_object_item(lndparams, "fmr_pool_size");
                (concurrent_sends) ? concurrent_sends->cy_valueint : 0;
 
        fmr_pool_size = cYAML_get_object_item(lndparams, "fmr_pool_size");
-       lnd_cfg->lt_tun_u.lt_o2ib.lnd_fmr_pool_size =
+       lnd_cfg->lnd_fmr_pool_size =
                (fmr_pool_size) ? fmr_pool_size->cy_valueint : 0;
 
        fmr_flush_trigger = cYAML_get_object_item(lndparams,
                                                  "fmr_flush_trigger");
                (fmr_pool_size) ? fmr_pool_size->cy_valueint : 0;
 
        fmr_flush_trigger = cYAML_get_object_item(lndparams,
                                                  "fmr_flush_trigger");
-       lnd_cfg->lt_tun_u.lt_o2ib.lnd_fmr_flush_trigger =
+       lnd_cfg->lnd_fmr_flush_trigger =
                (fmr_flush_trigger) ? fmr_flush_trigger->cy_valueint : 0;
 
        fmr_cache = cYAML_get_object_item(lndparams, "fmr_cache");
                (fmr_flush_trigger) ? fmr_flush_trigger->cy_valueint : 0;
 
        fmr_cache = cYAML_get_object_item(lndparams, "fmr_cache");
-       lnd_cfg->lt_tun_u.lt_o2ib.lnd_fmr_cache =
+       lnd_cfg->lnd_fmr_cache =
                (fmr_cache) ? fmr_cache->cy_valueint : 0;
 }
 
                (fmr_cache) ? fmr_cache->cy_valueint : 0;
 }
 
+
 void
 void
-lustre_interface_parse(struct cYAML *lndparams, const char *dev_name,
-                      struct lnet_ioctl_config_lnd_tunables *lnd_cfg)
+lustre_yaml_extract_lnd_tunables(struct cYAML *tree,
+                                __u32 net_type,
+                                struct lnet_lnd_tunables *tun)
 {
 {
-       if (dev_name != NULL && strstr(dev_name, "ib"))
-               lustre_ko2iblnd_parse_net(lndparams, lnd_cfg);
+       if (net_type == O2IBLND)
+               yaml_extract_o2ib_tun(tree,
+                                     &tun->lnd_tun_u.lnd_o2ib);
+
 }
 }
+
index e3f0621..af53e16 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <limits.h>
 #include <libcfs/util/ioctl.h>
 #include <libcfs/util/parser.h>
 #include <lnet/lnetctl.h>
 #include <libcfs/util/ioctl.h>
 #include <libcfs/util/parser.h>
 #include <lnet/lnetctl.h>
+#include <lnet/nidstr.h>
 #include "cyaml/cyaml.h"
 #include "lnetconfig/liblnetconfig.h"
 
 #include "cyaml/cyaml.h"
 #include "lnetconfig/liblnetconfig.h"
 
 static int jt_config_lnet(int argc, char **argv);
 static int jt_unconfig_lnet(int argc, char **argv);
 static int jt_add_route(int argc, char **argv);
 static int jt_config_lnet(int argc, char **argv);
 static int jt_unconfig_lnet(int argc, char **argv);
 static int jt_add_route(int argc, char **argv);
-static int jt_add_net(int argc, char **argv);
+static int jt_add_ni(int argc, char **argv);
 static int jt_set_routing(int argc, char **argv);
 static int jt_del_route(int argc, char **argv);
 static int jt_set_routing(int argc, char **argv);
 static int jt_del_route(int argc, char **argv);
-static int jt_del_net(int argc, char **argv);
+static int jt_del_ni(int argc, char **argv);
 static int jt_show_route(int argc, char **argv);
 static int jt_show_net(int argc, char **argv);
 static int jt_show_routing(int argc, char **argv);
 static int jt_show_route(int argc, char **argv);
 static int jt_show_net(int argc, char **argv);
 static int jt_show_routing(int argc, char **argv);
@@ -81,7 +83,7 @@ command_t route_cmds[] = {
 };
 
 command_t net_cmds[] = {
 };
 
 command_t net_cmds[] = {
-       {"add", jt_add_net, 0, "add a network\n"
+       {"add", jt_add_ni, 0, "add a network\n"
         "\t--net: net name (e.g. tcp0)\n"
         "\t--if: physical interface (e.g. eth0)\n"
         "\t--ip2net: specify networks based on IP address patterns\n"
         "\t--net: net name (e.g. tcp0)\n"
         "\t--if: physical interface (e.g. eth0)\n"
         "\t--ip2net: specify networks based on IP address patterns\n"
@@ -90,8 +92,9 @@ command_t net_cmds[] = {
         "\t--peer-buffer-credits: the number of buffer credits per peer\n"
         "\t--credits: Network Interface credits\n"
         "\t--cpt: CPU Partitions configured net uses (e.g. [0,1]\n"},
         "\t--peer-buffer-credits: the number of buffer credits per peer\n"
         "\t--credits: Network Interface credits\n"
         "\t--cpt: CPU Partitions configured net uses (e.g. [0,1]\n"},
-       {"del", jt_del_net, 0, "delete a network\n"
-        "\t--net: net name (e.g. tcp0)\n"},
+       {"del", jt_del_ni, 0, "delete a network\n"
+        "\t--net: net name (e.g. tcp0)\n"
+        "\t--if: physical interface (e.g. eth0)\n"},
        {"show", jt_show_net, 0, "show networks\n"
         "\t--net: net name (e.g. tcp0) to filter on\n"
         "\t--verbose: display detailed output per network\n"},
        {"show", jt_show_net, 0, "show networks\n"
         "\t--net: net name (e.g. tcp0) to filter on\n"
         "\t--verbose: display detailed output per network\n"},
@@ -423,12 +426,19 @@ static int jt_add_route(int argc, char **argv)
        return rc;
 }
 
        return rc;
 }
 
-static int jt_add_net(int argc, char **argv)
+static int jt_add_ni(int argc, char **argv)
 {
 {
-       char *network = NULL, *intf = NULL, *ip2net = NULL, *cpt = NULL;
+       char *ip2net = NULL;
        long int pto = -1, pc = -1, pbc = -1, cre = -1;
        struct cYAML *err_rc = NULL;
        long int pto = -1, pc = -1, pbc = -1, cre = -1;
        struct cYAML *err_rc = NULL;
-       int rc, opt;
+       int rc, opt, num_global_cpts = 0;
+       struct lnet_dlc_network_descr nw_descr;
+       struct cfs_expr_list *global_cpts = NULL;
+       struct lnet_ioctl_config_lnd_tunables tunables;
+       bool found = false;
+
+       memset(&tunables, 0, sizeof(tunables));
+       lustre_lnet_init_nw_descr(&nw_descr);
 
        const char *const short_options = "n:i:p:t:c:b:r:s:h";
        const struct option long_options[] = {
 
        const char *const short_options = "n:i:p:t:c:b:r:s:h";
        const struct option long_options[] = {
@@ -448,10 +458,16 @@ static int jt_add_net(int argc, char **argv)
                                   long_options, NULL)) != -1) {
                switch (opt) {
                case 'n':
                                   long_options, NULL)) != -1) {
                switch (opt) {
                case 'n':
-                       network = optarg;
+                       nw_descr.nw_id = libcfs_str2net(optarg);
                        break;
                case 'i':
                        break;
                case 'i':
-                       intf = optarg;
+                       rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
+                       if (rc != 0) {
+                               cYAML_build_error(-1, -1, "ni", "add",
+                                               "bad interface list",
+                                               &err_rc);
+                               goto failed;
+                       }
                        break;
                case 'p':
                        ip2net = optarg;
                        break;
                case 'p':
                        ip2net = optarg;
@@ -489,7 +505,10 @@ static int jt_add_net(int argc, char **argv)
                        }
                        break;
                case 's':
                        }
                        break;
                case 's':
-                       cpt = optarg;
+                       num_global_cpts =
+                               cfs_expr_list_parse(optarg,
+                                                strlen(optarg),
+                                                0, UINT_MAX, &global_cpts);
                        break;
                case 'h':
                        print_help(net_cmds, "net", "add");
                        break;
                case 'h':
                        print_help(net_cmds, "net", "add");
@@ -499,9 +518,23 @@ static int jt_add_net(int argc, char **argv)
                }
        }
 
                }
        }
 
-       rc = lustre_lnet_config_net(network, intf, ip2net, pto, pc, pbc,
-                                   cre, cpt, -1, NULL, &err_rc);
+       if (pto > 0 || pc > 0 || pbc > 0 || cre > 0) {
+               tunables.lt_cmn.lct_peer_timeout = pto;
+               tunables.lt_cmn.lct_peer_tx_credits = pc;
+               tunables.lt_cmn.lct_peer_rtr_credits = pbc;
+               tunables.lt_cmn.lct_max_tx_credits = cre;
+               found = true;
+       }
+
+       rc = lustre_lnet_config_ni(&nw_descr,
+                                  (num_global_cpts > 0) ? global_cpts: NULL,
+                                  ip2net, (found) ? &tunables : NULL,
+                                  -1, &err_rc);
+
+       if (global_cpts != NULL)
+               cfs_expr_list_free(global_cpts);
 
 
+failed:
        if (rc != LUSTRE_CFG_RC_NO_ERR)
                cYAML_print_tree2file(stderr, err_rc);
 
        if (rc != LUSTRE_CFG_RC_NO_ERR)
                cYAML_print_tree2file(stderr, err_rc);
 
@@ -551,15 +584,18 @@ static int jt_del_route(int argc, char **argv)
        return rc;
 }
 
        return rc;
 }
 
-static int jt_del_net(int argc, char **argv)
+static int jt_del_ni(int argc, char **argv)
 {
 {
-       char *network = NULL;
        struct cYAML *err_rc = NULL;
        int rc, opt;
        struct cYAML *err_rc = NULL;
        int rc, opt;
+       struct lnet_dlc_network_descr nw_descr;
+
+       lustre_lnet_init_nw_descr(&nw_descr);
 
 
-       const char *const short_options = "n:h";
+       const char *const short_options = "n:i:h";
        const struct option long_options[] = {
                { "net", 1, NULL, 'n' },
        const struct option long_options[] = {
                { "net", 1, NULL, 'n' },
+               { "if", 1, NULL, 'i' },
                { "help", 0, NULL, 'h' },
                { NULL, 0, NULL, 0 },
        };
                { "help", 0, NULL, 'h' },
                { NULL, 0, NULL, 0 },
        };
@@ -568,7 +604,16 @@ static int jt_del_net(int argc, char **argv)
                                   long_options, NULL)) != -1) {
                switch (opt) {
                case 'n':
                                   long_options, NULL)) != -1) {
                switch (opt) {
                case 'n':
-                       network = optarg;
+                       nw_descr.nw_id = libcfs_str2net(optarg);
+                       break;
+               case 'i':
+                       rc = lustre_lnet_parse_interfaces(optarg, &nw_descr);
+                       if (rc != 0) {
+                               cYAML_build_error(-1, -1, "ni", "add",
+                                               "bad interface list",
+                                               &err_rc);
+                               goto out;
+                       }
                        break;
                case 'h':
                        print_help(net_cmds, "net", "del");
                        break;
                case 'h':
                        print_help(net_cmds, "net", "del");
@@ -578,8 +623,9 @@ static int jt_del_net(int argc, char **argv)
                }
        }
 
                }
        }
 
-       rc = lustre_lnet_del_net(network, -1, &err_rc);
+       rc = lustre_lnet_del_ni(&nw_descr, -1, &err_rc);
 
 
+out:
        if (rc != LUSTRE_CFG_RC_NO_ERR)
                cYAML_print_tree2file(stderr, err_rc);
 
        if (rc != LUSTRE_CFG_RC_NO_ERR)
                cYAML_print_tree2file(stderr, err_rc);