#include <portals/lib-p30.h>
#include <portals/p30.h>
-#include <portals/nal.h>
#include <linux/kp30.h>
#include <linux/kpr.h>
#include <linux/portals_compat25.h>
extern void (kping_client)(struct portal_ioctl_data *);
+struct nal_cmd_handler {
+ nal_cmd_handler_t nch_handler;
+ void * nch_private;
+};
+
+static struct nal_cmd_handler nal_cmd[NAL_MAX_NR + 1];
+static DECLARE_MUTEX(nal_cmd_sem);
+
+
+static int
+kportal_add_route(int gateway_nalid, ptl_nid_t gateway_nid,
+ ptl_nid_t lo_nid, ptl_nid_t hi_nid)
+{
+ int rc;
+ kpr_control_interface_t *ci;
+
+ ci = (kpr_control_interface_t *) PORTAL_SYMBOL_GET (kpr_control_interface);
+ if (ci == NULL)
+ return (-ENODEV);
+
+ rc = ci->kprci_add_route (gateway_nalid, gateway_nid, lo_nid, hi_nid);
+
+ PORTAL_SYMBOL_PUT(kpr_control_interface);
+ return (rc);
+}
+
+static int
+kportal_del_route(int gw_nalid, ptl_nid_t gw_nid,
+ ptl_nid_t lo, ptl_nid_t hi)
+{
+ int rc;
+ kpr_control_interface_t *ci;
+
+ ci = (kpr_control_interface_t *)PORTAL_SYMBOL_GET(kpr_control_interface);
+ if (ci == NULL)
+ return (-ENODEV);
+
+ rc = ci->kprci_del_route (gw_nalid, gw_nid, lo, hi);
+
+ PORTAL_SYMBOL_PUT(kpr_control_interface);
+ return (rc);
+}
+
+static int
+kportal_notify_router (int gw_nalid, ptl_nid_t gw_nid,
+ int alive, time_t when)
+{
+ int rc;
+ kpr_control_interface_t *ci;
+
+ /* No error if router not preset. Sysadmin is allowed to notify
+ * _everywhere_ when a NID boots or crashes, even if they know
+ * nothing of the peer. */
+ ci = (kpr_control_interface_t *)PORTAL_SYMBOL_GET(kpr_control_interface);
+ if (ci == NULL)
+ return (0);
+
+ rc = ci->kprci_notify (gw_nalid, gw_nid, alive, when);
+
+ PORTAL_SYMBOL_PUT(kpr_control_interface);
+ return (rc);
+}
+
+static int
+kportal_get_route(int index, __u32 *gateway_nalidp, ptl_nid_t *gateway_nidp,
+ ptl_nid_t *lo_nidp, ptl_nid_t *hi_nidp, int *alivep)
+{
+ int gateway_nalid;
+ ptl_nid_t gateway_nid;
+ ptl_nid_t lo_nid;
+ ptl_nid_t hi_nid;
+ int alive;
+ int rc;
+ kpr_control_interface_t *ci;
+
+ ci = (kpr_control_interface_t *) PORTAL_SYMBOL_GET(kpr_control_interface);
+ if (ci == NULL)
+ return (-ENODEV);
+
+ rc = ci->kprci_get_route(index, &gateway_nalid, &gateway_nid,
+ &lo_nid, &hi_nid, &alive);
+
+ if (rc == 0) {
+ CDEBUG(D_IOCTL, "got route [%d] %d "LPX64":"LPX64" - "LPX64", %s\n",
+ index, gateway_nalid, gateway_nid, lo_nid, hi_nid,
+ alive ? "up" : "down");
+
+ *gateway_nalidp = (__u32)gateway_nalid;
+ *gateway_nidp = gateway_nid;
+ *lo_nidp = lo_nid;
+ *hi_nidp = hi_nid;
+ *alivep = alive;
+ }
+
+ PORTAL_SYMBOL_PUT (kpr_control_interface);
+ return (rc);
+}
+
+static int
+kportal_router_cmd(struct portals_cfg *pcfg, void * private)
+{
+ int err = -EINVAL;
+ ENTRY;
+
+ switch(pcfg->pcfg_command) {
+ default:
+ CDEBUG(D_IOCTL, "Inappropriate cmd: %d\n", pcfg->pcfg_command);
+ break;
+
+ case NAL_CMD_ADD_ROUTE:
+ CDEBUG(D_IOCTL, "Adding route: [%d] "LPU64" : "LPU64" - "LPU64"\n",
+ pcfg->pcfg_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_nid2, pcfg->pcfg_nid3);
+ err = kportal_add_route(pcfg->pcfg_gw_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_nid2, pcfg->pcfg_nid3);
+ break;
+
+ case NAL_CMD_DEL_ROUTE:
+ CDEBUG (D_IOCTL, "Removing routes via [%d] "LPU64" : "LPU64" - "LPU64"\n",
+ pcfg->pcfg_gw_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_nid2, pcfg->pcfg_nid3);
+ err = kportal_del_route (pcfg->pcfg_gw_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_nid2, pcfg->pcfg_nid3);
+ break;
+
+ case NAL_CMD_NOTIFY_ROUTER: {
+ CDEBUG (D_IOCTL, "Notifying peer [%d] "LPU64" %s @ %ld\n",
+ pcfg->pcfg_gw_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_flags ? "Enabling" : "Disabling",
+ (time_t)pcfg->pcfg_nid3);
+
+ err = kportal_notify_router (pcfg->pcfg_gw_nal, pcfg->pcfg_nid,
+ pcfg->pcfg_flags,
+ (time_t)pcfg->pcfg_nid3);
+ break;
+ }
+
+ case NAL_CMD_GET_ROUTE:
+ CDEBUG (D_IOCTL, "Getting route [%d]\n", pcfg->pcfg_count);
+ err = kportal_get_route(pcfg->pcfg_count, &pcfg->pcfg_gw_nal,
+ &pcfg->pcfg_nid,
+ &pcfg->pcfg_nid2, &pcfg->pcfg_nid3,
+ &pcfg->pcfg_flags);
+ break;
+ }
+ RETURN(err);
+}
+
+int
+kportal_nal_cmd(struct portals_cfg *pcfg)
+{
+ __u32 nal = pcfg->pcfg_nal;
+ int rc = -EINVAL;
+
+ ENTRY;
+
+ down(&nal_cmd_sem);
+ if (nal > 0 && nal <= NAL_MAX_NR && nal_cmd[nal].nch_handler) {
+ CDEBUG(D_IOCTL, "calling handler nal: %d, cmd: %d\n", nal,
+ pcfg->pcfg_command);
+ rc = nal_cmd[nal].nch_handler(pcfg, nal_cmd[nal].nch_private);
+ }
+ up(&nal_cmd_sem);
+ RETURN(rc);
+}
+
+ptl_handle_ni_t *
+kportal_get_ni (int nal)
+{
+
+ switch (nal)
+ {
+ case QSWNAL:
+ return (PORTAL_SYMBOL_GET(kqswnal_ni));
+ case SOCKNAL:
+ return (PORTAL_SYMBOL_GET(ksocknal_ni));
+ case GMNAL:
+ return (PORTAL_SYMBOL_GET(kgmnal_ni));
+ case IBNAL:
+ return (PORTAL_SYMBOL_GET(kibnal_ni));
+ case TCPNAL:
+ /* userspace NAL */
+ return (NULL);
+ case SCIMACNAL:
+ return (PORTAL_SYMBOL_GET(kscimacnal_ni));
+ default:
+ /* A warning to a naive caller */
+ CERROR ("unknown nal: %d\n", nal);
+ return (NULL);
+ }
+}
+
+void
+kportal_put_ni (int nal)
+{
+
+ switch (nal)
+ {
+ case QSWNAL:
+ PORTAL_SYMBOL_PUT(kqswnal_ni);
+ break;
+ case SOCKNAL:
+ PORTAL_SYMBOL_PUT(ksocknal_ni);
+ break;
+ case GMNAL:
+ PORTAL_SYMBOL_PUT(kgmnal_ni);
+ break;
+ case IBNAL:
+ PORTAL_SYMBOL_PUT(kibnal_ni);
+ break;
+ case TCPNAL:
+ /* A lesson to a malicious caller */
+ LBUG ();
+ case SCIMACNAL:
+ PORTAL_SYMBOL_PUT(kscimacnal_ni);
+ break;
+ default:
+ CERROR ("unknown nal: %d\n", nal);
+ }
+}
+
+int
+kportal_nal_register(int nal, nal_cmd_handler_t handler, void * private)
+{
+ int rc = 0;
+
+ CDEBUG(D_IOCTL, "Register NAL %d, handler: %p\n", nal, handler);
+
+ if (nal > 0 && nal <= NAL_MAX_NR) {
+ down(&nal_cmd_sem);
+ if (nal_cmd[nal].nch_handler != NULL)
+ rc = -EBUSY;
+ else {
+ nal_cmd[nal].nch_handler = handler;
+ nal_cmd[nal].nch_private = private;
+ }
+ up(&nal_cmd_sem);
+ }
+ return rc;
+}
+
+int
+kportal_nal_unregister(int nal)
+{
+ int rc = 0;
+
+ CDEBUG(D_IOCTL, "Unregister NAL %d\n", nal);
+
+ if (nal > 0 && nal <= NAL_MAX_NR) {
+ down(&nal_cmd_sem);
+ nal_cmd[nal].nch_handler = NULL;
+ nal_cmd[nal].nch_private = NULL;
+ up(&nal_cmd_sem);
+ }
+ return rc;
+}
+
static int kportal_ioctl(struct portal_ioctl_data *data,
unsigned int cmd, unsigned long arg)
{
- int err;
+ int err = 0;
char str[PTL_NALFMT_SIZE];
ENTRY;
}
case IOC_PORTAL_GET_NID: {
- ptl_handle_ni_t nih;
- ptl_process_id_t pid;
+ const ptl_handle_ni_t *nip;
+ ptl_process_id_t pid;
CDEBUG (D_IOCTL, "Getting nid for nal [%d]\n", data->ioc_nal);
- err = PtlNIInit(data->ioc_nal, 0, NULL, NULL, &nih);
- if (!(err == PTL_OK || err == PTL_IFACE_DUP))
+ nip = kportal_get_ni (data->ioc_nal);
+ if (nip == NULL)
RETURN (-EINVAL);
- err = PtlGetId (nih, &pid);
+ err = PtlGetId (*nip, &pid);
LASSERT (err == PTL_OK);
-
- PtlNIFini(nih);
+ kportal_put_ni (data->ioc_nal);
data->ioc_nid = pid.nid;
if (copy_to_user ((char *)arg, data, sizeof (*data)))
- RETURN (-EFAULT);
- RETURN(0);
+ err = -EFAULT;
+ break;
}
+ case IOC_PORTAL_NAL_CMD: {
+ struct portals_cfg pcfg;
+
+ LASSERT (data->ioc_plen1 == sizeof(pcfg));
+ err = copy_from_user(&pcfg, (void *)data->ioc_pbuf1,
+ sizeof(pcfg));
+ if ( err ) {
+ EXIT;
+ return err;
+ }
+
+ CDEBUG (D_IOCTL, "nal command nal %d cmd %d\n", pcfg.pcfg_nal,
+ pcfg.pcfg_command);
+ err = kportal_nal_cmd(&pcfg);
+ if (err == 0) {
+ if (copy_to_user((char *)data->ioc_pbuf1, &pcfg,
+ sizeof (pcfg)))
+ err = -EFAULT;
+ if (copy_to_user((char *)arg, data, sizeof (*data)))
+ err = -EFAULT;
+ }
+ break;
+ }
case IOC_PORTAL_FAIL_NID: {
- ptl_handle_ni_t nih;
+ const ptl_handle_ni_t *nip;
CDEBUG (D_IOCTL, "fail nid: [%d] "LPU64" count %d\n",
data->ioc_nal, data->ioc_nid, data->ioc_count);
- err = PtlNIInit(data->ioc_nal, 0, NULL, NULL, &nih);
- if (!(err == PTL_OK || err == PTL_IFACE_DUP))
+ nip = kportal_get_ni (data->ioc_nal);
+ if (nip == NULL)
return (-EINVAL);
- if (err == PTL_OK) {
- /* There's no point in failing an interface that
- * came into existance just for this */
- err = -EINVAL;
- } else {
- err = PtlFailNid (nih, data->ioc_nid, data->ioc_count);
- if (err != PTL_OK)
- err = -EINVAL;
- }
-
- PtlNIFini(nih);
- RETURN (err);
+ err = PtlFailNid (*nip, data->ioc_nid, data->ioc_count);
+ kportal_put_ni (data->ioc_nal);
+ break;
}
default:
- RETURN(-EINVAL);
+ err = -EINVAL;
+ break;
}
- /* Not Reached */
+
+ RETURN(err);
}
DECLARE_IOCTL_HANDLER(kportal_ioctl_handler, kportal_ioctl);
RETURN(rc);
}
- rc = libcfs_register_ioctl(&kportal_ioctl_handler);
- LASSERT (rc == 0);
+ rc = kportal_nal_register(ROUTER, kportal_router_cmd, NULL);
+ if (rc) {
+ PtlFini();
+ CERROR("kportal_nal_registre: ROUTER error %d\n", rc);
+ }
+
+ if (rc == 0)
+ libcfs_register_ioctl(&kportal_ioctl_handler);
RETURN(rc);
}
static void exit_kportals_module(void)
{
- int rc;
-
- rc = libcfs_deregister_ioctl(&kportal_ioctl_handler);
- LASSERT (rc == 0);
-
+ libcfs_deregister_ioctl(&kportal_ioctl_handler);
+ kportal_nal_unregister(ROUTER);
PtlFini();
}
-EXPORT_SYMBOL(ptl_register_nal);
-EXPORT_SYMBOL(ptl_unregister_nal);
+EXPORT_SYMBOL(kportal_nal_register);
+EXPORT_SYMBOL(kportal_nal_unregister);
+EXPORT_SYMBOL(kportal_get_ni);
+EXPORT_SYMBOL(kportal_put_ni);
+EXPORT_SYMBOL(kportal_nal_cmd);
EXPORT_SYMBOL(ptl_err_str);
EXPORT_SYMBOL(lib_dispatch);
EXPORT_SYMBOL(PtlMDUnlink);
EXPORT_SYMBOL(PtlNIInit);
EXPORT_SYMBOL(PtlNIFini);
+EXPORT_SYMBOL(PtlNIDebug);
EXPORT_SYMBOL(PtlInit);
EXPORT_SYMBOL(PtlFini);
EXPORT_SYMBOL(PtlSnprintHandle);