Commit 6addf306 authored by Vikram Narayanan's avatar Vikram Narayanan
Browse files

lcd/test_mod: Add a new module for nullnet driver


Signed-off-by: Vikram Narayanan's avatarVikram Narayanan <vikram186@gmail.com>
parent f0a8ac84
......@@ -25,3 +25,4 @@ obj-m += bug/
obj-m += async_rpc/
obj-m += llvm_example/
obj-m += ioremap/
obj-m += nullnet/
......@@ -49,3 +49,7 @@ llvm_example/lcd isolated
ioremap/boot nonisolated
ioremap/lcd isolated
nullnet/boot nonisolated
nullnet/dummy_lcd isolated
nullnet/net_klcd nonisolated
obj-$(LCD_CONFIG_BUILD_NULLNET_BOOT) += boot/
obj-$(LCD_CONFIG_BUILD_NULLNET_DUMMY_LCD) += dummy_lcd/
obj-$(LCD_CONFIG_BUILD_NULLNET_NET_KLCD) += net_klcd/
obj-m += lcd_test_mod_nullnet_boot.o
lcd_test_mod_nullnet_boot-y += main.o
ccflags-y += $(NONISOLATED_CFLAGS)
/*
* boot.c - non-isolated kernel module, does setup
* when fake minix and vfs are to be launched
* in isolated containers
*/
#include <lcd_config/pre_hook.h>
#include <liblcd/liblcd.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <lcd_config/post_hook.h>
static int boot_main(void)
{
int ret;
cptr_t net_chnl;
cptr_t net_chnl_domain_cptr, dummy_chnl_domain_cptr;
cptr_t net_lcd, dummy_lcd;
struct lcd_create_ctx *dummy_ctx;
/*
* Enter lcd mode
*/
ret = lcd_enter();
if (ret) {
LIBLCD_ERR("lcd enter failed");
goto fail1;
}
/* ---------- Create vfs channel ---------- */
ret = lcd_create_sync_endpoint(&net_chnl);
if (ret) {
LIBLCD_ERR("lcd create sync endpoint");
goto fail2;
}
/* ---------- Create LCDs ---------- */
ret = lcd_create_module_klcd(LCD_DIR("nullnet/net_klcd"),
"lcd_test_mod_nullnet_net_klcd",
&net_lcd);
if (ret) {
LIBLCD_ERR("failed to create net klcd");
goto fail3;
}
ret = lcd_create_module_lcd(LCD_DIR("nullnet/dummy_lcd"),
"lcd_test_mod_nullnet_dummy_lcd",
&dummy_lcd,
&dummy_ctx);
if (ret) {
LIBLCD_ERR("failed to create dummy lcd");
goto fail4;
}
/* ---------- Grant caps ---------- */
/*
ret = cptr_alloc(lcd_to_boot_cptr_cache(net_ctx),
&net_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("alloc cptr");
goto fail5;
}
ret = lcd_cap_grant(net_lcd, net_chnl, net_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("grant");
goto fail6;
} */
ret = cptr_alloc(lcd_to_boot_cptr_cache(dummy_ctx),
&dummy_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("alloc cptr");
goto fail7;
}
ret = lcd_cap_grant(dummy_lcd, net_chnl, dummy_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("grant");
goto fail8;
}
/* ---------- Set up boot info ---------- */
// lcd_to_boot_info(net_ctx)->cptrs[0] = net_chnl_domain_cptr;
net_chnl_domain_cptr = __cptr(3);
ret = lcd_cap_grant(net_lcd, net_chnl, net_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("grant");
goto fail6;
}
lcd_to_boot_info(dummy_ctx)->cptrs[0] = dummy_chnl_domain_cptr;
/* ---------- RUN! ---------- */
LIBLCD_MSG("starting network...");
ret = lcd_run(net_lcd);
if (ret) {
LIBLCD_ERR("failed to start vfs lcd");
goto fail9;
}
/* Wait a few moments so vfs lcd has a chance to enter its
* dispatch loop. This is obviously a hack. You could use some
* kind of protocol to wait for the vfs to signal it is ready. */
//msleep(2000);
LIBLCD_MSG("starting dummy ethernet...");
ret = lcd_run(dummy_lcd);
if (ret) {
LIBLCD_ERR("failed to start dummy lcd");
goto fail10;
}
/*
* Wait for 4 seconds
*/
msleep(4000);
/*
* Tear everything down
*/
ret = 0;
goto out;
/* The destroy's will free up everything ... */
out:
fail10:
fail9:
fail8:
fail7:
fail6:
lcd_cap_delete(dummy_lcd);
lcd_destroy_create_ctx(dummy_ctx);
fail4:
lcd_cap_delete(net_lcd);
fail3:
fail2:
lcd_exit(0); /* will free endpoints */
fail1:
return ret;
}
static int boot_init(void)
{
int ret;
LCD_MAIN({
ret = boot_main();
});
return ret;
}
static void boot_exit(void)
{
/* nothing to do */
}
module_init(boot_init);
module_exit(boot_exit);
/*
* cap.c
*
* cspace code for pmfs/vfs
*/
#include <lcd_config/pre_hook.h>
#include <libcap.h>
#include <liblcd/liblcd.h>
#include <linux/slab.h>
#include "glue_helper.h"
#include <lcd_config/post_hook.h>
/* ------------------------------------------------------------ */
static struct cap_type_system *glue_libcap_type_system;
struct type_ops_id {
struct cap_type_ops ops;
cap_type_t libcap_type;
};
enum glue_type {
GLUE_TYPE_NET_DEVICE,
GLUE_TYPE_NET_DEVICE_OPS,
GLUE_TYPE_NLATTR,
GLUE_TYPE_RTNL_LINK_OPS,
GLUE_TYPE_RTNL_LINK_STATS64,
GLUE_TYPE_SK_BUFF,
GLUE_NR_TYPES,
};
static int dummy_func(struct cspace *cspace, struct cnode *cnode,
void *object)
{
return 0;
}
static struct type_ops_id glue_libcap_type_ops[GLUE_NR_TYPES] = {
{
{
.name = "struct net_device",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct net_device_ops",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct nlattr",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct rtnl_link_ops",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct rtnl_link_stats64",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct sk_buff",
.delete = dummy_func,
.revoke = dummy_func,
}
},
};
int glue_cap_init(void)
{
int ret;
int i;
cap_type_t libcap_type;
/*
* Alloc and init microkernel type system
*/
ret = cap_type_system_alloc(&glue_libcap_type_system);
if (ret) {
LIBLCD_ERR("alloc glue type system failed");
goto fail1;
}
ret = cap_type_system_init(glue_libcap_type_system);
if (ret) {
LIBLCD_ERR("init glue type system failed");
goto fail2;
}
/*
* Add types
*/
for (i = 0; i < GLUE_NR_TYPES; i++) {
libcap_type = cap_register_private_type(
glue_libcap_type_system,
0,
&glue_libcap_type_ops[i].ops);
if (libcap_type == CAP_TYPE_ERR) {
LIBLCD_ERR("failed to register glue cap type %s",
glue_libcap_type_ops[i].ops.name);
ret = -EIO;
goto fail3;
}
glue_libcap_type_ops[i].libcap_type = libcap_type;
}
return 0;
fail3:
cap_type_system_destroy(glue_libcap_type_system);
fail2:
cap_type_system_free(glue_libcap_type_system);
glue_libcap_type_system = NULL;
fail1:
return ret;
}
int glue_cap_create(struct glue_cspace **cspace_out)
{
return glue_cspace_alloc_init(glue_libcap_type_system, cspace_out);
}
void glue_cap_destroy(struct glue_cspace *cspace)
{
glue_cspace_destroy_free(cspace);
}
void glue_cap_exit(void)
{
/*
* Destroy and free type system if necessary
*/
if (glue_libcap_type_system) {
cap_type_system_destroy(glue_libcap_type_system);
cap_type_system_free(glue_libcap_type_system);
glue_libcap_type_system = NULL;
}
}
int glue_cap_insert_net_device_type(
struct glue_cspace *cspace,
struct net_device_container *net_device_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, net_device_container,
glue_libcap_type_ops[GLUE_TYPE_NET_DEVICE].libcap_type,
c_out);
}
int glue_cap_insert_net_device_ops_type(
struct glue_cspace *cspace,
struct net_device_ops_container *net_device_ops_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, net_device_ops_container,
glue_libcap_type_ops[GLUE_TYPE_NET_DEVICE_OPS].libcap_type,
c_out);
}
int glue_cap_insert_nlattr_type(
struct glue_cspace *cspace,
struct nlattr_container *nlattr_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, nlattr_container,
glue_libcap_type_ops[GLUE_TYPE_NLATTR].libcap_type,
c_out);
}
int glue_cap_insert_rtnl_link_ops_type(
struct glue_cspace *cspace,
struct rtnl_link_ops_container *rtnl_link_ops_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, rtnl_link_ops_container,
glue_libcap_type_ops[GLUE_TYPE_RTNL_LINK_OPS].libcap_type,
c_out);
}
int glue_cap_insert_rtnl_link_stats64_type(
struct glue_cspace *cspace,
struct rtnl_link_stats64_container *rtnl_link_stats64_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, rtnl_link_stats64_container,
glue_libcap_type_ops[GLUE_TYPE_RTNL_LINK_STATS64].libcap_type,
c_out);
}
int glue_cap_insert_sk_buff_type(
struct glue_cspace *cspace,
struct sk_buff_container *sk_buff_container,
cptr_t *c_out)
{
return glue_cspace_insert(cspace, sk_buff_container,
glue_libcap_type_ops[GLUE_TYPE_SK_BUFF].libcap_type,
c_out);
}
int glue_cap_lookup_net_device_type(
struct glue_cspace *cspace,
cptr_t c,
struct net_device_container **net_device_container)
{
return glue_cspace_lookup(cspace, c,
glue_libcap_type_ops[GLUE_TYPE_NET_DEVICE].libcap_type,
(void **)net_device_container);
}
int glue_cap_lookup_net_device_ops_type(
struct glue_cspace *cspace,
cptr_t c,
struct net_device_ops_container **net_device_ops_container)
{
return glue_cspace_lookup(cspace, c,
glue_libcap_type_ops[GLUE_TYPE_NET_DEVICE_OPS].libcap_type,
(void **)net_device_ops_container);
}
int glue_cap_lookup_nlattr_type(
struct glue_cspace *cspace,
cptr_t c,
struct nlattr_container **nlattr_container)
{
return glue_cspace_lookup(
cspace, c,
glue_libcap_type_ops[GLUE_TYPE_NLATTR].libcap_type,
(void **)nlattr_container);
}
int glue_cap_lookup_rtnl_link_ops_type(
struct glue_cspace *cspace,
cptr_t c,
struct rtnl_link_ops_container **rtnl_link_ops_container)
{
return glue_cspace_lookup(
cspace, c,
glue_libcap_type_ops[GLUE_TYPE_RTNL_LINK_OPS].libcap_type,
(void **)rtnl_link_ops_container);
}
int glue_cap_lookup_rtnl_link_stats64_type(
struct glue_cspace *cspace,
cptr_t c,
struct rtnl_link_stats64_container **rtnl_link_stats64_container)
{
return glue_cspace_lookup(
cspace, c,
glue_libcap_type_ops[GLUE_TYPE_RTNL_LINK_STATS64].libcap_type,
(void **)rtnl_link_stats64_container);
}
int glue_cap_lookup_sk_buff_type(
struct glue_cspace *cspace,
cptr_t c,
struct sk_buff_container **sk_buff_container)
{
return glue_cspace_lookup(
cspace, c,
glue_libcap_type_ops[GLUE_TYPE_SK_BUFF].libcap_type,
(void **)sk_buff_container);
}
void glue_cap_remove(
struct glue_cspace *cspace,
cptr_t c)
{
glue_cspace_remove(cspace, c);
}
obj-m += lcd_test_mod_nullnet_dummy_lcd.o
lcd_test_mod_nullnet_dummy_lcd-y += main.o
# Original code
lcd_test_mod_nullnet_dummy_lcd-y += dummy.o
lcd_test_mod_nullnet_dummy_lcd-y += $(LIBLCD)
# glue code
lcd_test_mod_nullnet_dummy_lcd-y += $(addprefix glue/, nullnet_caller.o \
dispatch.o )
lcd_test_mod_nullnet_dummy_lcd-y += $(addprefix ../, cap.o)
ccflags-y += $(ISOLATED_CFLAGS)
/* dummy.c: a dummy net driver
The purpose of this driver is to provide a device to point a
route through, but not to actually transmit packets.
Why? If you have a machine whose only connection is an occasional
PPP/SLIP/PLIP link, you can only connect to your own hostname
when the link is up. Otherwise you have to use localhost.
This isn't very consistent.
One solution is to set up a dummy link using PPP/SLIP/PLIP,
but this seems (to me) too much overhead for too little gain.
This driver provides a small alternative. Thus you can do
[when not running slip]
ifconfig dummy slip.addr.ess.here up
[to go to slip]
ifconfig dummy down
dip whatever
This was written by looking at Donald Becker's skeleton driver
and the loopback driver. I then threw away anything that didn't
apply! Thanks to Alan Cox for the key clue on what to do with
misguided packets.
Nick Holloway, 27th May 1994
[I tweaked this explanation a little but that's all]
Alan Cox, 30th May 1994
*/
#ifdef LCD_ISOLATE
#include <lcd_config/pre_hook.h>
#endif
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/rtnetlink.h>
#include <net/rtnetlink.h>
#include <linux/u64_stats_sync.h>
#include "../glue_helper.h"
#ifdef LCD_ISOLATE
#include <lcd_config/post_hook.h>
#endif
#define DRV_NAME "dummy"
#define DRV_VERSION "1.0"
static int numdummies = 1;
/* fake multicast ability */
static void set_multicast_list(struct net_device *dev)
{
}
struct pcpu_dstats {
u64 tx_packets;
u64 tx_bytes;
struct u64_stats_sync syncp;
};
static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
struct rtnl_link_stats64 *stats)
{
//int i;
/* for_each_possible_cpu(i) {
const struct pcpu_dstats *dstats;
u64 tbytes, tpackets;
unsigned int start;
dstats = per_cpu_ptr(dev->dstats, i);
do {
start = u64_stats_fetch_begin_irq(&dstats->syncp);
tbytes = dstats->tx_bytes;
tpackets = dstats->tx_packets;
} while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
stats->tx_bytes += tbytes;
stats->tx_packets += tpackets;
}*/
stats->tx_bytes = 100;
stats->tx_packets = 0x5A5A;
return stats;
}
static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
u64_stats_update_begin(&dstats->syncp);
dstats->tx_packets++;
dstats->tx_bytes += skb->len;
u64_stats_update_end(&dstats->syncp);
*/
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int dummy_dev_init(struct net_device *dev)
{
/* dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
if (!dev->dstats)
return -ENOMEM;
*/
return 0;
}
static void dummy_dev_uninit(struct net_device *dev)
{
// free_percpu(dev->dstats);
}
static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
{
if (new_carrier)
netif_carrier_on(dev);